Date: Sat, 7 May 2005 03:17:47 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 76646 for review Message-ID: <200505070317.j473Hlmb020838@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=76646 Change 76646 by sam@sam_ebb on 2005/05/07 03:17:28 checkpoint backport Affected files ... .. //depot/projects/vap/sys/conf/files#3 edit .. //depot/projects/vap/sys/dev/ath/ath_rate/onoe/onoe.c#5 edit .. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#2 edit .. //depot/projects/vap/sys/dev/ath/if_ath.c#7 edit .. //depot/projects/vap/sys/dev/ath/if_athvar.h#5 edit .. //depot/projects/vap/sys/dev/wi/if_wi.c#5 edit .. //depot/projects/vap/sys/modules/Makefile#3 edit .. //depot/projects/vap/sys/modules/wlan/Makefile#2 edit .. //depot/projects/vap/sys/net80211/_ieee80211.h#4 edit .. //depot/projects/vap/sys/net80211/ieee80211.c#7 edit .. //depot/projects/vap/sys/net80211/ieee80211.h#2 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto.h#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_ccmp.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_none.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_tkip.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_crypto_wep.c#4 edit .. //depot/projects/vap/sys/net80211/ieee80211_freebsd.c#7 edit .. //depot/projects/vap/sys/net80211/ieee80211_freebsd.h#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_input.c#8 edit .. //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_ioctl.h#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_node.c#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_node.h#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_output.c#7 edit .. //depot/projects/vap/sys/net80211/ieee80211_proto.c#6 edit .. //depot/projects/vap/sys/net80211/ieee80211_proto.h#5 edit .. //depot/projects/vap/sys/net80211/ieee80211_regdomain.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_regdomain.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_scan.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_scan.h#1 add .. //depot/projects/vap/sys/net80211/ieee80211_scan_ap.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_scan_sta.c#1 add .. //depot/projects/vap/sys/net80211/ieee80211_var.h#8 edit Differences ... ==== //depot/projects/vap/sys/conf/files#3 (text+ko) ==== @@ -1385,6 +1385,10 @@ net80211/ieee80211_node.c optional wlan net80211/ieee80211_output.c optional wlan net80211/ieee80211_proto.c optional wlan +net80211/ieee80211_regdomain.c optional wlan +net80211/ieee80211_scan.c optional wlan +net80211/ieee80211_scan_ap.c optional wlan_scan_ap +net80211/ieee80211_scan_sta.c optional wlan_scan_sta net80211/ieee80211_xauth.c optional wlan_xauth netatalk/aarp.c optional netatalk netatalk/at_control.c optional netatalk ==== //depot/projects/vap/sys/dev/ath/ath_rate/onoe/onoe.c#5 (text+ko) ==== @@ -198,9 +198,6 @@ (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); ni->ni_txrate = rate; - /* XXX management/control frames always go at the lowest speed */ - an->an_tx_mgtrate = rt->info[0].rateCode; - an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. @@ -247,7 +244,7 @@ /* NB: only do this if we didn't already do it above */ on->on_tx_rate3 = rt->info[0].rateCode; on->on_tx_rate3sp = - an->an_tx_mgtrate | rt->info[0].shortPreamble; + on->on_tx_rate3 | rt->info[0].shortPreamble; } else { on->on_tx_rate3 = on->on_tx_rate3sp = 0; } ==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#2 (text+ko) ==== @@ -139,28 +139,11 @@ return -1; } -/* - * Setup rate codes for management/control frames. We force - * all such frames to the lowest rate. - */ -static void -ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an) -{ - const HAL_RATE_TABLE *rt = sc->sc_currates; - - /* setup rates for management frames */ - /* XXX management/control frames always go at lowest speed */ - an->an_tx_mgtrate = rt->info[0].rateCode; - an->an_tx_mgtratesp = an->an_tx_mgtrate - | rt->info[0].shortPreamble; -} - void ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) { DPRINTF(sc, "%s:\n", __func__); /* NB: assumed to be zero'd by caller */ - ath_rate_setmgtrates(sc, an); } void @@ -696,7 +679,7 @@ * rate set is checked when the station associates. */ const struct ieee80211_rateset *rs = - &ic->ic_sup_rates[ic->ic_curmode]; + &ic->ic_sup_rates[ieee80211_chan2mode(ic->ic_bsschan)]; int r = rs->rs_rates[vap->iv_fixed_rate] & IEEE80211_RATE_VAL; /* NB: the rate set is assumed sorted */ srate = ni->ni_rates.rs_nrates - 1; ==== //depot/projects/vap/sys/dev/ath/if_ath.c#7 (text+ko) ==== @@ -93,6 +93,21 @@ ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) +/* + * MAC addresses for multiple BSS on the same radio. + * The very first VAP will just use the MAC address from the EEPROM. + * For the next 3 VAPs, we set the U/L bit (bit 1) in MAC address, + * and use the next two bits as the index of the VAP. + */ +#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ + ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) +#define ATH_GET_VAP_ID(bssid) \ + ((bssid)[0] >> 2) +#define ATH_SET_VAP_BSSID(bssid, id) do { \ + if (id) \ + (bssid)[0] |= (((id)<<2)|0x02); \ +} while(0) + enum { ATH_LED_TX, ATH_LED_RX, @@ -100,35 +115,39 @@ }; static struct ieee80211vap *ath_vap_create(struct ieee80211com *, - const char name[IFNAMSIZ], int unit, int opmode); + const char name[IFNAMSIZ], int unit, + int opmode, int flags); 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 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_proc(void *, int); -static int ath_key_alloc(struct ieee80211com *, +static int ath_key_alloc(struct ieee80211vap *, const struct ieee80211_key *); -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 void ath_beacon_dturbo_config(struct ath_softc *, u_int32_t ); +static void ath_beacon_dturbo_update(struct ath_softc *); +static void ath_turbo_switch(void *); static int ath_beaconq_setup(struct ath_hal *); static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); static void ath_beacon_setup(struct ath_softc *, struct ath_buf *); static void ath_beacon_proc(void *, int); 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_descdma_cleanup(struct ath_softc *sc, @@ -151,6 +170,7 @@ static int ath_tx_start(struct ath_softc *, struct ieee80211_node *, struct ath_buf *, struct mbuf *); static void ath_tx_proc_q0(void *, int); +static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *); static void ath_tx_proc_q0123(void *, int); static void ath_tx_proc(void *, int); static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *); @@ -158,9 +178,12 @@ static void ath_stoprecv(struct ath_softc *); static int ath_startrecv(struct ath_softc *); static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *); -static void ath_next_scan(void *); static void ath_calibrate(void *); +static void ath_scan_start(struct ieee80211com *); +static void ath_scan_end(struct ieee80211com *); +static void ath_set_channel(struct ieee80211com *); 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 *, u_int cc, HAL_BOOL outdoor, HAL_BOOL xchanmode); @@ -257,6 +280,7 @@ struct ath_hal *ah; HAL_STATUS status; int error = 0, i; + u_int cc; DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); @@ -302,11 +326,11 @@ * Get the hardware key cache size. */ sc->sc_keymax = ath_hal_keycachesize(ah); - if (sc->sc_keymax > sizeof(sc->sc_keymap) * NBBY) { + if (sc->sc_keymax > ATH_KEYMAX) { if_printf(ifp, "Warning, using only %zu of %u key cache slots\n", - sizeof(sc->sc_keymap) * NBBY, sc->sc_keymax); - sc->sc_keymax = sizeof(sc->sc_keymap) * NBBY; + ATH_KEYMAX, sc->sc_keymax); + sc->sc_keymax = ATH_KEYMAX; } /* * Reset the key cache since some parts do not @@ -362,8 +386,8 @@ if_printf(ifp, "failed to allocate descriptors: %d\n", error); goto bad; } - callout_init(&sc->sc_scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0); callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE); + callout_init(&sc->sc_dt_cb, CALLOUT_MPSAFE); ATH_TXBUF_LOCK_INIT(sc); @@ -476,12 +500,13 @@ IFQ_SET_READY(&ifp->if_snd); ic->ic_ifp = ifp; - ic->ic_reset = ath_reset_vap; + 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; ic->ic_caps = IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ | IEEE80211_C_HOSTAP /* hostap mode */ @@ -513,6 +538,7 @@ if (ath_hal_tkipsplit(ah)) sc->sc_splitmic = 1; } + sc->sc_mcastkey = ath_hal_hasmcastkeysearch(ah); /* * TPC support can be done either with a global cap or * per-packet support. The latter is not available on @@ -536,10 +562,11 @@ ic->ic_caps |= IEEE80211_C_BURST; if (ath_hal_hasfastframes(ah)) ic->ic_caps |= IEEE80211_C_FF; -#ifdef notyet - if (ath_hal_getwirelessmodes(ah) & (HAL_MODE_108G|HAL_MODE_TURBO)) + ath_hal_getcountrycode(ah, &cc); + if (ath_hal_getwirelessmodes(ah, cc) & (HAL_MODE_108G|HAL_MODE_108A)) ic->ic_caps |= IEEE80211_C_TURBOP; -#endif + sc->sc_hasbmask = ath_hal_hasbssidmask(ah); + sc->sc_hastsfadd = ath_hal_hastsfadjust(ah); /* * Indicate we need the 802.11 header padded to a @@ -564,6 +591,11 @@ /* get mac address from hardware */ ath_hal_getmac(ah, ic->ic_myaddr); + if (sc->sc_hasbmask) { + ath_hal_getbssidmask(ah, sc->sc_bssidmask); + ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); + ath_hal_setbssidmask(ah, sc->sc_bssidmask); + } /* XXX required for arp, yech */ IEEE80211_ADDR_COPY(IFP2AC(ifp)->ac_enaddr, ic->ic_myaddr); @@ -576,15 +608,14 @@ ic->ic_node_getrssi = ath_node_getrssi; sc->sc_recv_mgmt = ic->ic_recv_mgmt; ic->ic_recv_mgmt = ath_recv_mgmt; - ic->ic_key_alloc = ath_key_alloc; - ic->ic_key_delete = ath_key_delete; - ic->ic_key_set = ath_key_set; - ic->ic_key_update_begin = ath_key_update_begin; - ic->ic_key_update_end = ath_key_update_end; ic->ic_vap_create = ath_vap_create; ic->ic_vap_delete = ath_vap_delete; + ic->ic_scan_start = ath_scan_start; + ic->ic_scan_end = ath_scan_end; + ic->ic_set_channel = ath_set_channel; + ath_bpfattach(sc); if (bootverbose) @@ -635,41 +666,45 @@ static struct ieee80211vap * ath_vap_create(struct ieee80211com *ic, - const char name[IFNAMSIZ], int unit, int opmode) + const char name[IFNAMSIZ], int unit, int opmode, int flags) { struct ath_softc *sc = ic->ic_ifp->if_softc; struct ieee80211vap *vap; + struct ath_vap *avp; + int newopmode; /* XXX ic unlocked and race against add */ + newopmode = opmode; switch (opmode) { case IEEE80211_M_STA: - /* XXX sta+ap for repeater application */ - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one for now */ + /* if using h/w station beacons, must be first vap created */ + if ((flags & IEEE80211_CLONE_NOBEACONS) == 0 && sc->sc_nvaps) return NULL; - ic->ic_opmode = opmode; + if (flags & IEEE80211_CLONE_NOBEACONS) { + /* operate chip in AP mode */ + newopmode = IEEE80211_M_HOSTAP; + } break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: if ((ic->ic_caps & (IEEE80211_C_IBSS << opmode)) == 0) return NULL; - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one for now */ + if (sc->sc_nvaps != 0) /* only one for now */ return NULL; - ic->ic_opmode = opmode; break; case IEEE80211_M_HOSTAP: case IEEE80211_M_WDS: /* permit multiple ap's and/or wds links */ /* XXX device capability */ - /* XXX max count */ - /* XXX sta+ap for repeater/bridge application */ - if (!TAILQ_EMPTY(&ic->ic_vaps) && - ic->ic_opmode != IEEE80211_M_HOSTAP) + if (sc->sc_nvaps != 0 && ic->ic_opmode != IEEE80211_M_HOSTAP) return NULL; + if (opmode == IEEE80211_M_HOSTAP && STAILQ_EMPTY(&sc->sc_bbuf)) + return NULL; /* * XXX Not sure if this is correct when operating only * with WDS links. */ - ic->ic_opmode = IEEE80211_M_HOSTAP; + newopmode = IEEE80211_M_HOSTAP; break; case IEEE80211_M_MONITOR: /* XXX always allow, is that ok? */ @@ -679,31 +714,197 @@ default: return NULL; } - MALLOC(vap, struct ieee80211vap *, sizeof(struct ieee80211vap), + MALLOC(avp, struct ath_vap *, sizeof(struct ath_vap), M_80211_VAP, M_NOWAIT | M_ZERO); - if (vap == NULL) { + if (avp == NULL) { /* XXX msg */ return NULL; } + vap = &avp->av_vap; ieee80211_vap_setup(ic, vap, name, unit, opmode); /* override with driver methods */ - sc->sc_newstate = vap->iv_newstate; /* XXX per-vap */ + avp->av_newstate = vap->iv_newstate; /* XXX per-vap */ vap->iv_newstate = ath_newstate; - /* XXX multi-bssid */ + 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; + + if ((flags & IEEE80211_CLONE_BSSID) && + sc->sc_nvaps != 0 && opmode != IEEE80211_M_WDS && sc->sc_hasbmask) { + struct ieee80211vap *v; + int id_mask, id; - /* XXX allocate+setup beacon state for hostap/ibss */ + /* + * Hardware supports the bssid mask and a unique + * bssid was requested. Assign a new mac address + * and expand our bssid mask to cover the active + * virtual ap's with distinct addresses. + */ + KASSERT(sc->sc_nvaps <= ATH_BCBUF, + ("too many virtual ap's: %d", sc->sc_nvaps)); + /* do a full search to mark all the allocated vaps */ + id_mask = 0; + TAILQ_FOREACH(v, &ic->ic_vaps, iv_next) + id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr)); + for (id = 0; id < ATH_BCBUF; id++) { + /* get the first available slot */ + if ((id_mask & (1 << id)) == 0) { + ATH_SET_VAP_BSSID(vap->iv_myaddr, id); + break; + } + } + } + avp->av_bslot = -1; + switch (opmode) { + case IEEE80211_M_HOSTAP: + case IEEE80211_M_IBSS: + /* + * Setup queue for buffering multicast traffic. + */ + STAILQ_INIT(&avp->av_mcastq.axq_q); + ATH_TXQ_LOCK_INIT(sc, &avp->av_mcastq); + /* + * Allocate beacon state for hostap/ibss. We know + * a buffer is available because of the check above. + */ + avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf); + STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list); + if (opmode == IEEE80211_M_HOSTAP || !sc->sc_hasveol) { + int slot; + /* + * Assign the vap to a beacon xmit slot. As + * above, this cannot fail to find 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 misses + */ + 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; + } + if (sc->sc_hastsfadd) + ath_hal_settsfadjust(sc->sc_ah, 1); + break; + case IEEE80211_M_STA: + /* + * If we're to operate in station mode and TSF + * adjust support is available, turn it off. + */ + if (newopmode == IEEE80211_M_STA && sc->sc_hastsfadd) + ath_hal_settsfadjust(sc->sc_ah, 0); + sc->sc_nstavaps++; + if (flags & IEEE80211_CLONE_NOBEACONS) { + avp->av_nobeacons = 1; + sc->sc_rxbeacons++; + } + break; + case IEEE80211_M_MONITOR: + case IEEE80211_M_WDS: + /* XXX does WDS need beacons for state changes? */ + avp->av_nobeacons = 1; /* no need for beacon setup */ + break; + } + /* complete setup */ (void) ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status); + ic->ic_opmode = newopmode; + sc->sc_nvaps++; + return vap; } void ath_vap_delete(struct ieee80211vap *vap) { + struct ifnet *parent = vap->iv_ic->ic_ifp; + struct ath_softc *sc = parent->if_softc; + struct ath_hal *ah = sc->sc_ah; + struct ath_vap *avp = ATH_VAP(vap); + int i; + + KASSERT(vap->iv_state == IEEE80211_S_INIT, ("vap not stopped")); + + if (parent->if_flags & IFF_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. + * + * XXX can we do this w/o affecting other vap's? + */ + ath_hal_intrset(ah, 0); /* disable interrupts */ + ath_draintxq(sc); /* stop xmit side */ + ath_stoprecv(sc); /* stop recv side */ + } + + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) { + /* + * Reclaim any pending mcast bufs on 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 + * 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; + ath_beacon_return(sc, avp->av_bcbuf); + avp->av_bcbuf = NULL; + } + } ieee80211_vap_detach(vap); - FREE(vap, M_80211_VAP); + if (vap->iv_opmode == IEEE80211_M_STA) { + sc->sc_nstavaps--; + if (avp->av_nobeacons) + sc->sc_rxbeacons--; + } + sc->sc_nvaps--; + if (sc->sc_bmaster == vap) { + sc->sc_bmaster = NULL; + /* XXX pick a new master for restarting beacons */ + /* XXX not right, need to restart w/ current/adjusted TSF? */ + for (i = 0; i < ATH_BCBUF; i++) { + struct ieee80211vap *v = sc->sc_bslot[i]; + if (v != NULL && !ATH_VAP(v)->av_nobeacons) { + sc->sc_bmaster = v; + break; + } + } + } + FREE(avp, M_80211_VAP); + + if (parent->if_flags & IFF_RUNNING) { + /* + * Restart rx+tx machines if device is still running. + */ + if (ath_startrecv(sc) != 0) /* restart recv */ + if_printf(parent, "%s: unable to start recv logic\n", + __func__); + if (sc->sc_bmaster != NULL) + ath_beacon_config(sc); /* restart beacons */ + ath_hal_intrset(ah, sc->sc_imask); + } } void @@ -799,7 +1000,13 @@ * Handle beacon transmission directly; deferring * this is too slow to meet timing constraints * under load. + * + * If we are using dynamic turbo, update the + * capability info and arrange for a mode change + * if needed. */ + if (sc->sc_dturbo) + ath_beacon_dturbo_update(sc); ath_beacon_proc(sc, 0); } if (status & HAL_INT_RXEOL) { @@ -818,8 +1025,26 @@ } if (status & HAL_INT_RX) taskqueue_enqueue(taskqueue_swi, &sc->sc_rxtask); - if (status & HAL_INT_TX) + if (status & HAL_INT_TX) { + /* + * Check the beacon queue when a dynamic turbo switch + * is pending so we can initiate the change once the + * beacon announcing the switch has gone out. + * XXX must wait for all vap's beacons + */ + if (sc->sc_dt_switch && + ath_hal_numtxpending(ah, sc->sc_bhalq) == 0) { + sc->sc_dt_switch = 0; + /* + * Hack: defer switch for 10ms to permit slow + * clients time to track us. This especially + * noticeable with Windows clients. + */ + callout_reset(&sc->sc_dt_cb, + (hz*10)/1000, ath_turbo_switch, ifp); + } taskqueue_enqueue(taskqueue_swi, &sc->sc_txtask); + } if (status & HAL_INT_BMISS) { sc->sc_stats.ast_bmiss++; taskqueue_enqueue(taskqueue_swi, &sc->sc_bmisstask); @@ -871,7 +1096,7 @@ } static u_int -ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan) +ath_chan2flags(struct ieee80211_channel *chan) { #define N(a) (sizeof(a) / sizeof(a[0])) static const u_int modeflags[] = { @@ -880,10 +1105,10 @@ CHANNEL_B, /* IEEE80211_MODE_11B */ CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 0, /* IEEE80211_MODE_FH */ - CHANNEL_T, /* IEEE80211_MODE_TURBO_A */ + CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */ CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ }; - enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan); + enum ieee80211_phymode mode = ieee80211_chan2mode(chan); KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode)); KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode)); @@ -917,8 +1142,8 @@ * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->sc_curchan.channel = ic->ic_ibss_chan->ic_freq; - sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_ibss_chan); + sc->sc_curchan.channel = ic->ic_curchan->ic_freq; + sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan); if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) { if_printf(ifp, "unable to reset hardware; hal status %u\n", status); @@ -965,7 +1190,7 @@ * 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_ibss_chan); + ath_chan_change(sc, ic->ic_curchan); ieee80211_start_running(ic); /* NB: marks IFF_RUNNING */ done: ATH_UNLOCK(sc); @@ -1061,9 +1286,9 @@ * Convert to a HAL channel description with the flags * constrained to reflect the current operating mode. */ - c = ic->ic_ibss_chan; + c = ic->ic_curchan; sc->sc_curchan.channel = c->ic_freq; - sc->sc_curchan.channelFlags = ath_chan2flags(ic, c); + sc->sc_curchan.channelFlags = ath_chan2flags(c); ath_hal_intrset(ah, 0); /* disable interrupts */ ath_draintxq(sc); /* stop xmit side */ @@ -1081,7 +1306,7 @@ * might change as a result. */ ath_chan_change(sc, c); - if (sc->sc_beacons) + if (sc->sc_bmaster != NULL) ath_beacon_config(sc); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); @@ -1089,14 +1314,6 @@ return 0; } -static int -ath_reset_vap(struct ifnet *ifp) -{ - struct ieee80211vap *vap = ifp->if_softc; - - return ath_reset(vap->iv_ic->ic_ifp); -} - static int ath_ff_always(struct ath_txq *txq, struct ath_buf *bf) { @@ -1486,6 +1703,7 @@ sc->sc_stats.ast_tx_encap++; goto bad; } + /* XXX deal with tx frags */ } else { /* * Hack! The referenced node pointer is in the @@ -1621,7 +1839,8 @@ */ static int ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, - const u_int8_t mac[IEEE80211_ADDR_LEN]) + const u_int8_t mac0[IEEE80211_ADDR_LEN], + struct ieee80211_node *bss) { #define N(a) (sizeof(a)/sizeof(a[0])) static const u_int8_t ciphermap[] = { @@ -1635,6 +1854,8 @@ }; struct ath_hal *ah = sc->sc_ah; const struct ieee80211_cipher *cip = k->wk_cipher; + u_int8_t gmac[IEEE80211_ADDR_LEN]; + const u_int8_t *mac; HAL_KEYVAL hk; memset(&hk, 0, sizeof(hk)); @@ -1652,6 +1873,18 @@ } else hk.kv_type = HAL_CIPHER_CLR; + if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) { + /* + * Group keys on hardware that supports multicast frame + * key search use a mac that is the sender's address with + * the high bit set instead of the app-specified address. + */ + IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr); + gmac[0] |= 0x80; + mac = gmac; + } else + mac = mac0; + if (hk.kv_type == HAL_CIPHER_TKIP && (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) { @@ -1787,9 +2020,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) { - struct ath_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; /* * Group key allocation must be handled specially for @@ -1842,22 +2076,38 @@ * 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 ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const struct ieee80211_cipher *cip = k->wk_cipher; u_int keyix = k->wk_keyix; + struct ieee80211_node *ni; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); ath_hal_keyreset(ah, keyix); /* + * Check the key->node map and flush any ref. + */ + ni = sc->sc_keyixmap[keyix]; + if (ni != NULL) { + ieee80211_free_node(ni); + sc->sc_keyixmap[keyix] = NULL; + } + /* * Handle split tx/rx keying required for TKIP with h/w MIC. */ if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && - (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) + (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) { ath_hal_keyreset(ah, keyix+32); /* RX key */ + ni = sc->sc_keyixmap[keyix+32]; + if (ni != NULL) { /* as above... */ + ieee80211_free_node(ni); + sc->sc_keyixmap[keyix+32] = NULL; + } + } if (keyix >= IEEE80211_WEP_NKID) { /* * Don't touch keymap entries for global keys so @@ -1880,12 +2130,13 @@ * 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 ifnet *ifp = vap->iv_ic->ic_ifp; + struct ath_softc *sc = ifp->if_softc; - return ath_keyset(sc, k, mac); + return ath_keyset(sc, k, mac, vap->iv_bss); } /* @@ -1895,9 +2146,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__); @@ -1908,9 +2159,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__); @@ -1935,17 +2186,19 @@ * node table entries for peers, * - when operating in station mode for collecting rssi data when * the station is otherwise quiet, or + * - when operating as a repeater so we see repeater-sta beacons * - when scanning */ 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_if; u_int32_t rfilt; - rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYERR) + rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; if (ic->ic_opmode != IEEE80211_M_STA) rfilt |= HAL_RX_FILTER_PROBEREQ; @@ -1954,9 +2207,45 @@ rfilt |= HAL_RX_FILTER_PROM; if (ic->ic_opmode == IEEE80211_M_STA || ic->ic_opmode == IEEE80211_M_IBSS || - (ic->ic_flags & IEEE80211_F_SCAN)) + sc->sc_rxbeacons || sc->sc_scanning) rfilt |= HAL_RX_FILTER_BEACON; return rfilt; +#undef RX_FILTER_PRESERVE +} + +/* + * Merge multicast addresses 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 a 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; + u_int32_t val; + u_int8_t pos; + struct ifmultiaddr *ifma; + + mfilt[0] = mfilt[1] = 0; + /* XXX locking */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = &vap->iv_if; + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + + /* 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)); + } + } } static void @@ -1965,9 +2254,7 @@ struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &sc->sc_if; - u_int32_t rfilt, mfilt[2], val; - u_int8_t pos; - struct ifmultiaddr *ifma; + u_int32_t rfilt, mfilt[2]; /* configure rx filter */ rfilt = ath_calcrxfilter(sc); @@ -1989,19 +2276,7 @@ /* calculate and install multicast filter */ if ((ifp->if_flags & IFF_ALLMULTI) == 0) { - mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - - /* 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)); - } + ath_merge_mcast(sc, mfilt); } else { mfilt[0] = mfilt[1] = ~0; } @@ -2043,11 +2318,163 @@ */ if (ic->ic_opmode == IEEE80211_M_HOSTAP) sc->sc_updateslot = UPDATE; - else + else if (ifp->if_flags & IFF_RUNNING) ath_setslottime(sc); } /* + * Dynamic turbo support. + * XXX much of this could be moved up to the net80211 layer. + */ + +/* + * Configure dynamic turbo state on beacon setup. + */ +static void +ath_beacon_dturbo_config(struct ath_softc *sc, u_int32_t intval) +{ +#define IS_CAPABLE(ic) \ + (ic->ic_caps & IEEE80211_C_TURBOP) + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_opmode == IEEE80211_M_HOSTAP && + IS_CAPABLE(ic) && IEEE80211_IS_CHAN_DTURBO(ic->ic_bsschan)) { + /* Dynamic Turbo is supported on this channel. */ + sc->sc_dturbo = 1; + sc->sc_dt_tcount = 0; + sc->sc_dt_switch = 0; + sc->sc_ignore_ar = 0; + + /* Set the initial ATHC_BOOST capability. */ + if (ic->ic_bsschan->ic_flags & CHANNEL_TURBO) + ic->ic_flags |= IEEE80211_F_BOOST; + else + ic->ic_flags &= ~IEEE80211_F_BOOST; + + /* + * Calculate time & bandwidth thresholds + * + * sc_dt_base_tmin : ~70 seconds + * sc_dt_turbo_tmax : ~120 seconds + * + * NB: scale calculated values to account for staggered + * beacon handling + */ + sc->sc_dt_base_tmin = 70 * 1024 * ATH_BCBUF / intval; + sc->sc_dt_turbo_tmax = 120 * 1024 * ATH_BCBUF / intval; + sc->sc_dt_base_bw = 0; /* XXX: TBD */ + sc->sc_dt_turbo_bw = 0; /* XXX: TBD */ + } else { + sc->sc_dturbo = 0; + ic->ic_flags &= ~IEEE80211_F_BOOST; + } +#undef IS_CAPABLE +} + +/* + * Update dynamic turbo state at SWBA. We assume we care + * called only if dynamic turbo has been enabled (sc_turbo). >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200505070317.j473Hlmb020838>