PERFORCE change 135695 for review
Sam Leffler
sam at FreeBSD.org
Tue Feb 19 02:06:44 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=135695
Change 135695 by sam at sam_ebb on 2008/02/19 02:06:37
o add multi-vap create
o add bssid clone/allocation
o correctly map net80211 opmode to hal mode
o correct per-vap mcast q reclaim
o add support for sta mode s/w bmiss when operating as an ap
o hookup hal calls to check for bssid mask and tsf adjust support
Affected files ...
.. //depot/projects/vap/sys/dev/ath/if_ath.c#24 edit
.. //depot/projects/vap/sys/dev/ath/if_athvar.h#13 edit
Differences ...
==== //depot/projects/vap/sys/dev/ath/if_ath.c#24 (text+ko) ====
@@ -579,6 +579,8 @@
*/
if (ath_hal_hasbursting(ah))
ic->ic_caps |= IEEE80211_C_BURST;
+ sc->sc_hasbmask = ath_hal_hasbssidmask(ah);
+ sc->sc_hastsfadd = ath_hal_hastsfadjust(ah);
if (ath_hal_hasfastframes(ah))
ic->ic_caps |= IEEE80211_C_FF;
if (ath_hal_getwirelessmodes(ah, ath_countrycode) & (HAL_MODE_108G|HAL_MODE_TURBO))
@@ -608,7 +610,7 @@
ic->ic_max_keyix = sc->sc_keymax;
/* call MI attach routine. */
ieee80211_ifattach(ic);
- sc->sc_opmode = ic->ic_opmode;
+ sc->sc_opmode = HAL_M_STA;
/* override default methods */
ic->ic_newassoc = ath_newassoc;
@@ -685,21 +687,117 @@
return 0;
}
+/*
+ * MAC address handling for multiple BSS on the same radio.
+ * The first vap uses the MAC address from the EEPROM. For
+ * subsequent vap's we set the U/L bit (bit 1) in the MAC
+ * address and use the next six bits as an index.
+ */
+static void
+assign_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN], int clone)
+{
+ int i;
+
+ if (clone && sc->sc_hasbmask) {
+ /* NB: we only do this if h/w supports multiple bssid */
+ for (i = 0; i < 32; i++)
+ if ((sc->sc_bssidmask & (1<<i)) == 0)
+ break;
+ if (i != 0)
+ mac[0] |= (i << 2)|0x2;
+ } else
+ i = 0;
+ sc->sc_bssidmask |= 1<<i;
+ if (i == 0)
+ sc->sc_nbssid0++;
+}
+
+static void
+reclaim_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ int i = mac[0] >> 2;
+ if (i != 0 || --sc->sc_nbssid0 == 0)
+ sc->sc_bssidmask &= ~(1<<i);
+}
+
static struct ieee80211vap *
ath_vap_create(struct ieee80211com *ic,
const char name[IFNAMSIZ], int unit, int opmode, int flags,
const uint8_t bssid[IEEE80211_ADDR_LEN],
- const uint8_t mac[IEEE80211_ADDR_LEN])
+ const uint8_t mac0[IEEE80211_ADDR_LEN])
{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
struct ath_vap *avp;
struct ieee80211vap *vap;
+ uint8_t mac[IEEE80211_ADDR_LEN];
+ int ic_opmode, needbeacon;
- if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
+ needbeacon = 0;
+ IEEE80211_ADDR_COPY(mac, mac0);
+
+ /* XXX ic unlocked and race against add? */
+ switch (opmode) {
+ case IEEE80211_M_STA:
+ if (sc->sc_nstavaps != 0) /* XXX only 1 sta for now */
+ return NULL;
+ if (sc->sc_nvaps) {
+ /*
+ * When there are multiple vaps we must fall
+ * back to s/w beacon miss handling.
+ */
+ flags |= IEEE80211_CLONE_NOBEACONS;
+ }
+ if (flags & IEEE80211_CLONE_NOBEACONS) {
+ sc->sc_swbmiss = 1;
+ ic_opmode = IEEE80211_M_HOSTAP;
+ } else
+ ic_opmode = opmode;
+ break;
+ case IEEE80211_M_IBSS:
+ if (sc->sc_nvaps != 0) /* XXX only 1 for now */
+ return NULL;
+ ic_opmode = opmode;
+ needbeacon = 1;
+ break;
+ case IEEE80211_M_AHDEMO:
+ /* fall thru... */
+ case IEEE80211_M_MONITOR:
+ if (sc->sc_nvaps != 0 && ic->ic_opmode != opmode) {
+ /* XXX not right for monitor mode */
+ ic_opmode = ic->ic_opmode;
+ } else
+ ic_opmode = opmode;
+ break;
+ case IEEE80211_M_HOSTAP:
+ needbeacon = 1;
+ /* fall thru... */
+ case IEEE80211_M_WDS:
+ if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA)
+ return NULL;
+ if (opmode == IEEE80211_M_WDS) {
+ /*
+ * Silently remove any request for a unique
+ * bssid; WDS vap's always share the local
+ * mac address.
+ */
+ flags &= ~IEEE80211_CLONE_BSSID;
+ }
+ ic_opmode = IEEE80211_M_HOSTAP;
+ break;
+ default:
+ return NULL;
+ }
+ if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf))
return NULL;
+
avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
M_80211_VAP, M_NOWAIT | M_ZERO);
if (avp == NULL)
return NULL;
+
+ if (opmode == IEEE80211_M_HOSTAP)
+ assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
+
vap = &avp->av_vap;
ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
@@ -720,10 +818,85 @@
avp->av_bmiss = vap->iv_bmiss;
vap->iv_bmiss = ath_bmiss_vap;
+ avp->av_bslot = -1;
+ if (needbeacon) {
+ /*
+ * Allocate beacon state and setup the q for buffered
+ * multicast frames. We know a beacon buffer is
+ * available because we checked above.
+ */
+ avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf);
+ STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list);
+ if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) {
+ int slot;
+ /*
+ * Assign the vap to a beacon xmit slot. As above
+ * this cannot fail to find a free one.
+ */
+ avp->av_bslot = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->sc_bslot[slot] == NULL) {
+ /*
+ * XXX hack, space out slots to better
+ * deal with traffic coming out of the
+ * cab q.
+ */
+ if (slot + 1 < ATH_BCBUF &&
+ sc->sc_bslot[slot+1] == NULL) {
+ avp->av_bslot = slot + 1;
+ break;
+ }
+ avp->av_bslot = slot;
+ /* NB: keep looking for a double slot */
+ }
+ }
+ KASSERT(sc->sc_bslot[avp->av_bslot] == NULL,
+ ("beacon slot %u not empty", avp->av_bslot));
+ sc->sc_bslot[avp->av_bslot] = vap;
+ sc->sc_nbcnvaps++;
+ }
+ if (sc->sc_hastsfadd) {
+ /*
+ * Multple vaps are to transmit beacons and we
+ * have h/w support for TSF adjusting; enable
+ * use of staggered beacons.
+ */
+ sc->sc_stagbeacons = 1;
+ }
+ STAILQ_INIT(&avp->av_mcastq.axq_q);
+ ATH_TXQ_LOCK_INIT(sc, &avp->av_mcastq);
+ }
/* complete setup */
ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
- ic->ic_opmode = opmode;
+ ic->ic_opmode = ic_opmode;
+ if (opmode != IEEE80211_M_WDS)
+ sc->sc_nvaps++;
+ switch (ic_opmode) {
+ case IEEE80211_M_IBSS:
+ sc->sc_opmode = HAL_M_IBSS;
+ break;
+ case IEEE80211_M_STA:
+ sc->sc_opmode = HAL_M_STA;
+ break;
+ case IEEE80211_M_AHDEMO:
+ case IEEE80211_M_HOSTAP:
+ sc->sc_opmode = HAL_M_HOSTAP;
+ break;
+ case IEEE80211_M_MONITOR:
+ sc->sc_opmode = HAL_M_MONITOR;
+ break;
+ default:
+ /* XXX should not happen */
+ break;
+ }
+
+ if (sc->sc_hastsfadd) {
+ /*
+ * Configure whether or not TSF adjust should be done.
+ */
+ ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons);
+ }
return vap;
}
@@ -746,12 +919,8 @@
ath_draintxq(sc); /* stop xmit side */
ath_stoprecv(sc); /* stop recv side */
}
- /*
- * Reclaim any pending mcast frames for the vap.
- */
- ath_tx_draintxq(sc, &avp->av_mcastq);
- ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
+ ieee80211_vap_detach(vap);
/*
* Reclaim beacon state. Note this must be done before
* the vap instance is reclaimed as we may have a reference
@@ -766,16 +935,25 @@
avp->av_bcbuf = NULL;
if (sc->sc_nbcnvaps == 0)
sc->sc_stagbeacons = 0;
+ /*
+ * Reclaim any pending mcast frames for the vap.
+ */
+ ath_tx_draintxq(sc, &avp->av_mcastq);
+ ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
}
/*
* Update bookkeeping.
*/
if (vap->iv_opmode == IEEE80211_M_STA) {
sc->sc_nstavaps--;
+ if (sc->sc_nstavaps == 0 && sc->sc_swbmiss)
+ sc->sc_swbmiss = 0;
+ } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ reclaim_address(sc, vap->iv_myaddr);
}
- ieee80211_vap_detach(vap);
+ if (vap->iv_opmode != IEEE80211_M_WDS)
+ sc->sc_nvaps--;
free(avp, M_80211_VAP);
- sc->sc_nvaps--;
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
/*
@@ -2216,13 +2394,17 @@
* hostap, adhoc, or monitor modes
* o enable promiscuous mode according to the interface state
* o accept beacons:
+ * - when operating in station mode for collecting rssi data when
+ * the station is otherwise quiet, or
* - when operating in adhoc mode so the 802.11 layer creates
* node table entries for peers,
- * - when operating in station mode for collecting rssi data when
- * the station is otherwise quiet, or
* - when scanning
+ * - when doing s/w beacon miss (e.g. for ap+sta)
* o accept control frames:
* - when in monitor mode
+ * o accept PHY error frames when hardware doesn't have MIB support
+ * to count and we need them for ANI (sta mode only at the moment)
+ * and we are not scanning (ANI is disabled)
* XXX BAR frames for 11n
*/
static u_int32_t
@@ -2240,7 +2422,7 @@
rfilt |= HAL_RX_FILTER_PROM;
if (ic->ic_opmode == IEEE80211_M_STA ||
sc->sc_opmode == HAL_M_IBSS ||
- sc->sc_scanning)
+ sc->sc_swbmiss || sc->sc_scanning)
rfilt |= HAL_RX_FILTER_BEACON;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
@@ -2977,7 +3159,7 @@
nexttbtt = roundup(nexttbtt, intval);
DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
__func__, nexttbtt, intval, ni->ni_intval);
- if (ic->ic_opmode == IEEE80211_M_STA) {
+ if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) {
HAL_BEACON_STATE bs;
int dtimperiod, dtimcount;
int cfpperiod, cfpcount;
==== //depot/projects/vap/sys/dev/ath/if_athvar.h#13 (text+ko) ====
@@ -206,6 +206,9 @@
int sc_debug;
int sc_nvaps; /* # vaps */
int sc_nstavaps; /* # station vaps */
+ u_int8_t sc_nbssid0; /* # vap's using base mac */
+ uint32_t sc_bssidmask; /* bssid mask */
+
u_int32_t sc_countrycode;
u_int32_t sc_regdomain;
void (*sc_node_free)(struct ieee80211_node *);
@@ -238,6 +241,7 @@
sc_hasbmask : 1,/* bssid mask support */
sc_hastsfadd: 1,/* tsf adjust support */
sc_beacons : 1,/* beacons running */
+ sc_swbmiss : 1,/* sta mode using sw bmiss */
sc_stagbeacons:1;/* use staggered beacons */
/* rate tables */
#define IEEE80211_MODE_HALF (IEEE80211_MODE_MAX+0)
@@ -552,6 +556,14 @@
#endif
#define ath_hal_hasfastframes(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK)
+#define ath_hal_hasbssidmask(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_BSSIDMASK, 0, NULL) == HAL_OK)
+#define ath_hal_hastsfadjust(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TSF_ADJUST, 0, NULL) == HAL_OK)
+#define ath_hal_gettsfadjust(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TSF_ADJUST, 1, NULL) == HAL_OK)
+#define ath_hal_settsfadjust(_ah, _onoff) \
+ ath_hal_setcapability(_ah, HAL_CAP_TSF_ADJUST, 1, _onoff, NULL)
#define ath_hal_hasrfsilent(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK)
#define ath_hal_getrfkill(_ah) \
More information about the p4-projects
mailing list