Date: Tue, 19 Feb 2008 04:57:46 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 135700 for review Message-ID: <200802190457.m1J4vkla063585@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=135700 Change 135700 by sam@sam_ebb on 2008/02/19 04:56:47 Fixups to make multiple ap vaps work: o allocate all the beacon buffers (not just 1!) o fixup the state machine to to be multi-vap aware o move newstate super call up so we have the bss node setup before we do driver work that depends on it o import fixups to set associd+bssid in newstate only when needed While here add printfs to vap_create failure causes; may want to move them to debug msgs eventually. Affected files ... .. //depot/projects/vap/sys/dev/ath/if_ath.c#25 edit Differences ... ==== //depot/projects/vap/sys/dev/ath/if_ath.c#25 (text+ko) ==== @@ -738,8 +738,10 @@ /* XXX ic unlocked and race against add? */ switch (opmode) { case IEEE80211_M_STA: - if (sc->sc_nstavaps != 0) /* XXX only 1 sta for now */ + if (sc->sc_nstavaps != 0) { /* XXX only 1 sta for now */ + device_printf(sc->sc_dev, "only 1 sta vap supported\n"); return NULL; + } if (sc->sc_nvaps) { /* * When there are multiple vaps we must fall @@ -754,8 +756,11 @@ ic_opmode = opmode; break; case IEEE80211_M_IBSS: - if (sc->sc_nvaps != 0) /* XXX only 1 for now */ + if (sc->sc_nvaps != 0) { /* XXX only 1 for now */ + device_printf(sc->sc_dev, + "only 1 ibss vap supported\n"); return NULL; + } ic_opmode = opmode; needbeacon = 1; break; @@ -772,8 +777,11 @@ needbeacon = 1; /* fall thru... */ case IEEE80211_M_WDS: - if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA) + if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA) { + device_printf(sc->sc_dev, + "wds not supported in sta mode\n"); return NULL; + } if (opmode == IEEE80211_M_WDS) { /* * Silently remove any request for a unique @@ -785,15 +793,20 @@ ic_opmode = IEEE80211_M_HOSTAP; break; default: + device_printf(sc->sc_dev, "unknown opmode %d\n", opmode); return NULL; } - if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) + if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) { + device_printf(sc->sc_dev, "no beacon buffer available\n"); return NULL; + } avp = (struct ath_vap *) malloc(sizeof(struct ath_vap), M_80211_VAP, M_NOWAIT | M_ZERO); - if (avp == NULL) + if (avp == NULL) { + device_printf(sc->sc_dev, "unable to allocate memory\n"); return NULL; + } if (opmode == IEEE80211_M_HOSTAP) assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID); @@ -3475,7 +3488,7 @@ } error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, - "beacon", 1, 1); + "beacon", ATH_BCBUF, 1); if (error != 0) { ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); @@ -5397,6 +5410,22 @@ sc->sc_syncbeacon = 1; } +/* + * Walk the vap list and check if there any vap's in RUN state. + */ +static int +ath_isanyrunningvaps(const struct ieee80211vap *this) +{ + const struct ieee80211com *ic = this->iv_ic; + const struct ieee80211vap *vap; + + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + if (vap != this && vap->iv_state == IEEE80211_S_RUN) + return 1; + } + return 0; +} + static int ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { @@ -5404,8 +5433,8 @@ struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_vap *avp = ATH_VAP(vap); struct ath_hal *ah = sc->sc_ah; - struct ieee80211_node *ni; - int i, error, stamode; + struct ieee80211_node *ni = NULL; + int i, error; u_int32_t rfilt; static const HAL_LED_STATE leds[] = { HAL_LED_INIT, /* IEEE80211_S_INIT */ @@ -5427,40 +5456,41 @@ if (nstate == IEEE80211_S_INIT) { /* - * Shutdown host/driver operation: + * If there are no vaps left in RUN state then + * shutdown host/driver operation: * o disable interrupts so we don't rx frames * o clean any pending items on the task q * o notify the rate control algorithm */ - sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); - ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL); + if (!ath_isanyrunningvaps(vap)) { + sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); + /* + * Disable interrupts. + */ + ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL); + sc->sc_beacons = 0; #if 0 - /* XXX can't use taskqueue_drain 'cuz we're holding sc_mtx */ - taskqueue_drain(sc->sc_tq, &sc->sc_rxtask); - taskqueue_drain(sc->sc_tq, &sc->sc_rxorntask); - taskqueue_drain(sc->sc_tq, &sc->sc_bmisstask); - taskqueue_drain(sc->sc_tq, &sc->sc_bstucktask); + /* XXX can't use taskqueue_drain 'cuz we're holding sc_mtx */ + taskqueue_drain(sc->sc_tq, &sc->sc_rxtask); + taskqueue_drain(sc->sc_tq, &sc->sc_rxorntask); + taskqueue_drain(sc->sc_tq, &sc->sc_bmisstask); + taskqueue_drain(sc->sc_tq, &sc->sc_bstucktask); #endif + } ath_rate_newstate(vap, nstate); - goto done; + return avp->av_newstate(vap, nstate, arg); } + ni = vap->iv_bss; - rfilt = ath_calcrxfilter(sc); - stamode = (sc->sc_opmode == HAL_M_STA || sc->sc_opmode == HAL_M_IBSS); - if (stamode && nstate == IEEE80211_S_RUN) { + if (vap->iv_opmode == IEEE80211_M_STA && nstate == IEEE80211_S_RUN) { sc->sc_curaid = ni->ni_associd; IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid); - } else - sc->sc_curaid = 0; - + ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid); + } DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, ether_sprintf(sc->sc_curbssid), - sc->sc_curaid); - + __func__, rfilt, ether_sprintf(sc->sc_curbssid), sc->sc_curaid); ath_hal_setrxfilter(ah, rfilt); - if (stamode) - ath_hal_setassocid(ah, sc->sc_curbssid, ni->ni_associd); if (vap->iv_opmode != IEEE80211_M_STA && (vap->iv_flags & IEEE80211_F_PRIVACY)) { @@ -5468,23 +5498,26 @@ if (ath_hal_keyisvalid(ah, i)) ath_hal_keysetmac(ah, i, ni->ni_bssid); } - /* * Notify the rate control algorithm so rates * are setup should ath_beacon_alloc be called. */ ath_rate_newstate(vap, nstate); - if (nstate == IEEE80211_S_RUN) { + /* + * Invoke the parent method to do net80211 work. + */ + error = avp->av_newstate(vap, nstate, arg); + + if (error == 0 && nstate == IEEE80211_S_RUN) { + /* NB: collect bss node again, it may have changed */ + ni = vap->iv_bss; + DPRINTF(sc, ATH_DEBUG_STATE, - "%s(RUN): iv_flags=0x%08x iv=%d bssid=%s " - "capinfo=0x%04x chan=%d\n" - , __func__ - , vap->iv_flags - , ni->ni_intval - , ether_sprintf(ni->ni_bssid) - , ni->ni_capinfo - , ieee80211_chan2ieee(ic, ic->ic_curchan)); + "%s(RUN): iv_flags 0x%08x bintvl %d bssid %s " + "capinfo 0x%04x chan %d\n", __func__, + vap->iv_flags, ni->ni_intval, ether_sprintf(ni->ni_bssid), + ni->ni_capinfo, ieee80211_chan2ieee(ic, ic->ic_curchan)); switch (vap->iv_opmode) { case IEEE80211_M_HOSTAP: @@ -5499,7 +5532,7 @@ * be called with beacon transmission active. */ ath_hal_stoptxdma(ah, sc->sc_bhalq); - ath_beacon_free(sc); + error = ath_beacon_alloc(sc, ni); if (error != 0) goto bad; @@ -5507,13 +5540,17 @@ * If joining an adhoc network defer beacon timer * configuration to the next beacon frame so we * have a current TSF to use. Otherwise we're - * starting an ibss/bss so there's no need to delay. + * starting an ibss/bss so there's no need to delay; + * if this is the first vap moving to RUN state, then + * beacon state needs to be [re]configured. */ if (vap->iv_opmode == IEEE80211_M_IBSS && - vap->iv_bss->ni_tstamp.tsf != 0) + ni->ni_tstamp.tsf != 0) { sc->sc_syncbeacon = 1; - else + } else if (!sc->sc_beacons) { ath_beacon_config(sc, vap); + sc->sc_beacons = 1; + } break; case IEEE80211_M_STA: /* @@ -5530,6 +5567,8 @@ */ sc->sc_syncbeacon = 1; break; + case IEEE80211_M_WDS: + break; default: break; } @@ -5544,24 +5583,19 @@ sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + /* + * Finally, start any timers. + */ + if (sc->sc_calinterval != 0) { + /* start periodic recalibration timer */ + callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, + ath_calibrate, sc); + } } else { ath_hal_intrset(ah, sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); } -done: - /* - * Invoke the parent method to complete the work. - */ - error = avp->av_newstate(vap, nstate, arg); - /* - * Finally, start any timers. - */ - if (nstate == IEEE80211_S_RUN) { - /* start periodic recalibration timer */ - callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, - ath_calibrate, sc); - } bad: return error; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802190457.m1J4vkla063585>