Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Mar 2009 21:53:28 +0000 (UTC)
From:      Sam Leffler <sam@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r190579 - in head/sys: arm/conf dev/ath dev/ipw dev/iwi dev/iwn dev/malo dev/ral dev/usb/wlan dev/wi dev/wpi net80211
Message-ID:  <200903302153.n2ULrSxx079540@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sam
Date: Mon Mar 30 21:53:27 2009
New Revision: 190579
URL: http://svn.freebsd.org/changeset/base/190579

Log:
  Hoist 802.11 encapsulation up into net80211:
  o call ieee80211_encap in ieee80211_start so frames passed down to drivers
    are already encapsulated
  o remove ieee80211_encap calls in drivers
  o fixup wi so it recreates the 802.3 head it requires from the 802.11
    header contents
  o move fast-frame aggregation from ath to net80211 (conditional on
    IEEE80211_SUPPORT_SUPERG):
    - aggregation is now done in ieee80211_start; it is enabled when the
      packets/sec exceeds ieee80211_ffppsmin (net.wlan.ffppsmin) and frames
      are held on a staging queue according to ieee80211_ffagemax
      (net.wlan.ffagemax) to wait for a frame to combine with
    - drivers must call back to age/flush the staging queue (ath does this
      on tx done, at swba, and on rx according to the state of the tx queues
      and/or the contents of the staging queue)
    - remove fast-frame-related data structures from ath
    - add ieee80211_ff_node_init and ieee80211_ff_node_cleanup to handle
      per-node fast-frames state (we reuse 11n tx ampdu state)
  o change ieee80211_encap calling convention to include an explicit vap
    so frames coming through a WDS vap are recognized w/o setting M_WDS
  
  With these changes any device able to tx/rx 3Kbyte+ frames can use fast-frames.
  
  Reviewed by:	thompsa, rpaulo, avatar, imp, sephe

Modified:
  head/sys/arm/conf/AVILA
  head/sys/dev/ath/if_ath.c
  head/sys/dev/ath/if_athvar.h
  head/sys/dev/ipw/if_ipw.c
  head/sys/dev/iwi/if_iwi.c
  head/sys/dev/iwn/if_iwn.c
  head/sys/dev/malo/if_malo.c
  head/sys/dev/ral/rt2560.c
  head/sys/dev/ral/rt2661.c
  head/sys/dev/usb/wlan/if_rum.c
  head/sys/dev/usb/wlan/if_ural.c
  head/sys/dev/usb/wlan/if_zyd.c
  head/sys/dev/wi/if_wi.c
  head/sys/dev/wpi/if_wpi.c
  head/sys/net80211/ieee80211_freebsd.c
  head/sys/net80211/ieee80211_hostap.c
  head/sys/net80211/ieee80211_ioctl.h
  head/sys/net80211/ieee80211_node.c
  head/sys/net80211/ieee80211_output.c
  head/sys/net80211/ieee80211_proto.h
  head/sys/net80211/ieee80211_sta.c
  head/sys/net80211/ieee80211_superg.c
  head/sys/net80211/ieee80211_superg.h
  head/sys/net80211/ieee80211_var.h

Modified: head/sys/arm/conf/AVILA
==============================================================================
--- head/sys/arm/conf/AVILA	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/arm/conf/AVILA	Mon Mar 30 21:53:27 2009	(r190579)
@@ -51,6 +51,7 @@ options 	FFS			#Berkeley Fast Filesystem
 options 	SOFTUPDATES		#Enable FFS soft updates support
 options 	NFSCLIENT		#Network Filesystem Client
 options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+options		NFS_LEGACYRPC
 options 	BOOTP
 options 	BOOTP_NFSROOT
 options 	BOOTP_NFSV3

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/ath/if_ath.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -71,6 +71,9 @@ __FBSDID("$FreeBSD$");
 
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
 #ifdef IEEE80211_SUPPORT_TDMA
 #include <net80211/ieee80211_tdma.h>
 #endif
@@ -1293,7 +1296,17 @@ ath_intr(void *arg)
 					sc->sc_tdmaswba--;
 			} else
 #endif
