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