From owner-p4-projects@FreeBSD.ORG Tue Feb 19 00:12:41 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 803B816A469; Tue, 19 Feb 2008 00:12:41 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 13A9016A419 for ; Tue, 19 Feb 2008 00:12:41 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 085D413C448 for ; Tue, 19 Feb 2008 00:12:41 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m1J0Ced0006292 for ; Tue, 19 Feb 2008 00:12:40 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m1J0Cegr006289 for perforce@freebsd.org; Tue, 19 Feb 2008 00:12:40 GMT (envelope-from sam@freebsd.org) Date: Tue, 19 Feb 2008 00:12:40 GMT Message-Id: <200802190012.m1J0Cegr006289@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 135687 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Feb 2008 00:12:41 -0000 http://perforce.freebsd.org/chv.cgi?CH=135687 Change 135687 by sam@sam_ebb on 2008/02/19 00:12:15 first step towards vap support Affected files ... .. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 edit .. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 edit .. //depot/projects/vap/sys/dev/ath/if_ath.c#22 edit .. //depot/projects/vap/sys/dev/ath/if_athrate.h#7 edit .. //depot/projects/vap/sys/dev/ath/if_athvar.h#12 edit Differences ... ==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 (text+ko) ==== @@ -671,15 +671,15 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) - struct ieee80211com *ic = &sc->sc_ic; struct ath_node *an = ATH_NODE(ni); + const struct ieee80211_txparam *tp = an->an_tp; struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; int x, y, srate; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); sn->static_rate_ndx = -1; - if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { + if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is to be used; ic_fixed_rate is the * IEEE code for this rate (sans basic bit). Convert this @@ -688,7 +688,7 @@ */ /* NB: the rate set is assumed sorted */ srate = ni->ni_rates.rs_nrates - 1; - for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--) + for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--) ; /* * The fixed rate may not be available due to races @@ -786,18 +786,19 @@ * Reset the rate control state for each 802.11 state transition. */ void -ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state) +ath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state) { - struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211com *ic = vap->iv_ic; + struct ath_softc *sc = ic->ic_ifp->if_softc; if (state == IEEE80211_S_RUN) { - if (ic->ic_opmode != IEEE80211_M_STA) { + if (vap->iv_opmode != IEEE80211_M_STA) { /* * Sync rates for associated stations and neighbors. */ ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc); } - ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1); + ath_rate_newassoc(sc, ATH_NODE(vap->iv_bss), 1); } } ==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 (text+ko) ==== ==== //depot/projects/vap/sys/dev/ath/if_ath.c#22 (text+ko) ==== @@ -99,49 +99,57 @@ ATH_LED_POLL, }; +static struct ieee80211vap *ath_vap_create(struct ieee80211com *, + const char name[IFNAMSIZ], int unit, int opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void ath_vap_delete(struct ieee80211vap *); static void ath_init(void *); static void ath_stop_locked(struct ifnet *); static void ath_stop(struct ifnet *); static void ath_start(struct ifnet *); static int ath_reset(struct ifnet *); +static int ath_reset_vap(struct ieee80211vap *); static int ath_media_change(struct ifnet *); static void ath_watchdog(struct ifnet *); static int ath_ioctl(struct ifnet *, u_long, caddr_t); static void ath_fatal_proc(void *, int); static void ath_rxorn_proc(void *, int); +static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); -static int ath_key_alloc(struct ieee80211com *, +static int ath_key_alloc(struct ieee80211vap *, const struct ieee80211_key *, ieee80211_keyix *, ieee80211_keyix *); -static int ath_key_delete(struct ieee80211com *, +static int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *); -static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *, +static int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *, const u_int8_t mac[IEEE80211_ADDR_LEN]); -static void ath_key_update_begin(struct ieee80211com *); -static void ath_key_update_end(struct ieee80211com *); +static void ath_key_update_begin(struct ieee80211vap *); +static void ath_key_update_end(struct ieee80211vap *); static void ath_mode_init(struct ath_softc *); static void ath_setslottime(struct ath_softc *); static void ath_updateslot(struct ifnet *); static int ath_beaconq_setup(struct ath_hal *); static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); -static void ath_beacon_update(struct ieee80211com *, int item); +static void ath_beacon_update(struct ieee80211vap *, int item); static void ath_beacon_setup(struct ath_softc *, struct ath_buf *); static void ath_beacon_proc(void *, int); +static struct ath_buf *ath_beacon_generate(struct ath_softc *, + struct ieee80211vap *); static void ath_bstuck_proc(void *, int); +static void ath_beacon_return(struct ath_softc *, struct ath_buf *); static void ath_beacon_free(struct ath_softc *); -static void ath_beacon_config(struct ath_softc *); +static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *); static void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *, ath_bufhead *); static int ath_desc_alloc(struct ath_softc *); static void ath_desc_free(struct ath_softc *); static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *); static void ath_node_free(struct ieee80211_node *); -static int8_t ath_node_getrssi(const struct ieee80211_node *); static void ath_node_getsignal(const struct ieee80211_node *, int8_t *, int8_t *); static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *); -static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, - struct ieee80211_node *ni, +static void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, int noise, u_int32_t rstamp); static void ath_setdefantenna(struct ath_softc *, u_int); static void ath_rx_proc(void *, int); @@ -157,6 +165,7 @@ static void ath_tx_proc_q0(void *, int); static void ath_tx_proc_q0123(void *, int); static void ath_tx_proc(void *, int); +static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *); static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *); static void ath_draintxq(struct ath_softc *); static void ath_stoprecv(struct ath_softc *); @@ -166,13 +175,12 @@ static void ath_scan_end(struct ieee80211com *); static void ath_set_channel(struct ieee80211com *); static void ath_calibrate(void *); -static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int); +static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void ath_setup_stationkey(struct ieee80211_node *); static void ath_newassoc(struct ieee80211_node *, int); static int ath_getchannels(struct ath_softc *, HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL); static void ath_led_event(struct ath_softc *, int); -static void ath_update_txpow(struct ath_softc *); static int ath_rate_setup(struct ath_softc *, u_int mode); static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); @@ -378,7 +386,6 @@ goto bad; } callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE); - callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE); ATH_TXBUF_LOCK_INIT(sc); @@ -412,8 +419,6 @@ error = EIO; goto bad2; } - /* NB: s/w q, qnum used only by WITNESS */ - ath_txq_init(sc, &sc->sc_mcastq, HAL_NUM_TX_QUEUES+1); /* NB: insure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", @@ -497,10 +502,6 @@ IFQ_SET_READY(&ifp->if_snd); ic->ic_ifp = ifp; - ic->ic_reset = ath_reset; - ic->ic_newassoc = ath_newassoc; - ic->ic_updateslot = ath_updateslot; - ic->ic_wme.wme_update = ath_wme_update; /* XXX not right but it's not used anywhere important */ ic->ic_phytype = IEEE80211_T_OFDM; ic->ic_opmode = IEEE80211_M_STA; @@ -603,32 +604,26 @@ /* get mac address from hardware */ ath_hal_getmac(ah, ic->ic_myaddr); + /* NB: used to size node table key mapping array */ + ic->ic_max_keyix = sc->sc_keymax; /* call MI attach routine. */ ieee80211_ifattach(ic); sc->sc_opmode = ic->ic_opmode; + /* override default methods */ + ic->ic_newassoc = ath_newassoc; + ic->ic_updateslot = ath_updateslot; + ic->ic_wme.wme_update = ath_wme_update; + ic->ic_vap_create = ath_vap_create; + ic->ic_vap_delete = ath_vap_delete; + ic->ic_raw_xmit = ath_raw_xmit; ic->ic_node_alloc = ath_node_alloc; sc->sc_node_free = ic->ic_node_free; ic->ic_node_free = ath_node_free; - ic->ic_node_getrssi = ath_node_getrssi; ic->ic_node_getsignal = ath_node_getsignal; - sc->sc_recv_mgmt = ic->ic_recv_mgmt; - ic->ic_recv_mgmt = ath_recv_mgmt; - sc->sc_newstate = ic->ic_newstate; - ic->ic_newstate = ath_newstate; ic->ic_scan_start = ath_scan_start; ic->ic_scan_end = ath_scan_end; ic->ic_set_channel = ath_set_channel; - ic->ic_crypto.cs_max_keyix = sc->sc_keymax; - ic->ic_crypto.cs_key_alloc = ath_key_alloc; - ic->ic_crypto.cs_key_delete = ath_key_delete; - ic->ic_crypto.cs_key_set = ath_key_set; - ic->ic_crypto.cs_key_update_begin = ath_key_update_begin; - ic->ic_crypto.cs_key_update_end = ath_key_update_end; - ic->ic_raw_xmit = ath_raw_xmit; - ic->ic_update_beacon = ath_beacon_update; - /* complete initialization */ - ieee80211_media_init(ic, ath_media_change, ieee80211_media_status); ath_bpfattach(sc); /* @@ -690,6 +685,112 @@ return 0; } +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]) +{ + struct ath_vap *avp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return NULL; + avp = (struct ath_vap *) malloc(sizeof(struct ath_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (avp == NULL) + return NULL; + vap = &avp->av_vap; + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + + /* h/w crypto support */ + vap->iv_key_alloc = ath_key_alloc; + vap->iv_key_delete = ath_key_delete; + vap->iv_key_set = ath_key_set; + vap->iv_key_update_begin = ath_key_update_begin; + vap->iv_key_update_end = ath_key_update_end; + + /* override various methods */ + avp->av_recv_mgmt = vap->iv_recv_mgmt; + vap->iv_recv_mgmt = ath_recv_mgmt; + vap->iv_reset = ath_reset_vap; + vap->iv_update_beacon = ath_beacon_update; + avp->av_newstate = vap->iv_newstate; + vap->iv_newstate = ath_newstate; + avp->av_bmiss = vap->iv_bmiss; + vap->iv_bmiss = ath_bmiss_vap; + + /* complete setup */ + ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status); + + ic->ic_opmode = opmode; + return vap; +} + +static void +ath_vap_delete(struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; + struct ath_hal *ah = sc->sc_ah; + struct ath_vap *avp = ATH_VAP(vap); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* + * Quiesce the hardware while we remove the vap. In + * particular we need to reclaim all references to + * the vap state by any frames pending on the tx queues. + */ + ath_hal_intrset(ah, 0); /* disable interrupts */ + 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); + + /* + * Reclaim beacon state. Note this must be done before + * the vap instance is reclaimed as we may have a reference + * to it in the buffer for the beacon frame. + */ + if (avp->av_bcbuf != NULL) { + if (avp->av_bslot != -1) { + sc->sc_bslot[avp->av_bslot] = NULL; + sc->sc_nbcnvaps--; + } + ath_beacon_return(sc, avp->av_bcbuf); + avp->av_bcbuf = NULL; + if (sc->sc_nbcnvaps == 0) + sc->sc_stagbeacons = 0; + } + /* + * Update bookkeeping. + */ + if (vap->iv_opmode == IEEE80211_M_STA) { + sc->sc_nstavaps--; + } + ieee80211_vap_detach(vap); + free(avp, M_80211_VAP); + sc->sc_nvaps--; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* + * Restart rx+tx machines if still running (RUNNING will + * be reset if we just destroyed the last vap). + */ + if (ath_startrecv(sc) != 0) + if_printf(ifp, "%s: unable to restart recv logic\n", + __func__); + if (sc->sc_beacons) + ath_beacon_config(sc, NULL); + ath_hal_intrset(ah, sc->sc_imask); + } +} + void ath_suspend(struct ath_softc *sc) { @@ -864,37 +965,39 @@ } static void +ath_bmiss_vap(struct ieee80211vap *vap) +{ + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + u_int64_t lastrx = sc->sc_lastrx; + u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); + u_int bmisstimeout = + vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024; + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", + __func__, (unsigned long long) tsf, + (unsigned long long)(tsf - lastrx), + (unsigned long long) lastrx, bmisstimeout); + /* + * Workaround phantom bmiss interrupts by sanity-checking + * the time of our last rx'd frame. If it is within the + * beacon miss interval then ignore the interrupt. If it's + * truly a bmiss we'll get another interrupt soon and that'll + * be dispatched up for processing. + */ + if (tsf - lastrx > bmisstimeout) + ATH_VAP(vap)->av_bmiss(vap); + else + sc->sc_stats.ast_bmiss_phantom++; +} + +static void ath_bmiss_proc(void *arg, int pending) { struct ath_softc *sc = arg; - struct ieee80211com *ic = &sc->sc_ic; DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); - KASSERT(ic->ic_opmode == IEEE80211_M_STA, - ("unexpect operating mode %u", ic->ic_opmode)); - if (ic->ic_state == IEEE80211_S_RUN) { - u_int64_t lastrx = sc->sc_lastrx; - u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); - u_int bmisstimeout = - ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024; - - DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", - __func__, (unsigned long long) tsf, - (unsigned long long)(tsf - lastrx), - (unsigned long long) lastrx, bmisstimeout); - /* - * Workaround phantom bmiss interrupts by sanity-checking - * the time of our last rx'd frame. If it is within the - * beacon miss interval then ignore the interrupt. If it's - * truly a bmiss we'll get another interrupt soon and that'll - * be dispatched up for processing. - */ - if (tsf - lastrx > bmisstimeout) - ieee80211_beacon_miss(ic); - else - sc->sc_stats.ast_bmiss_phantom++; - } + ieee80211_beacon_miss(&sc->sc_ic); } /* @@ -971,13 +1074,9 @@ status); goto done; } + ath_chan_change(sc, ic->ic_curchan); /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath_update_txpow(sc); - /* * Likewise this is set during reset so update * state cached in the driver. */ @@ -1009,27 +1108,16 @@ */ if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) sc->sc_imask |= HAL_INT_MIB; - ath_hal_intrset(ah, sc->sc_imask); ifp->if_drv_flags |= IFF_DRV_RUNNING; - ic->ic_state = IEEE80211_S_INIT; + ath_hal_intrset(ah, sc->sc_imask); - /* - * The hardware should be ready to go now so it's safe - * to kick the 802.11 state machine as it's likely to - * immediately call back to us to send mgmt frames. - */ - ath_chan_change(sc, ic->ic_curchan); #ifdef ATH_TX99_DIAG if (sc->sc_tx99 != NULL) sc->sc_tx99->start(sc->sc_tx99); else #endif - if (ic->ic_opmode != IEEE80211_M_MONITOR) { - if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) - ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); - } else - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + ieee80211_start_all(ic); /* start all vap's */ done: ATH_UNLOCK(sc); } @@ -1038,7 +1126,6 @@ ath_stop_locked(struct ifnet *ifp) { struct ath_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", @@ -1065,7 +1152,6 @@ if (sc->sc_tx99 != NULL) sc->sc_tx99->stop(sc->sc_tx99); #endif - ieee80211_new_state(ic, IEEE80211_S_INIT, -1); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ifp->if_timer = 0; if (!sc->sc_invalid) { @@ -1083,8 +1169,7 @@ ath_hal_phydisable(ah); } else sc->sc_rxlink = NULL; - IFQ_DRV_PURGE(&ifp->if_snd); - ath_beacon_free(sc); + ath_beacon_free(sc); /* XXX not needed */ } } @@ -1138,7 +1223,6 @@ if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status)) if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", __func__, status); - ath_update_txpow(sc); /* update tx power state */ sc->sc_diversity = ath_hal_getdiversity(ah); sc->sc_calinterval = 1; sc->sc_caltries = 0; @@ -1150,14 +1234,20 @@ * might change as a result. */ ath_chan_change(sc, ic->ic_curchan); - if (ic->ic_state == IEEE80211_S_RUN) - ath_beacon_config(sc); /* restart beacons */ + if (sc->sc_beacons) + ath_beacon_config(sc, NULL); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); ath_start(ifp); /* restart xmit */ return 0; } +static int +ath_reset_vap(struct ieee80211vap *vap) +{ + return ath_reset(vap->iv_ic->ic_ifp); +} + static int ath_ff_always(struct ath_txq *txq, struct ath_buf *bf) { @@ -1210,7 +1300,7 @@ sc->sc_stats.ast_ff_flush++; /* encap and xmit */ - bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni); + bf->bf_m = ieee80211_encap(ni, bf->bf_m); if (bf->bf_m == NULL) { DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF, "%s: discard, encapsulation failure\n", @@ -1330,7 +1420,6 @@ ath_ff_check(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni) { - struct ieee80211com *ic = ni->ni_ic; struct ath_node *an = ATH_NODE(ni); struct ath_buf *bfstaged; int ff_flush, pri; @@ -1423,7 +1512,7 @@ ether_sprintf(an->an_node.ni_macaddr)); /* encap and xmit */ - bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni); + bfstaged->bf_m = ieee80211_encap(ni, bfstaged->bf_m); if (bfstaged->bf_m == NULL) { DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF, "%s: discard, encap failure\n", __func__); @@ -1525,13 +1614,10 @@ ath_start(struct ifnet *ifp) { struct ath_softc *sc = ifp->if_softc; - struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ath_buf *bf; struct mbuf *m, *next; - struct ieee80211_frame *wh; - struct ether_header *eh; struct ath_txq *txq; ath_bufhead frags; int pri; @@ -1539,6 +1625,9 @@ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) return; for (;;) { + IFQ_POLL(&ifp->if_snd, m); + if (m == NULL) + break; /* * Grab a TX buffer and associated resources. */ @@ -1550,158 +1639,70 @@ if (bf == NULL) { DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", __func__); + /* XXX tail drop */ sc->sc_stats.ast_tx_qstop++; ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } - /* - * Poll the management queue for frames; they - * have priority over normal data frames. - */ - IF_DEQUEUE(&ic->ic_mgtq, m); + + STAILQ_INIT(&frags); + IFQ_DEQUEUE(&ifp->if_snd, m); if (m == NULL) { /* - * No data frames go out unless we're associated. + * The q was emptied while we blocked, + * this can happen when we're preempted. */ - if (ic->ic_state != IEEE80211_S_RUN) { - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: discard data packet, state %s\n", - __func__, - ieee80211_state_name[ic->ic_state]); - sc->sc_stats.ast_tx_discard++; - ATH_TXBUF_LOCK(sc); - STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); - ATH_TXBUF_UNLOCK(sc); - break; - } - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */ - if (m == NULL) { - ATH_TXBUF_LOCK(sc); - STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); - ATH_TXBUF_UNLOCK(sc); - break; - } + ni = NULL; + goto reclaim; + } + ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + pri = M_WME_GETAC(m); + txq = sc->sc_ac2q[pri]; + if (ni->ni_ath_flags & IEEE80211_NODE_FF) { /* - * Cancel any background scan. + * Check queue length; if too deep drop this + * frame (tail drop considered good). */ - if (ic->ic_flags & IEEE80211_F_SCAN) - ieee80211_cancel_scan(ic); - - STAILQ_INIT(&frags); - /* - * Find the node for the destination so we can do - * things like power save and fast frames aggregation. - */ - if (m->m_len < sizeof(struct ether_header) && - (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { - ic->ic_stats.is_tx_nobuf++; /* XXX */ - ni = NULL; - goto bad; - } - eh = mtod(m, struct ether_header *); - ni = ieee80211_find_txnode(ic, eh->ether_dhost); - if (ni == NULL) { - /* NB: ieee80211_find_txnode does stat+msg */ + if (txq->axq_depth >= sc->sc_fftxqmax) { + DPRINTF(sc, ATH_DEBUG_FF, + "[%s] tail drop on q %u depth %u\n", + ether_sprintf(ni->ni_macaddr), + txq->axq_qnum, txq->axq_depth); + sc->sc_stats.ast_tx_qfull++; m_freem(m); - goto bad; - } - if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && - (m->m_flags & M_PWR_SAV) == 0) { - /* - * Station in power save mode; pass the frame - * to the 802.11 layer and continue. We'll get - * the frame back when the time is right. - */ - ieee80211_pwrsave(ni, m); goto reclaim; } - /* calculate priority so we can find the tx queue */ - if (ieee80211_classify(ic, m, ni)) { - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: discard, classification failure\n", - __func__); - m_freem(m); - goto bad; - } - pri = M_WME_GETAC(m); - txq = sc->sc_ac2q[pri]; - if (ni->ni_ath_flags & IEEE80211_NODE_FF) { - /* - * Check queue length; if too deep drop this - * frame (tail drop considered good). - */ - if (txq->axq_depth >= sc->sc_fftxqmax) { - DPRINTF(sc, ATH_DEBUG_FF, - "[%s] tail drop on q %u depth %u\n", - ether_sprintf(ni->ni_macaddr), - txq->axq_qnum, txq->axq_depth); - sc->sc_stats.ast_tx_qfull++; - m_freem(m); - goto reclaim; - } - m = ath_ff_check(sc, txq, bf, m, ni); - if (m == NULL) { - /* NB: ni ref & bf held on stageq */ - continue; - } - } - ifp->if_opackets++; - BPF_MTAP(ifp, m); - /* - * Encapsulate the packet in prep for transmission. - */ - m = ieee80211_encap(ic, m, ni); + m = ath_ff_check(sc, txq, bf, m, ni); if (m == NULL) { - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: encapsulation failure\n", - __func__); - sc->sc_stats.ast_tx_encap++; - goto bad; + /* NB: ni ref & bf held on stageq */ + continue; } - /* - * Check for fragmentation. If this frame - * has been broken up verify we have enough - * buffers to send all the fragments so all - * go out or none... - */ - if ((m->m_flags & M_FRAG) && - !ath_txfrag_setup(sc, &frags, m, ni)) { - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: out of txfrag buffers\n", __func__); - ic->ic_stats.is_tx_nobuf++; /* XXX */ - ath_freetx(m); - goto bad; - } - } else { - /* - * Hack! The referenced node pointer is in the - * rcvif field of the packet header. This is - * placed there by ieee80211_mgmt_output because - * we need to hold the reference with the frame - * and there's no other way (other than packet - * tags which we consider too expensive to use) - * to pass it along. - */ - ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; - m->m_pkthdr.rcvif = NULL; - - wh = mtod(m, struct ieee80211_frame *); - if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == - IEEE80211_FC0_SUBTYPE_PROBE_RESP) { - /* fill time stamp */ - u_int64_t tsf; - u_int32_t *tstamp; - - tsf = ath_hal_gettsf64(ah); - /* XXX: adjust 100us delay to xmit */ - tsf += 100; - tstamp = (u_int32_t *)&wh[1]; - tstamp[0] = htole32(tsf & 0xffffffff); - tstamp[1] = htole32(tsf >> 32); - } - sc->sc_stats.ast_tx_mgmt++; + } + ifp->if_opackets++; + /* + * Encapsulate the packet in prep for transmission. + */ + m = ieee80211_encap(ni, m); + if (m == NULL) { + DPRINTF(sc, ATH_DEBUG_XMIT, + "%s: encapsulation failure\n", __func__); + sc->sc_stats.ast_tx_encap++; + goto bad; + } + /* + * Check for fragmentation. If this frame + * has been broken up verify we have enough + * buffers to send all the fragments so all + * go out or none... + */ + if ((m->m_flags & M_FRAG) && + !ath_txfrag_setup(sc, &frags, m, ni)) { + DPRINTF(sc, ATH_DEBUG_XMIT, + "%s: out of txfrag buffers\n", __func__); + ic->ic_stats.is_tx_nobuf++; /* XXX */ + ath_freetx(m); + goto bad; } - nextfrag: /* * Pass the frame to the h/w for transmission. @@ -1735,11 +1736,11 @@ * Beware of state changing between frags. * XXX check sta power-save state? */ - if (ic->ic_state != IEEE80211_S_RUN) { + if (ni->ni_vap->iv_state != IEEE80211_S_RUN) { DPRINTF(sc, ATH_DEBUG_XMIT, "%s: flush fragmented packet, state %s\n", __func__, - ieee80211_state_name[ic->ic_state]); + ieee80211_state_name[ni->ni_vap->iv_state]); ath_freetx(next); goto reclaim; } @@ -1751,7 +1752,6 @@ } ifp->if_timer = 5; - ic->ic_lastdata = ticks; #if 0 /* * Flush stale frames from the fast-frame staging queue. @@ -1765,30 +1765,9 @@ static int ath_media_change(struct ifnet *ifp) { -#define IS_UP(ifp) \ - ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) - int error; - - error = ieee80211_media_change(ifp); - if (error == ENETRESET) { - struct ath_softc *sc = ifp->if_softc; - struct ieee80211com *ic = &sc->sc_ic; - - if (ic->ic_opmode == IEEE80211_M_AHDEMO) { - /* - * Adhoc demo mode is just ibss mode w/o beacons - * (mostly). The hal knows nothing about it; - * tell it we're operating in ibss mode. - */ - sc->sc_opmode = HAL_M_IBSS; - } else - sc->sc_opmode = ic->ic_opmode; - if (IS_UP(ifp)) - ath_init(sc); /* XXX lose error */ - error = 0; - } - return error; -#undef IS_UP + int error = ieee80211_media_change(ifp); + /* NB: only the fixed rate can change and that doesn't need a reset */ + return (error == ENETRESET ? 0 : error); } #ifdef ATH_DEBUG @@ -2091,10 +2070,10 @@ * 64 entries. */ static int -ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k, +ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k, ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) { - struct ath_softc *sc = ic->ic_ifp->if_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; /* * Group key allocation must be handled specially for @@ -2108,8 +2087,8 @@ * multi-station operation. */ if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) { - if (!(&ic->ic_nw_keys[0] <= k && - k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) { + if (!(&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { /* should not happen */ DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: bogus group key\n", __func__); @@ -2119,7 +2098,7 @@ * XXX we pre-allocate the global keys so * have no way to check if they've already been allocated. */ - *keyix = *rxkeyix = k - ic->ic_nw_keys; + *keyix = *rxkeyix = k - vap->iv_nw_keys; return 1; } @@ -2148,9 +2127,9 @@ * Delete an entry in the key cache allocated by ath_key_alloc. */ static int -ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) +ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) { - struct ath_softc *sc = ic->ic_ifp->if_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const struct ieee80211_cipher *cip = k->wk_cipher; u_int keyix = k->wk_keyix; @@ -2188,12 +2167,12 @@ * slot(s) must already have been allocated by ath_key_alloc. */ static int -ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, +ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, const u_int8_t mac[IEEE80211_ADDR_LEN]) { - struct ath_softc *sc = ic->ic_ifp->if_softc; + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; - return ath_keyset(sc, k, mac, ic->ic_bss); + return ath_keyset(sc, k, mac, vap->iv_bss); } /* @@ -2203,9 +2182,9 @@ * uses that originate in the driver. */ static void -ath_key_update_begin(struct ieee80211com *ic) +ath_key_update_begin(struct ieee80211vap *vap) { - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); @@ -2216,9 +2195,9 @@ } static void -ath_key_update_end(struct ieee80211com *ic) +ath_key_update_end(struct ieee80211vap *vap) { - struct ifnet *ifp = ic->ic_ifp; + struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); @@ -2233,8 +2212,6 @@ * operating mode and state: * * o always accept unicast, broadcast, and multicast traffic - * o maintain current state of phy error reception (the hal - * may enable phy error frames for noise immunity work) * o probe request frames are accepted only when operating in * hostap, adhoc, or monitor modes * o enable promiscuous mode according to the interface state @@ -2246,31 +2223,68 @@ * - when scanning * o accept control frames: * - when in monitor mode + * XXX BAR frames for 11n */ static u_int32_t ath_calcrxfilter(struct ath_softc *sc) { -#define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR) struct ieee80211com *ic = &sc->sc_ic; - struct ath_hal *ah = sc->sc_ah; struct ifnet *ifp = sc->sc_ifp; u_int32_t rfilt; - rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) - | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; + rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; if (ic->ic_opmode != IEEE80211_M_STA) rfilt |= HAL_RX_FILTER_PROBEREQ; if (ic->ic_opmode != IEEE80211_M_HOSTAP && (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; if (ic->ic_opmode == IEEE80211_M_STA || - ic->ic_opmode == IEEE80211_M_IBSS || + sc->sc_opmode == HAL_M_IBSS || sc->sc_scanning) rfilt |= HAL_RX_FILTER_BEACON; if (ic->ic_opmode == IEEE80211_M_MONITOR) rfilt |= HAL_RX_FILTER_CONTROL; + if (ic->ic_opmode == IEEE80211_M_STA && + !sc->sc_needmib && !sc->sc_scanning) + rfilt |= HAL_RX_FILTER_PHYERR; return rfilt; -#undef RX_FILTER_PRESERVE +} + +/* + * Merge multicast address from all vap's to form the hardware + * filter. Ideally we should only inspect our own list and the + * 802.11 layer would merge for us but that's bit difficult so + * for now we put the onus on the driver. + */ +static void +ath_merge_mcast(struct ath_softc *sc, u_int32_t mfilt[2]) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap; + + mfilt[0] = mfilt[1] = 0; + /* XXX locking */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = vap->iv_ifp; + struct ifmultiaddr *ifma; + + IF_ADDR_LOCK(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + u_int32_t val; + u_int8_t pos; + + /* calculate XOR of eight 6bit values */ + dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); + val = LE_READ_4(dl + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = LE_READ_4(dl + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + } + IF_ADDR_UNLOCK(ifp); + } } static void @@ -2279,9 +2293,7 @@ struct ieee80211com *ic = &sc->sc_ic; >>> TRUNCATED FOR MAIL (1000 lines) <<<