+			{
 				ath_beacon_proc(sc, 0);
+#ifdef IEEE80211_SUPPORT_SUPERG
+				/*
+				 * Schedule the rx taskq in case there's no
+				 * traffic so any frames held on the staging
+				 * queue are aged and potentially flushed.
+				 */
+				taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+#endif
+			}
 		}
 		if (status & HAL_INT_RXEOL) {
 			/*
@@ -1662,320 +1675,6 @@ ath_reset_vap(struct ieee80211vap *vap, 
 	return ath_reset(ifp);
 }
 
-static int 
-ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
-{
-	return 0;
-}
-
-#if 0
-static int 
-ath_ff_ageflushtestdone(struct ath_txq *txq, struct ath_buf *bf)
-{
-	return (txq->axq_curage - bf->bf_age) < ATH_FF_STAGEMAX;
-}
-#endif
-
-/*
- * Flush FF staging queue.
- */
-static void
-ath_ff_stageq_flush(struct ath_softc *sc, struct ath_txq *txq,
-	int (*ath_ff_flushdonetest)(struct ath_txq *txq, struct ath_buf *bf))
-{
-	struct ath_buf *bf;
-	struct ieee80211_node *ni;
-	int pktlen, pri;
-	
-	for (;;) {
-		ATH_TXQ_LOCK(txq);
-		/*
-		 * Go from the back (oldest) to front so we can
-		 * stop early based on the age of the entry.
-		 */
-		bf = TAILQ_LAST(&txq->axq_stageq, axq_headtype);
-		if (bf == NULL || ath_ff_flushdonetest(txq, bf)) {
-			ATH_TXQ_UNLOCK(txq);
-			break;
-		}
-
-		ni = bf->bf_node;
-		pri = M_WME_GETAC(bf->bf_m);
-		KASSERT(ATH_NODE(ni)->an_ff_buf[pri],
-			("no bf on staging queue %p", bf));
-		ATH_NODE(ni)->an_ff_buf[pri] = NULL;
-		TAILQ_REMOVE(&txq->axq_stageq, bf, bf_stagelist);
-		
-		ATH_TXQ_UNLOCK(txq);
-
-		DPRINTF(sc, ATH_DEBUG_FF, "%s: flush frame, age %u\n",
-			__func__, bf->bf_age);
-
-		sc->sc_stats.ast_ff_flush++;
-		
-		/* encap and xmit */
-		bf->bf_m = ieee80211_encap(ni, bf->bf_m);
-		if (bf->bf_m == NULL) {
-			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
-				"%s: discard, encapsulation failure\n",
-				__func__);
-			sc->sc_stats.ast_tx_encap++;
-			goto bad;
-		}
-		pktlen = bf->bf_m->m_pkthdr.len; /* NB: don't reference below */
-		if (ath_tx_start(sc, ni, bf, bf->bf_m) == 0) {
-#if 0 /*XXX*/
-			ifp->if_opackets++;
-#endif
-			continue;
-		}
-	bad:
-		if (ni != NULL)
-			ieee80211_free_node(ni);
-		bf->bf_node = NULL;
-		if (bf->bf_m != NULL) {
-			m_freem(bf->bf_m);
-			bf->bf_m = NULL;
-		}
-
-		ATH_TXBUF_LOCK(sc);
-		STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
-		ATH_TXBUF_UNLOCK(sc);
-	}
-}
-
-static __inline u_int32_t
-ath_ff_approx_txtime(struct ath_softc *sc, struct ath_node *an, struct mbuf *m)
-{
-	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
-	u_int32_t framelen;
-	struct ath_buf *bf;
-
-	/*
-	 * Approximate the frame length to be transmitted. A swag to add
-	 * the following maximal values to the skb payload:
-	 *   - 32: 802.11 encap + CRC
-	 *   - 24: encryption overhead (if wep bit)
-	 *   - 4 + 6: fast-frame header and padding
-	 *   - 16: 2 LLC FF tunnel headers
-	 *   - 14: 1 802.3 FF tunnel header (skb already accounts for 2nd)
-	 */
-	framelen = m->m_pkthdr.len + 32 + 4 + 6 + 16 + 14;
-	if (ic->ic_flags & IEEE80211_F_PRIVACY)
-		framelen += 24;
-	bf = an->an_ff_buf[M_WME_GETAC(m)];
-	if (bf != NULL)
-		framelen += bf->bf_m->m_pkthdr.len;
-	return ath_hal_computetxtime(sc->sc_ah, sc->sc_currates, framelen,
-			sc->sc_lastdatarix, AH_FALSE);
-}
-
-/*
- * Determine if a data frame may be aggregated via ff tunnelling.
- * Note the caller is responsible for checking if the destination
- * supports fast frames.
- *
- *  NB: allowing EAPOL frames to be aggregated with other unicast traffic.
- *      Do 802.1x EAPOL frames proceed in the clear? Then they couldn't
- *      be aggregated with other types of frames when encryption is on?
- *
- *  NB: assumes lock on an_ff_buf effectively held by txq lock mechanism.
- */
-static __inline int 
-ath_ff_can_aggregate(struct ath_softc *sc,
-	struct ath_node *an, struct mbuf *m, int *flushq)
-{
-	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
-	struct ath_txq *txq;
-	u_int32_t txoplimit;
-	u_int pri;
-
-	*flushq = 0;
-
-	/*
-	 * If there is no frame to combine with and the txq has
-	 * fewer frames than the minimum required; then do not
-	 * attempt to aggregate this frame.
-	 */
-	pri = M_WME_GETAC(m);
-	txq = sc->sc_ac2q[pri];
-	if (an->an_ff_buf[pri] == NULL && txq->axq_depth < sc->sc_fftxqmin)
-		return 0;
-	/*
-	 * When not in station mode never aggregate a multicast
-	 * frame; this insures, for example, that a combined frame
-	 * does not require multiple encryption keys when using
-	 * 802.1x/WPA.
-	 */
-	if (ic->ic_opmode != IEEE80211_M_STA &&
-	    ETHER_IS_MULTICAST(mtod(m, struct ether_header *)->ether_dhost))
-		return 0;		
-	/*
-	 * Consult the max bursting interval to insure a combined
-	 * frame fits within the TxOp window.
-	 */
-	txoplimit = IEEE80211_TXOP_TO_US(
-		ic->ic_wme.wme_chanParams.cap_wmeParams[pri].wmep_txopLimit);
-	if (txoplimit != 0 && ath_ff_approx_txtime(sc, an, m) > txoplimit) {
-		DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
-			"%s: FF TxOp violation\n", __func__);
-		if (an->an_ff_buf[pri] != NULL)
-			*flushq = 1;
-		return 0;
-	}
-	return 1;		/* try to aggregate */
-}
-
-/*
- * Check if the supplied frame can be partnered with an existing
- * or pending frame.  Return a reference to any frame that should be
- * sent on return; otherwise return NULL.
- */
-static struct mbuf *
-ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
-	struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
-{
-	struct ath_node *an = ATH_NODE(ni);
-	struct ath_buf *bfstaged;
-	int ff_flush, pri;
-
-	/*
-	 * Check if the supplied frame can be aggregated.
-	 *
-	 * NB: we use the txq lock to protect references to
-	 *     an->an_ff_txbuf in ath_ff_can_aggregate().
-	 */
-	ATH_TXQ_LOCK(txq);
-	pri = M_WME_GETAC(m);
-	if (ath_ff_can_aggregate(sc, an, m, &ff_flush)) {
-		struct ath_buf *bfstaged = an->an_ff_buf[pri];
-		if (bfstaged != NULL) {
-			/*
-			 * A frame is available for partnering; remove
-			 * it, chain it to this one, and encapsulate.
-			 */
-			an->an_ff_buf[pri] = NULL;
-			TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
-			ATH_TXQ_UNLOCK(txq);
-
-			/* 
-			 * Chain mbufs and add FF magic.
-			 */
-			DPRINTF(sc, ATH_DEBUG_FF,
-				"[%s] aggregate fast-frame, age %u\n",
-				ether_sprintf(ni->ni_macaddr), txq->axq_curage);
-			m->m_nextpkt = NULL;
-			bfstaged->bf_m->m_nextpkt = m;
-			m = bfstaged->bf_m;
-			bfstaged->bf_m = NULL;
-			m->m_flags |= M_FF;
-			/*
-			 * Release the node reference held while
-			 * the packet sat on an_ff_buf[]
-			 */
-			bfstaged->bf_node = NULL;
-			ieee80211_free_node(ni);
-
-			/*
-			 * Return bfstaged to the free list.
-			 */
-			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bfstaged, bf_list);
-			ATH_TXBUF_UNLOCK(sc);
-
-			return m;		/* ready to go */
-		} else {
-			/*
-			 * No frame available, queue this frame to wait
-			 * for a partner.  Note that we hold the buffer
-			 * and a reference to the node; we need the
-			 * buffer in particular so we're certain we
-			 * can flush the frame at a later time.
-			 */
-			DPRINTF(sc, ATH_DEBUG_FF,
-				"[%s] stage fast-frame, age %u\n",
-				ether_sprintf(ni->ni_macaddr), txq->axq_curage);
-
-			bf->bf_m = m;
-			bf->bf_node = ni;	/* NB: held reference */
-			bf->bf_age = txq->axq_curage;
-			an->an_ff_buf[pri] = bf;
-			TAILQ_INSERT_HEAD(&txq->axq_stageq, bf, bf_stagelist);
-			ATH_TXQ_UNLOCK(txq);
-
-			return NULL;		/* consumed */
-		}
-	}
-	/*
-	 * Frame could not be aggregated, it needs to be returned
-	 * to the caller for immediate transmission.  In addition
-	 * we check if we should first flush a frame from the
-	 * staging queue before sending this one.
-	 *
-	 * NB: ath_ff_can_aggregate only marks ff_flush if a frame
-	 *     is present to flush.
-	 */
-	if (ff_flush) {
-		int pktlen;
-
-		bfstaged = an->an_ff_buf[pri];
-		an->an_ff_buf[pri] = NULL;
-		TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
-		ATH_TXQ_UNLOCK(txq);
-
-		DPRINTF(sc, ATH_DEBUG_FF, "[%s] flush staged frame\n",
-			ether_sprintf(an->an_node.ni_macaddr));
-
-		/* encap and xmit */
-		bfstaged->bf_m = ieee80211_encap(ni, bfstaged->bf_m);
-		if (bfstaged->bf_m == NULL) {
-			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
-				"%s: discard, encap failure\n", __func__);
-			sc->sc_stats.ast_tx_encap++;
-			goto ff_flushbad;
-		}
-		pktlen = bfstaged->bf_m->m_pkthdr.len;
-		if (ath_tx_start(sc, ni, bfstaged, bfstaged->bf_m)) {
-			DPRINTF(sc, ATH_DEBUG_XMIT,
-				"%s: discard, xmit failure\n", __func__);
-	ff_flushbad:
-			/*
-			 * Unable to transmit frame that was on the staging
-			 * queue.  Reclaim the node reference and other
-			 * resources.
-			 */
-			if (ni != NULL)
-				ieee80211_free_node(ni);
-			bfstaged->bf_node = NULL;
-			if (bfstaged->bf_m != NULL) {
-				m_freem(bfstaged->bf_m);
-				bfstaged->bf_m = NULL;
-			}
-
-			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bfstaged, bf_list);
-			ATH_TXBUF_UNLOCK(sc);
-		} else {
-#if 0
-			ifp->if_opackets++;
-#endif
-		}
-	} else {
-		if (an->an_ff_buf[pri] != NULL) {
-			/* 
-			 * XXX: out-of-order condition only occurs for AP
-			 * mode and multicast.  There may be no valid way
-			 * to get this condition.
-			 */
-			DPRINTF(sc, ATH_DEBUG_FF, "[%s] out-of-order frame\n",
-				ether_sprintf(an->an_node.ni_macaddr));
-			/* XXX stat */
-		}
-		ATH_TXQ_UNLOCK(txq);
-	}
-	return m;
-}
-
 static struct ath_buf *
 _ath_getbuf_locked(struct ath_softc *sc)
 {
@@ -2070,9 +1769,7 @@ ath_start(struct ifnet *ifp)
 	struct ieee80211_node *ni;
 	struct ath_buf *bf;
 	struct mbuf *m, *next;
-	struct ath_txq *txq;
 	ath_bufhead frags;
-	int pri;
 
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
 		return;
@@ -2091,47 +1788,14 @@ ath_start(struct ifnet *ifp)
 			ATH_TXBUF_UNLOCK(sc);
 			break;
 		}
