ath9k: fix multi-bss operation (fixes #7914)
[openwrt.git] / package / mac80211 / patches / 550-ath9k_bssid_mask_fix.patch
1 --- a/drivers/net/wireless/ath/ath9k/virtual.c
2 +++ b/drivers/net/wireless/ath/ath9k/virtual.c
3 @@ -19,45 +19,36 @@
4  #include "ath9k.h"
5  
6  struct ath9k_vif_iter_data {
7 -       int count;
8 -       u8 *addr;
9 +       const u8 *hw_macaddr;
10 +       u8 mask[ETH_ALEN];
11  };
12  
13  static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
14  {
15         struct ath9k_vif_iter_data *iter_data = data;
16 -       u8 *nbuf;
17 -
18 -       nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
19 -                       GFP_ATOMIC);
20 -       if (nbuf == NULL)
21 -               return;
22 +       int i;
23  
24 -       memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
25 -       iter_data->addr = nbuf;
26 -       iter_data->count++;
27 +       for (i = 0; i < ETH_ALEN; i++)
28 +               iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
29  }
30  
31 -void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
32 +void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
33  {
34         struct ath_wiphy *aphy = hw->priv;
35         struct ath_softc *sc = aphy->sc;
36         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
37         struct ath9k_vif_iter_data iter_data;
38 -       int i, j;
39 -       u8 mask[ETH_ALEN];
40 +       int i;
41  
42         /*
43 -        * Add primary MAC address even if it is not in active use since it
44 -        * will be configured to the hardware as the starting point and the
45 -        * BSSID mask will need to be changed if another address is active.
46 +        * Use the hardware MAC address as reference, the hardware uses it
47 +        * together with the BSSID mask when matching addresses.
48          */
49 -       iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
50 -       if (iter_data.addr) {
51 -               memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
52 -               iter_data.count = 1;
53 -       } else
54 -               iter_data.count = 0;
55 +       iter_data.hw_macaddr = common->macaddr;
56 +       memset(&iter_data.mask, 0xff, ETH_ALEN);
57 +
58 +       if (vif)
59 +               ath9k_vif_iter(&iter_data, vif->addr, vif);
60  
61         /* Get list of all active MAC addresses */
62         spin_lock_bh(&sc->wiphy_lock);
63 @@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee802
64         }
65         spin_unlock_bh(&sc->wiphy_lock);
66  
67 -       /* Generate an address mask to cover all active addresses */
68 -       memset(mask, 0, ETH_ALEN);
69 -       for (i = 0; i < iter_data.count; i++) {
70 -               u8 *a1 = iter_data.addr + i * ETH_ALEN;
71 -               for (j = i + 1; j < iter_data.count; j++) {
72 -                       u8 *a2 = iter_data.addr + j * ETH_ALEN;
73 -                       mask[0] |= a1[0] ^ a2[0];
74 -                       mask[1] |= a1[1] ^ a2[1];
75 -                       mask[2] |= a1[2] ^ a2[2];
76 -                       mask[3] |= a1[3] ^ a2[3];
77 -                       mask[4] |= a1[4] ^ a2[4];
78 -                       mask[5] |= a1[5] ^ a2[5];
79 -               }
80 -       }
81 -
82 -       kfree(iter_data.addr);
83 -
84 -       /* Invert the mask and configure hardware */
85 -       common->bssidmask[0] = ~mask[0];
86 -       common->bssidmask[1] = ~mask[1];
87 -       common->bssidmask[2] = ~mask[2];
88 -       common->bssidmask[3] = ~mask[3];
89 -       common->bssidmask[4] = ~mask[4];
90 -       common->bssidmask[5] = ~mask[5];
91 -
92 +       memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
93         ath_hw_setbssidmask(common);
94  }
95  
96 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
97 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
98 @@ -666,7 +666,7 @@ static inline void ath_ahb_exit(void) {}
99  void ath9k_ps_wakeup(struct ath_softc *sc);
100  void ath9k_ps_restore(struct ath_softc *sc);
101  
102 -void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
103 +void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
104  int ath9k_wiphy_add(struct ath_softc *sc);
105  int ath9k_wiphy_del(struct ath_wiphy *aphy);
106  void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
107 --- a/drivers/net/wireless/ath/ath9k/main.c
108 +++ b/drivers/net/wireless/ath/ath9k/main.c
109 @@ -1416,7 +1416,7 @@ static int ath9k_add_interface(struct ie
110         sc->nvifs++;
111  
112         if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
113 -               ath9k_set_bssid_mask(hw);
114 +               ath9k_set_bssid_mask(hw, vif);
115  
116         if (sc->nvifs > 1)
117                 goto out; /* skip global settings for secondary vif */