Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ca21f01 authored by Jouni Malinen's avatar Jouni Malinen Committed by John W. Linville
Browse files

ath9k: Set BSSID mask based on configured interfaces



Instead of using a hardcoded BSSID mask (mask for own addresses),
iterate through all active interfaces and determine the minimal mask
that covers all local addresses.

Signed-off-by: default avatarJouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2c3db3d5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ ath9k-y += hw.o \
		main.o \
		recv.o \
		xmit.o \
		virtual.o \
		rc.o

ath9k-$(CONFIG_PCI) += pci.o
+3 −11
Original line number Diff line number Diff line
@@ -387,17 +387,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
/* VIFs */
/********/

/*
 * Define the scheme that we select MAC address for multiple
 * BSS on the same radio. The very first VIF will just use the MAC
 * address from the EEPROM. For the next 3 VIFs, we set the
 * U/L bit (bit 1) in MAC address, and use the next two bits as the
 * index of the VIF.
 */

#define ATH_SET_VIF_BSSID_MASK(bssid_mask) \
	((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))

struct ath_vif {
	int av_bslot;
	enum nl80211_iftype av_opmode;
@@ -676,4 +665,7 @@ static inline void ath9k_ps_restore(struct ath_softc *sc)
					  sc->sc_ah->restore_mode);
}


void ath9k_set_bssid_mask(struct ieee80211_hw *hw);

#endif /* ATH9K_H */
+11 −4
Original line number Diff line number Diff line
@@ -1514,11 +1514,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
	ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
	sc->rx.defant = ath9k_hw_getdefantenna(ah);

	if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
	if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
		memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
		ATH_SET_VIF_BSSID_MASK(sc->bssidmask);
		ath9k_hw_setbssidmask(sc);
	}

	sc->beacon.slottime = ATH9K_SLOT_TIME_9;	/* default to short slot time */

@@ -2128,6 +2125,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,

	mutex_lock(&sc->mutex);

	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
	    sc->nvifs > 0) {
		ret = -ENOBUFS;
		goto out;
	}

	switch (conf->type) {
	case NL80211_IFTYPE_STATION:
		ic_opmode = NL80211_IFTYPE_STATION;
@@ -2160,6 +2163,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
	avp->av_bslot = -1;

	sc->nvifs++;

	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
		ath9k_set_bssid_mask(hw);

	if (sc->nvifs > 1)
		goto out; /* skip global settings for secondary vif */

+88 −0
Original line number Diff line number Diff line
/*
 * 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);
}