-		STAILQ_INIT(&frags);
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		pri = M_WME_GETAC(m);
-		txq = sc->sc_ac2q[pri];
-		if (IEEE80211_ATH_CAP(ni->ni_vap, ni, IEEE80211_NODE_FF)) {
-			/*
-			 * Check queue length; if too deep drop this
-			 * frame (tail drop considered good).
-			 */
-			if (txq->axq_depth >= sc->sc_fftxqmax) {
-				DPRINTF(sc, ATH_DEBUG_FF,
-				    "[%s] tail drop on q %u depth %u\n",
-				    ether_sprintf(ni->ni_macaddr),
-				    txq->axq_qnum, txq->axq_depth);
-				sc->sc_stats.ast_tx_qfull++;
-				m_freem(m);
-				goto reclaim;
-			}
-			m = ath_ff_check(sc, txq, bf, m, ni);
-			if (m == NULL) {
-				/* NB: ni ref & bf held on stageq */
-				continue;
-			}
-		}
-		ifp->if_opackets++;
-		/*
-		 * Encapsulate the packet in prep for transmission.
-		 */
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			DPRINTF(sc, ATH_DEBUG_XMIT,
-			    "%s: encapsulation failure\n", __func__);
-			sc->sc_stats.ast_tx_encap++;
-			goto bad;
-		}
 		/*
 		 * Check for fragmentation.  If this frame
 		 * has been broken up verify we have enough
 		 * buffers to send all the fragments so all
 		 * go out or none...
 		 */
