Date: Tue, 19 Feb 2008 02:06:43 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 135695 for review Message-ID: <200802190206.m1J26hYc027476@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=135695 Change 135695 by sam@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) \
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802190206.m1J26hYc027476>