PERFORCE change 76646 for review
Sam Leffler
sam at FreeBSD.org
Fri May 6 20:17:49 PDT 2005
http://perforce.freebsd.org/chv.cgi?CH=76646
Change 76646 by sam at 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) <<<
More information about the p4-projects
mailing list