+		STAILQ_INIT(&frags);
 		if ((m->m_flags & M_FRAG) && 
 		    !ath_txfrag_setup(sc, &frags, m, ni)) {
 			DPRINTF(sc, ATH_DEBUG_XMIT,
@@ -2140,6 +1804,7 @@ ath_start(struct ifnet *ifp)
 			ath_freetx(m);
 			goto bad;
 		}
+		ifp->if_opackets++;
 	nextfrag:
 		/*
 		 * Pass the frame to the h/w for transmission.
@@ -2189,13 +1854,6 @@ ath_start(struct ifnet *ifp)
 		}
 
 		sc->sc_wd_timer = 5;
-#if 0
-		/*
-		 * Flush stale frames from the fast-frame staging queue.
-		 */
-		if (ic->ic_opmode != IEEE80211_M_STA)
-			ath_ff_stageq_flush(sc, txq, ath_ff_ageflushtestdone);
-#endif
 	}
 }
 
@@ -4335,10 +3993,18 @@ rx_next:
 	if (ngood)
 		sc->sc_lastrx = tsf;
 
-	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 &&
-	    !IFQ_IS_EMPTY(&ifp->if_snd))
-		ath_start(ifp);
-
+	if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
+#ifdef IEEE80211_SUPPORT_SUPERG
+		if (ic->ic_stageqdepth) {
+			ieee80211_age_stageq(ic, WME_AC_VO, 100);
+			ieee80211_age_stageq(ic, WME_AC_VI, 100);
+			ieee80211_age_stageq(ic, WME_AC_BE, 100);
+			ieee80211_age_stageq(ic, WME_AC_BK, 100);
+		}
+#endif
+		if (!IFQ_IS_EMPTY(&ifp->if_snd))
+			ath_start(ifp);
+	}
 #undef PA2DESC
 }
 
