|
@@ -0,0 +1,88 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
|
|
|
+ *
|
|
|
+ * Permission to use, copy, modify, and/or distribute this software for any
|
|
|
+ * purpose with or without fee is hereby granted, provided that the above
|
|
|
+ * copyright notice and this permission notice appear in all copies.
|
|
|
+ *
|
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
+ */
|
|
|
+
|
|
|
+#include "ath9k.h"
|
|
|
+
|
|
|
+struct ath9k_vif_iter_data {
|
|
|
+ int count;
|
|
|
+ u8 *addr;
|
|
|
+};
|
|
|
+
|
|
|
+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;
|
|
|
+
|
|
|
+ memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
|
|
|
+ iter_data->addr = nbuf;
|
|
|
+ iter_data->count++;
|
|
|
+}
|
|
|
+
|
|
|
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
|
|
|
+{
|
|
|
+ struct ath_softc *sc = hw->priv;
|
|
|
+ struct ath9k_vif_iter_data iter_data;
|
|
|
+ int i, j;
|
|
|
+ u8 mask[ETH_ALEN];
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+ iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
|
|
|
+ if (iter_data.addr) {
|
|
|
+ memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN);
|
|
|
+ iter_data.count = 1;
|
|
|
+ } else
|
|
|
+ iter_data.count = 0;
|
|
|
+
|
|
|
+ /* Get list of all active MAC addresses */
|
|
|
+ ieee80211_iterate_active_interfaces_atomic(hw, ath9k_vif_iter,
|
|
|
+ &iter_data);
|
|
|
+
|
|
|
+ /* 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 */
|
|
|
+ sc->bssidmask[0] = ~mask[0];
|
|
|
+ sc->bssidmask[1] = ~mask[1];
|
|
|
+ sc->bssidmask[2] = ~mask[2];
|
|
|
+ sc->bssidmask[3] = ~mask[3];
|
|
|
+ sc->bssidmask[4] = ~mask[4];
|
|
|
+ sc->bssidmask[5] = ~mask[5];
|
|
|
+
|
|
|
+ ath9k_hw_setbssidmask(sc);
|
|
|
+}
|