Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd
[cascardo/linux.git] / drivers / net / wireless / ath / ath9k / virtual.c
index fd20241..ec7cf5e 100644 (file)
 #include "ath9k.h"
 
 struct ath9k_vif_iter_data {
-       int count;
-       u8 *addr;
+       const u8 *hw_macaddr;
+       u8 mask[ETH_ALEN];
 };
 
 static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 {
        struct ath9k_vif_iter_data *iter_data = data;
-       u8 *nbuf;
-
-       nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
-                       GFP_ATOMIC);
-       if (nbuf == NULL)
-               return;
+       int i;
 
-       memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
-       iter_data->addr = nbuf;
-       iter_data->count++;
+       for (i = 0; i < ETH_ALEN; i++)
+               iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
 }
 
-void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath9k_vif_iter_data iter_data;
-       int i, j;
-       u8 mask[ETH_ALEN];
+       int i;
 
        /*
-        * Add primary MAC address even if it is not in active use since it
-        * will be configured to the hardware as the starting point and the
-        * BSSID mask will need to be changed if another address is active.
+        * Use the hardware MAC address as reference, the hardware uses it
+        * together with the BSSID mask when matching addresses.
         */
-       iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
-       if (iter_data.addr) {
-               memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
-               iter_data.count = 1;
-       } else
-               iter_data.count = 0;
+       iter_data.hw_macaddr = common->macaddr;
+       memset(&iter_data.mask, 0xff, ETH_ALEN);
+
+       if (vif)
+               ath9k_vif_iter(&iter_data, vif->addr, vif);
 
        /* Get list of all active MAC addresses */
        spin_lock_bh(&sc->wiphy_lock);
@@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
        }
        spin_unlock_bh(&sc->wiphy_lock);
 
-       /* Generate an address mask to cover all active addresses */
-       memset(mask, 0, ETH_ALEN);
-       for (i = 0; i < iter_data.count; i++) {
-               u8 *a1 = iter_data.addr + i * ETH_ALEN;
-               for (j = i + 1; j < iter_data.count; j++) {
-                       u8 *a2 = iter_data.addr + j * ETH_ALEN;
-                       mask[0] |= a1[0] ^ a2[0];
-                       mask[1] |= a1[1] ^ a2[1];
-                       mask[2] |= a1[2] ^ a2[2];
-                       mask[3] |= a1[3] ^ a2[3];
-                       mask[4] |= a1[4] ^ a2[4];
-                       mask[5] |= a1[5] ^ a2[5];
-               }
-       }
-
-       kfree(iter_data.addr);
-
-       /* Invert the mask and configure hardware */
-       common->bssidmask[0] = ~mask[0];
-       common->bssidmask[1] = ~mask[1];
-       common->bssidmask[2] = ~mask[2];
-       common->bssidmask[3] = ~mask[3];
-       common->bssidmask[4] = ~mask[4];
-       common->bssidmask[5] = ~mask[5];
-
+       memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
        ath_hw_setbssidmask(common);
 }