@@ -4346,13 +4012,12 @@ static void
 ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
 {
 	txq->axq_qnum = qnum;
+	txq->axq_ac = 0;
 	txq->axq_depth = 0;
 	txq->axq_intrcnt = 0;
 	txq->axq_link = NULL;
 	STAILQ_INIT(&txq->axq_q);
 	ATH_TXQ_LOCK_INIT(sc, txq);
-	TAILQ_INIT(&txq->axq_stageq);
-	txq->axq_curage = 0;
 }
 
 /*
@@ -4429,6 +4094,7 @@ ath_tx_setup(struct ath_softc *sc, int a
 	}
 	txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype);
 	if (txq != NULL) {
+		txq->axq_ac = ac;
 		sc->sc_ac2q[ac] = txq;
 		return 1;
 	} else
@@ -5292,13 +4958,6 @@ ath_tx_processq(struct ath_softc *sc, st
 				ieee80211_process_callback(ni, bf->bf_m,
 				    (bf->bf_txflags & HAL_TXDESC_NOACK) == 0 ?
 				        ts->ts_status : HAL_TXERR_XRETRY);
-			/*
-			 * Reclaim reference to node.
-			 *
-			 * NB: the node may be reclaimed here if, for example
-			 *     this is a DEAUTH message that was sent and the
-			 *     node was timed out due to inactivity.
-			 */
 			ieee80211_free_node(ni);
 		}
 		bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
@@ -5316,11 +4975,13 @@ ath_tx_processq(struct ath_softc *sc, st
 		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
 		ATH_TXBUF_UNLOCK(sc);
 	}
+#ifdef IEEE80211_SUPPORT_SUPERG
 	/*
 	 * Flush fast-frame staging queue when traffic slows.
 	 */
 	if (txq->axq_depth <= 1)
-		ath_ff_stageq_flush(sc, txq, ath_ff_always);
+		ieee80211_flush_stageq(ic, txq->axq_ac);
+#endif
 	return nacked;
 }
 
@@ -6920,16 +6581,6 @@ ath_sysctlattach(struct ath_softc *sc)
 			"tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
 			ath_sysctl_tpcts, "I", "tx power for cts frames");
 	}
-	if (ath_hal_hasfastframes(sc->sc_ah)) {
-		sc->sc_fftxqmin = ATH_FF_TXQMIN;
-		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-			"fftxqmin", CTLFLAG_RW, &sc->sc_fftxqmin, 0,
-			"min frames before fast-frame staging");
-		sc->sc_fftxqmax = ATH_FF_TXQMAX;
-		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-			"fftxqmax", CTLFLAG_RW, &sc->sc_fftxqmax, 0,
-			"max queued frames before tail drop");
-	}
 	if (ath_hal_hasrfsilent(ah)) {
 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 			"rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0,

Modified: head/sys/dev/ath/if_athvar.h
==============================================================================
--- head/sys/dev/ath/if_athvar.h	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/ath/if_athvar.h	Mon Mar 30 21:53:27 2009	(r190579)
@@ -71,10 +71,6 @@
 #define	ATH_KEYMAX	128		/* max key cache size we handle */
 #define	ATH_KEYBYTES	(ATH_KEYMAX/NBBY)	/* storage space in bytes */
 
-#define	ATH_FF_TXQMIN	2		/* min txq depth for staging */
-#define	ATH_FF_TXQMAX	50		/* maximum # of queued frames allowed */
-#define	ATH_FF_STAGEMAX	5		/* max waiting period for staged frame*/
-
 struct taskqueue;
 struct kthread;
 struct ath_buf;
@@ -106,8 +102,6 @@ struct ath_node {
 
 struct ath_buf {
 	STAILQ_ENTRY(ath_buf)	bf_list;
-	TAILQ_ENTRY(ath_buf)	bf_stagelist;	/* stage queue list */
-	u_int32_t		bf_age;		/* age when placed on stageq */
 	int			bf_nseg;
 	uint16_t		bf_txflags;	/* tx descriptor flags */
 	uint16_t		bf_flags;	/* status flags (below) */
@@ -151,6 +145,7 @@ struct ath_descdma {
 struct ath_txq {
 	u_int			axq_qnum;	/* hardware q number */
 #define	ATH_TXQ_SWQ	(HAL_NUM_TX_QUEUES+1)	/* qnum for s/w only queue */
+	u_int			axq_ac;		/* WME AC */
 	u_int			axq_flags;
 #define	ATH_TXQ_PUTPENDING	0x0001		/* ath_hal_puttxbuf pending */
 	u_int			axq_depth;	/* queue depth (stat only) */
@@ -159,13 +154,6 @@ struct ath_txq {
 	STAILQ_HEAD(, ath_buf)	axq_q;		/* transmit queue */
 	struct mtx		axq_lock;	/* lock on q and link */
 	char			axq_name[12];	/* e.g. "ath0_txq4" */
-	/*
-	 * Fast-frame state.  The staging queue holds awaiting
-	 * a fast-frame pairing.  Buffers on this queue are
-	 * assigned an ``age'' and flushed when they wait too long.
-	 */
-	TAILQ_HEAD(axq_headtype, ath_buf) axq_stageq;
-	u_int32_t		axq_curage;	/* queue age */
 };
 
 #define	ATH_TXQ_LOCK_INIT(_sc, _tq) do { \
@@ -181,7 +169,6 @@ struct ath_txq {
 #define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
 	STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
 	(_tq)->axq_depth++; \
-	(_tq)->axq_curage++; \
 } while (0)
 #define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
 	STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \

Modified: head/sys/dev/ipw/if_ipw.c
==============================================================================
--- head/sys/dev/ipw/if_ipw.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/ipw/if_ipw.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1795,11 +1795,6 @@ ipw_start_locked(struct ifnet *ifp)
 			break;
 		}
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			continue;
-		}
 		if (ipw_tx_start(ifp, m, ni) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/iwi/if_iwi.c
==============================================================================
--- head/sys/dev/iwi/if_iwi.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/iwi/if_iwi.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1982,13 +1982,6 @@ iwi_start_locked(struct ifnet *ifp)
 		BPF_MTAP(ifp, m);
 
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
-
 		if (iwi_tx_start(ifp, m, ni, ac) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/iwn/if_iwn.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -2122,12 +2122,6 @@ iwn_start_locked(struct ifnet *ifp)
 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
 		pri = M_WME_GETAC(m);
 		txq = &sc->txq[pri];
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ifp->if_oerrors++;
-			ieee80211_free_node(ni);
-			continue;
-		}
 		if (txq->queued >= IWN_TX_RING_COUNT - 8) {
 			/* XXX not right */
 			/* ring is nearly full, stop flow */

Modified: head/sys/dev/malo/if_malo.c
==============================================================================
--- head/sys/dev/malo/if_malo.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/malo/if_malo.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1290,20 +1290,9 @@ malo_start(struct ifnet *ifp)
 			break;
 		}
 		/*
-		 * Encapsulate the packet in prep for transmission.
-		 */
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			DPRINTF(sc, MALO_DEBUG_XMIT,
-			    "%s: encapsulation failure\n", __func__);
-			sc->malo_stats.mst_tx_encap++;
-			goto bad;
-		}
-		/*
 		 * Pass the frame to the h/w for transmission.
 		 */
 		if (malo_tx_start(sc, ni, bf, m)) {
-	bad:
 			ifp->if_oerrors++;
 			if (bf != NULL) {
 				bf->bf_m = NULL;

Modified: head/sys/dev/ral/rt2560.c
==============================================================================
--- head/sys/dev/ral/rt2560.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/ral/rt2560.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1963,15 +1963,7 @@ rt2560_start_locked(struct ifnet *ifp)
 			sc->sc_flags |= RT2560_F_DATA_OACTIVE;
 			break;
 		}
-
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
-
 		if (rt2560_tx_data(sc, m, ni) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/ral/rt2661.c
==============================================================================
--- head/sys/dev/ral/rt2661.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/ral/rt2661.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1660,15 +1660,7 @@ rt2661_start_locked(struct ifnet *ifp)
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;
 		}
-
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
-
 		if (rt2661_tx_data(sc, m, ni, ac) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/usb/wlan/if_rum.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rum.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/usb/wlan/if_rum.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1354,12 +1354,6 @@ rum_start(struct ifnet *ifp)
 			break;
 		}
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
 		if (rum_tx_data(sc, m, ni) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/usb/wlan/if_ural.c
==============================================================================
--- head/sys/dev/usb/wlan/if_ural.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/usb/wlan/if_ural.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1436,12 +1436,6 @@ ural_start(struct ifnet *ifp)
 			break;
 		}
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
 		if (ural_tx_data(sc, m, ni) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/usb/wlan/if_zyd.c
==============================================================================
--- head/sys/dev/usb/wlan/if_zyd.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/usb/wlan/if_zyd.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -2697,12 +2697,6 @@ zyd_start(struct ifnet *ifp)
 			break;
 		}
 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
 		if (zyd_tx_data(sc, m, ni) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/dev/wi/if_wi.c
==============================================================================
--- head/sys/dev/wi/if_wi.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/wi/if_wi.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$");
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
+#include <net/if_llc.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
 
@@ -978,6 +979,7 @@ wi_start_locked(struct ifnet *ifp)
 	struct mbuf *m0;
 	struct ieee80211_key *k;
 	struct wi_frame frmhdr;
+	const struct llc *llc;
 	int cur;
 
 	WI_LOCK_ASSERT(sc);
@@ -996,19 +998,33 @@ wi_start_locked(struct ifnet *ifp)
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;
 		}
-		/* NB: copy before 802.11 header is prepended */
-		m_copydata(m0, 0, ETHER_HDR_LEN, 
-		    (caddr_t)&frmhdr.wi_ehdr);
-
 		ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif;
-		m0 = ieee80211_encap(ni, m0);
-		if (m0 == NULL) {
-			ifp->if_oerrors++;
-			ieee80211_free_node(ni);
-			continue;
-		}
 
+		/* reconstruct 802.3 header */
 		wh = mtod(m0, struct ieee80211_frame *);
+		switch (wh->i_fc[1]) {
+		case IEEE80211_FC1_DIR_TODS:
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_shost,
+			    wh->i_addr2);
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_dhost,
+			    wh->i_addr3);
+			break;
+		case IEEE80211_FC1_DIR_NODS:
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_shost,
+			    wh->i_addr2);
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_dhost,
+			    wh->i_addr1);
+			break;
+		case IEEE80211_FC1_DIR_FROMDS:
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_shost,
+			    wh->i_addr3);
+			IEEE80211_ADDR_COPY(frmhdr.wi_ehdr.ether_dhost,
+			    wh->i_addr1);
+			break;
+		}
+		llc = (const struct llc *)(
+		    mtod(m0, const uint8_t *) + ieee80211_hdrsize(wh));
+		frmhdr.wi_ehdr.ether_type = llc->llc_snap.ether_type;
 		frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
 			k = ieee80211_crypto_encap(ni, m0);

Modified: head/sys/dev/wpi/if_wpi.c
==============================================================================
--- head/sys/dev/wpi/if_wpi.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/dev/wpi/if_wpi.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -2048,7 +2048,6 @@ wpi_start_locked(struct ifnet *ifp)
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL)
 			break;
-		/* no QoS encapsulation for EAPOL frames */
 		ac = M_WME_GETAC(m);
 		if (sc->txq[ac].queued > sc->txq[ac].count - 8) {
 			/* there is no place left in this ring */
@@ -2057,12 +2056,6 @@ wpi_start_locked(struct ifnet *ifp)
 			break;
 		}
 		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-		m = ieee80211_encap(ni, m);
-		if (m == NULL) {
-			ieee80211_free_node(ni);
-			ifp->if_oerrors++;
-			continue;
-		}
 		if (wpi_tx_data(sc, m, ni, ac) != 0) {
 			ieee80211_free_node(ni);
 			ifp->if_oerrors++;

Modified: head/sys/net80211/ieee80211_freebsd.c
==============================================================================
--- head/sys/net80211/ieee80211_freebsd.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_freebsd.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -189,6 +189,15 @@ SYSCTL_PROC(_net_wlan, OID_AUTO, addba_b
 extern int ieee80211_addba_maxtries;
 SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW,
 	&ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
+#ifdef IEEE80211_SUPPORT_SUPERG
+extern int ieee80211_ffppsmin;
+SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLFLAG_RW,
+	&ieee80211_ffppsmin, 0, "min packet rate before fast-frame staging");
+extern int ieee80211_ffagemax;
+SYSCTL_PROC(_net_wlan, OID_AUTO, ffagemax, CTLFLAG_RW,
+	&ieee80211_ffagemax, 0, ieee80211_sysctl_msecs_ticks, "I",
+	"max hold time for fast-frame staging (ms)");
+#endif /* IEEE80211_SUPPORT_SUPERG */
 
 static int
 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)

Modified: head/sys/net80211/ieee80211_hostap.c
==============================================================================
--- head/sys/net80211/ieee80211_hostap.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_hostap.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -2038,6 +2038,10 @@ hostap_recv_mgmt(struct ieee80211_node *
 			ieee80211_ht_updatehtcap(ni, htcap);
 		} else if (ni->ni_flags & IEEE80211_NODE_HT)
 			ieee80211_ht_node_cleanup(ni);
+#ifdef IEEE80211_SUPPORT_SUPERG
+		else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
+			ieee80211_ff_node_cleanup(ni);
+#endif
 		/*
 		 * Allow AMPDU operation only with unencrypted traffic
 		 * or AES-CCM; the 11n spec only specifies these ciphers

Modified: head/sys/net80211/ieee80211_ioctl.h
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.h	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_ioctl.h	Mon Mar 30 21:53:27 2009	(r190579)
@@ -217,7 +217,8 @@ struct ieee80211_stats {
 	uint8_t		is_rx_authfail_code;	/* last rx'd auth fail reason */
 	uint32_t	is_beacon_miss;		/* beacon miss notification */
 	uint32_t	is_rx_badstate;		/* rx discard state != RUN */
-	uint32_t	is_spare[12];
+	uint32_t	is_ff_flush;		/* ff's flush'd from stageq */
+	uint32_t	is_spare[11];
 };
 
 /*

Modified: head/sys/net80211/ieee80211_node.c
==============================================================================
--- head/sys/net80211/ieee80211_node.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_node.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -929,6 +929,10 @@ node_cleanup(struct ieee80211_node *ni)
 	 */
 	if (ni->ni_flags & IEEE80211_NODE_HT)
 		ieee80211_ht_node_cleanup(ni);
+#ifdef IEEE80211_SUPPORT_SUPERG
+	else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
+		ieee80211_ff_node_cleanup(ni);
+#endif
 	/*
 	 * Clear AREF flag that marks the authorization refcnt bump
 	 * has happened.  This is probably not needed as the node

Modified: head/sys/net80211/ieee80211_output.c
==============================================================================
--- head/sys/net80211/ieee80211_output.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_output.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -217,6 +217,7 @@ ieee80211_start(struct ifnet *ifp)
 			ieee80211_free_node(ni);
 			continue;
 		}
+
 		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
 		    (m->m_flags & M_PWR_SAV) == 0) {
 			/*
@@ -241,23 +242,26 @@ ieee80211_start(struct ifnet *ifp)
 			continue;
 		}
 
-		BPF_MTAP(ifp, m);		/* 802.11 tx path */
-
+		BPF_MTAP(ifp, m);		/* 802.3 tx */
+ 
+#ifdef IEEE80211_SUPPORT_SUPERG
+		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) {
+			m = ieee80211_ff_check(ni, m);
+			if (m == NULL) {
+				/* NB: any ni ref held on stageq */
+				continue;
+			}
+		}
+#endif /* IEEE80211_SUPPORT_SUPERG */
 		/*
-		 * XXX When ni is associated with a WDS link then
-		 * the vap will be the WDS vap but ni_vap will point
-		 * to the ap vap the station associated to.  Once
-		 * we handoff the packet to the driver the callback
-		 * to ieee80211_encap won't be able to tell if the
-		 * packet should be encapsulated for WDS or not (e.g.
-		 * multicast frames will not be handled correctly).
-		 * We hack this by marking the mbuf so ieee80211_encap
-		 * can do the right thing.
+		 * Encapsulate the packet in prep for transmission.
 		 */
-		if (vap->iv_opmode == IEEE80211_M_WDS)
-			m->m_flags |= M_WDS;
-		else
-			m->m_flags &= ~M_WDS;
+		m = ieee80211_encap(vap, ni, m);
+		if (m == NULL) {
+			/* NB: stat+msg handled in ieee80211_encap */
+			ieee80211_free_node(ni);
+			continue;
+		}
 
 		/*
 		 * Stash the node pointer and hand the frame off to
@@ -267,7 +271,6 @@ ieee80211_start(struct ifnet *ifp)
 		 */
 		m->m_pkthdr.rcvif = (void *)ni;
 
-		/* XXX defer if_start calls? */
 		error = parent->if_transmit(parent, m);
 		if (error != 0) {
 			/* NB: IFQ_HANDOFF reclaims mbuf */
@@ -852,10 +855,10 @@ ieee80211_crypto_getmcastkey(struct ieee
  *     marked EAPOL frames w/ M_EAPOL.
  */
 struct mbuf *
-ieee80211_encap(struct ieee80211_node *ni, struct mbuf *m)
+ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
+    struct mbuf *m)
 {
 #define	WH4(wh)	((struct ieee80211_frame_addr4 *)(wh))
-	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
 	struct ether_header eh;
 	struct ieee80211_frame *wh;
@@ -955,6 +958,9 @@ ieee80211_encap(struct ieee80211_node *n
 		llc->llc_snap.ether_type = eh.ether_type;
 	} else {
 #ifdef IEEE80211_SUPPORT_SUPERG
+		/*
+		 * Aggregated frame.
+		 */
 		m = ieee80211_ff_encap(vap, m, hdrspace, key);
 		if (m == NULL)
 #endif

Modified: head/sys/net80211/ieee80211_proto.h
==============================================================================
--- head/sys/net80211/ieee80211_proto.h	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_proto.h	Mon Mar 30 21:53:27 2009	(r190579)
@@ -75,8 +75,9 @@ void	ieee80211_start(struct ifnet *);
 int	ieee80211_send_nulldata(struct ieee80211_node *);
 int	ieee80211_classify(struct ieee80211_node *, struct mbuf *m);
 struct mbuf *ieee80211_mbuf_adjust(struct ieee80211vap *, int,
-	struct ieee80211_key *, struct mbuf *);
-struct mbuf *ieee80211_encap(struct ieee80211_node *, struct mbuf *);
+		struct ieee80211_key *, struct mbuf *);
+struct mbuf *ieee80211_encap(struct ieee80211vap *, struct ieee80211_node *,
+		struct mbuf *);
 int	ieee80211_send_mgmt(struct ieee80211_node *, int, int);
 struct ieee80211_appie;
 int	ieee80211_send_probereq(struct ieee80211_node *ni,

Modified: head/sys/net80211/ieee80211_sta.c
==============================================================================
--- head/sys/net80211/ieee80211_sta.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_sta.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -1459,6 +1459,11 @@ sta_recv_mgmt(struct ieee80211_node *ni,
 			ieee80211_setup_htrates(ni, htcap,
 			     IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
 			ieee80211_setup_basic_htrates(ni, htinfo);
+		} else {
+#ifdef IEEE80211_SUPPORT_SUPERG
+			if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH))
+				ieee80211_ff_node_init(ni);
+#endif
 		}
 		/*
 		 * Configure state now that we are associated.

Modified: head/sys/net80211/ieee80211_superg.c
==============================================================================
--- head/sys/net80211/ieee80211_superg.c	Mon Mar 30 21:46:50 2009	(r190578)
+++ head/sys/net80211/ieee80211_superg.c	Mon Mar 30 21:53:27 2009	(r190579)
@@ -76,12 +76,21 @@ __FBSDID("$FreeBSD$");
 #define	ATH_FF_SNAP_ORGCODE_1	0x03
 #define	ATH_FF_SNAP_ORGCODE_2	0x7f
 
+#define	ATH_FF_TXQMIN	2		/* min txq depth for staging */
+#define	ATH_FF_TXQMAX	50		/* maximum # of queued frames allowed */
+#define	ATH_FF_STAGEMAX	5		/* max waiting period for staged frame*/
+
 #define	ETHER_HEADER_COPY(dst, src) \
 	memcpy(dst, src, sizeof(struct ether_header))
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903302153.n2ULrSxx079540>