Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Oct 2008 23:59:00 +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: r184280 - head/sys/net80211
Message-ID:  <200810252359.m9PNx0Es061051@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sam
Date: Sat Oct 25 23:58:59 2008
New Revision: 184280
URL: http://svn.freebsd.org/changeset/base/184280

Log:
  Sync BAR frame handling with out of tree work:
  o correct BAR frame construction for AMPDU
  o retransmit BAR frames until ACK'd or timeout (use tunables to
    control behaviour, default is very aggressive)
  o defer seq# update until BAR frame is ACK'd
  o add BAR response handling callback for driver to interpose and
    push new state to device or push pending aggregates
  
  While here also:
  o add backpointer to node in the per-tid tx aggregation data structure
  o move ampdu tx state setup/teardown work to separate functions

Modified:
  head/sys/net80211/ieee80211_ht.c
  head/sys/net80211/ieee80211_ht.h
  head/sys/net80211/ieee80211_var.h

Modified: head/sys/net80211/ieee80211_ht.c
==============================================================================
--- head/sys/net80211/ieee80211_ht.c	Sat Oct 25 23:44:25 2008	(r184279)
+++ head/sys/net80211/ieee80211_ht.c	Sat Oct 25 23:58:59 2008	(r184280)
@@ -86,6 +86,8 @@ int	ieee80211_recv_bar_ena = 1;
 int	ieee80211_addba_timeout = -1;	/* timeout waiting for ADDBA response */
 int	ieee80211_addba_backoff = -1;	/* backoff after max ADDBA requests */
 int	ieee80211_addba_maxtries = 3;	/* max ADDBA requests before backoff */
+int	ieee80211_bar_timeout = -1;	/* timeout waiting for BAR response */
+int	ieee80211_bar_maxtries = 50;	/* max BAR requests before DELBA */
 
 /*
  * Setup HT parameters that depends on the clock frequency.
@@ -98,6 +100,7 @@ ieee80211_ht_setup(void)
 #endif
 	ieee80211_addba_timeout = msecs_to_ticks(250);
 	ieee80211_addba_backoff = msecs_to_ticks(10*1000);
+	ieee80211_bar_timeout = msecs_to_ticks(250);
 }
 SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
 
@@ -113,6 +116,10 @@ static void ieee80211_addba_stop(struct 
 	struct ieee80211_tx_ampdu *tap);
 static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
 	const uint8_t *frm, const uint8_t *efrm);
+static void ieee80211_bar_response(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap, int status);
+static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
+static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
 
 void
 ieee80211_ht_attach(struct ieee80211com *ic)
@@ -124,6 +131,7 @@ ieee80211_ht_attach(struct ieee80211com 
 	ic->ic_addba_request = ieee80211_addba_request;
 	ic->ic_addba_response = ieee80211_addba_response;
 	ic->ic_addba_stop = ieee80211_addba_stop;
+	ic->ic_bar_response = ieee80211_bar_response;
 
 	ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
 	ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
@@ -534,7 +542,6 @@ ieee80211_ampdu_reorder(struct ieee80211
 		 */
 		return PROCESS;
 	}
-
 	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
 		tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
 	else
@@ -803,6 +810,7 @@ ieee80211_ht_node_init(struct ieee80211_
 	for (ac = 0; ac < WME_NUM_AC; ac++) {
 		tap = &ni->ni_tx_ampdu[ac];
 		tap->txa_ac = ac;
+		tap->txa_ni = ni;
 		/* NB: further initialization deferred */
 	}
 	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
@@ -815,7 +823,6 @@ ieee80211_ht_node_init(struct ieee80211_
 void
 ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
 {
-	struct ieee80211com *ic = ni->ni_ic;
 	int i;
 
 	KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
@@ -823,18 +830,8 @@ ieee80211_ht_node_cleanup(struct ieee802
 	/* XXX optimize this */
 	for (i = 0; i < WME_NUM_AC; i++) {
 		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
-		if (tap->txa_flags & IEEE80211_AGGR_SETUP) {
-			/*
-			 * Stop BA stream if setup so driver has a chance
-			 * to reclaim any resources it might have allocated.
-			 */
-			ic->ic_addba_stop(ni, &ni->ni_tx_ampdu[i]);
-			tap->txa_lastsample = 0;
-			tap->txa_avgpps = 0;
-			/* NB: clearing NAK means we may re-send ADDBA */ 
-			tap->txa_flags &=
-			    ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
-		}
+		if (tap->txa_flags & IEEE80211_AGGR_SETUP)
+			ampdu_tx_stop(tap);
 	}
 	for (i = 0; i < WME_NUM_TID; i++)
 		ampdu_rx_stop(&ni->ni_rx_ampdu[i]);
@@ -1422,6 +1419,38 @@ ieee80211_setup_basic_htrates(struct iee
 }
 
 static void
+ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
+{
+	callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
+	tap->txa_flags |= IEEE80211_AGGR_SETUP;
+}
+
+static void
+ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
+{
+	struct ieee80211_node *ni = tap->txa_ni;
+	struct ieee80211com *ic = ni->ni_ic;
+
+	KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
+	    ("txa_flags 0x%x ac %d", tap->txa_flags, tap->txa_ac));
+
+	/*
+	 * Stop BA stream if setup so driver has a chance
+	 * to reclaim any resources it might have allocated.
+	 */
+	ic->ic_addba_stop(ni, tap);
+	/*
+	 * Stop any pending BAR transmit.
+	 */
+	bar_stop_timer(tap);
+
+	tap->txa_lastsample = 0;
+	tap->txa_avgpps = 0;
+	/* NB: clearing NAK means we may re-send ADDBA */ 
+	tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
+}
+
+static void
 addba_timeout(void *arg)
 {
 	struct ieee80211_tx_ampdu *tap = arg;
@@ -1483,7 +1512,7 @@ ieee80211_addba_response(struct ieee8021
 	struct ieee80211_tx_ampdu *tap,
 	int status, int baparamset, int batimeout)
 {
-	int bufsiz;
+	int bufsiz, tid;
 
 	/* XXX locking */
 	addba_stop_timeout(tap);
@@ -1492,7 +1521,10 @@ ieee80211_addba_response(struct ieee8021
 		/* XXX override our request? */
 		tap->txa_wnd = (bufsiz == 0) ?
 		    IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
+		/* XXX AC/TID */
+		tid = MS(baparamset, IEEE80211_BAPS_TID);
 		tap->txa_flags |= IEEE80211_AGGR_RUNNING;
+		tap->txa_attempts = 0;
 	} else {
 		/* mark tid so we don't try again */
 		tap->txa_flags |= IEEE80211_AGGR_NAK;
@@ -1648,7 +1680,6 @@ ieee80211_aggr_recv_action(struct ieee80
 				return;
 			}
 #endif
-
 			IEEE80211_NOTE(vap,
 			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 			    "recv ADDBA response: dialogtoken %u code %d "
@@ -1817,8 +1848,7 @@ ieee80211_ampdu_request(struct ieee80211
 	/* XXX locking */
 	if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
 		/* do deferred setup of state */
-		callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
-		tap->txa_flags |= IEEE80211_AGGR_SETUP;
+		ampdu_tx_setup(tap);
 	}
 	/* XXX hack for not doing proper locking */
 	tap->txa_flags &= ~IEEE80211_AGGR_NAK;
@@ -1827,7 +1857,6 @@ ieee80211_ampdu_request(struct ieee80211
 	tid = WME_AC_TO_TID(tap->txa_ac);
 	tap->txa_start = ni->ni_txseqs[tid];
 
-	tid = WME_AC_TO_TID(tap->txa_ac);
 	args[0] = dialogtoken;
 	args[1]	= IEEE80211_BAPS_POLICY_IMMEDIATE
 		| SM(tid, IEEE80211_BAPS_TID)
@@ -1869,6 +1898,7 @@ ieee80211_ampdu_stop(struct ieee80211_no
 	uint16_t args[4];
 
 	/* XXX locking */
+	tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
 	if (IEEE80211_AMPDU_RUNNING(tap)) {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 		    ni, "%s: stop BA stream for AC %d (reason %d)",
@@ -1889,72 +1919,171 @@ ieee80211_ampdu_stop(struct ieee80211_no
 	}
 }
 
+static void
+bar_timeout(void *arg)
+{
+	struct ieee80211_tx_ampdu *tap = arg;
+	struct ieee80211_node *ni = tap->txa_ni;
+
+	KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
+	    ("bar/addba collision, flags 0x%x", tap->txa_flags));
+
+	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+	    ni, "%s: tid %u flags 0x%x attempts %d", __func__,
+	    tap->txa_ac, tap->txa_flags, tap->txa_attempts);
+
+	/* guard against race with bar_tx_complete */
+	if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
+		return;
+	/* XXX ? */
+	if (tap->txa_attempts >= ieee80211_bar_maxtries)
+		ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
+	else
+		ieee80211_send_bar(ni, tap, tap->txa_seqpending);
+}
+
+static void
+bar_start_timer(struct ieee80211_tx_ampdu *tap)
+{
+	callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
+}
+
+static void
+bar_stop_timer(struct ieee80211_tx_ampdu *tap)
+{
+	callout_stop(&tap->txa_timer);
+}
+
+static void
+bar_tx_complete(struct ieee80211_node *ni, void *arg, int status)
+{
+	struct ieee80211_tx_ampdu *tap = arg;
+
+	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+	    ni, "%s: tid %u flags 0x%x pending %d status %d",
+	    __func__, tap->txa_ac, tap->txa_flags,
+	    callout_pending(&tap->txa_timer), status);
+
+	/* XXX locking */
+	if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
+	    callout_pending(&tap->txa_timer)) {
+		struct ieee80211com *ic = ni->ni_ic;
+
+		if (status)		/* ACK'd */
+			bar_stop_timer(tap);
+		ic->ic_bar_response(ni, tap, status);
+		/* NB: just let timer expire so we pace requests */
+	}
+}
+
+static void
+ieee80211_bar_response(struct ieee80211_node *ni,
+	struct ieee80211_tx_ampdu *tap, int status)
+{
+
+	if (status != 0) {		/* got ACK */
+		IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
+		    ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
+		    tap->txa_start,
+		    IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
+		    tap->txa_qframes, tap->txa_seqpending,
+		    WME_AC_TO_TID(tap->txa_ac));
+
+		/* NB: timer already stopped in bar_tx_complete */
+		tap->txa_start = tap->txa_seqpending;
+		tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
+	}
+}
+
 /*
  * Transmit a BAR frame to the specified node.  The
  * BAR contents are drawn from the supplied aggregation
  * state associated with the node.
+ *
+ * NB: we only handle immediate ACK w/ compressed bitmap.
  */
 int
 ieee80211_send_bar(struct ieee80211_node *ni,
-	const struct ieee80211_tx_ampdu *tap)
+	struct ieee80211_tx_ampdu *tap, ieee80211_seq seq)
 {
 #define	senderr(_x, _v)	do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
-#define	ADDSHORT(frm, v) do {			\
-	frm[0] = (v) & 0xff;			\
-	frm[1] = (v) >> 8;			\
-	frm += 2;				\
-} while (0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
-	struct ieee80211_frame_min *wh;
+	struct ieee80211_frame_bar *bar;
 	struct mbuf *m;
-	uint8_t *frm;
 	uint16_t barctl, barseqctl;
+	uint8_t *frm;
 	int tid, ret;
 
+	if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
+		/* no ADDBA response, should not happen */
+		/* XXX stat+msg */
+		return EINVAL;
+	}
+	/* XXX locking */
+	bar_stop_timer(tap);
+
 	ieee80211_ref_node(ni);
 
-	m = ieee80211_getmgtframe(&frm,
-		ic->ic_headroom + sizeof(struct ieee80211_frame_min),
-		sizeof(struct ieee80211_ba_request)
-	);
+	m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
 	if (m == NULL)
 		senderr(ENOMEM, is_tx_nobuf);
 
-	wh = mtod(m, struct ieee80211_frame_min *);
-	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 |
+	if (!ieee80211_add_callback(m, bar_tx_complete, tap)) {
+		m_freem(m);
+		senderr(ENOMEM, is_tx_nobuf);	/* XXX */
+		/* NOTREACHED */
+	}
+
+	bar = mtod(m, struct ieee80211_frame_bar *);
+	bar->i_fc[0] = IEEE80211_FC0_VERSION_0 |
 		IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
-	wh->i_fc[1] = 0;
-	IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
-	IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
+	bar->i_fc[1] = 0;
+	IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
+	IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
 
 	tid = WME_AC_TO_TID(tap->txa_ac);
 	barctl 	= (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
-			IEEE80211_BAPS_POLICY_IMMEDIATE :
-			IEEE80211_BAPS_POLICY_DELAYED)
-		| SM(tid, IEEE80211_BAPS_TID)
-		| SM(tap->txa_wnd, IEEE80211_BAPS_BUFSIZ)
-		;
-	barseqctl = SM(tap->txa_start, IEEE80211_BASEQ_START)
-		| SM(0, IEEE80211_BASEQ_FRAG)
+			0 : IEEE80211_BAR_NOACK)
+		| IEEE80211_BAR_COMP
+		| SM(tid, IEEE80211_BAR_TID)
 		;
-	ADDSHORT(frm, barctl);
-	ADDSHORT(frm, barseqctl);
-	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
+	barseqctl = SM(seq, IEEE80211_BAR_SEQ_START);
+	/* NB: known to have proper alignment */
+	bar->i_ctl = htole16(barctl);
+	bar->i_seq = htole16(barseqctl);
+	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
 
 	M_WME_SETAC(m, WME_AC_VO);
 
 	IEEE80211_NODE_STAT(ni, tx_mgmt);	/* XXX tx_ctl? */
 
-	IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
-	    ni, "send bar frame (tid %u start %u) on channel %u",
-	    tid, tap->txa_start, ieee80211_chan2ieee(ic, ic->ic_curchan));
-
-	return ic->ic_raw_xmit(ni, m, NULL);
+	/* XXX locking */
+	/* init/bump attempts counter */
+	if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
+		tap->txa_attempts = 1;
+	else
+		tap->txa_attempts++;
+	tap->txa_seqpending = seq;
+	tap->txa_flags |= IEEE80211_AGGR_BARPEND;
+
+	IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
+	    ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)",
+	    tid, barctl, seq, tap->txa_attempts);
+
+	ret = ic->ic_raw_xmit(ni, m, NULL);
+	if (ret != 0) {
+		/* xmit failed, clear state flag */
+		tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
+		goto bad;
+	}
+	/* XXX hack against tx complete happening before timer is started */
+	if (tap->txa_flags & IEEE80211_AGGR_BARPEND)
+		bar_start_timer(tap);
+	return 0;
 bad:
 	ieee80211_free_node(ni);
 	return ret;
-#undef ADDSHORT
 #undef senderr
 }
 

Modified: head/sys/net80211/ieee80211_ht.h
==============================================================================
--- head/sys/net80211/ieee80211_ht.h	Sat Oct 25 23:44:25 2008	(r184279)
+++ head/sys/net80211/ieee80211_ht.h	Sat Oct 25 23:58:59 2008	(r184280)
@@ -38,12 +38,14 @@
 typedef uint16_t ieee80211_seq;
 
 struct ieee80211_tx_ampdu {
+	struct ieee80211_node *txa_ni;	/* back pointer */
 	u_short		txa_flags;
 #define	IEEE80211_AGGR_IMMEDIATE	0x0001	/* BA policy */
 #define	IEEE80211_AGGR_XCHGPEND		0x0002	/* ADDBA response pending */
 #define	IEEE80211_AGGR_RUNNING		0x0004	/* ADDBA response received */
 #define	IEEE80211_AGGR_SETUP		0x0008	/* deferred state setup */
 #define	IEEE80211_AGGR_NAK		0x0010	/* peer NAK'd ADDBA request */
+#define	IEEE80211_AGGR_BARPEND		0x0020	/* BAR response pending */
 	uint8_t		txa_ac;
 	uint8_t		txa_token;	/* dialog token */
 	int		txa_lastsample;	/* ticks @ last traffic sample */
@@ -54,8 +56,8 @@ struct ieee80211_tx_ampdu {
 	ieee80211_seq	txa_start;	/* BA window left edge */
 	ieee80211_seq	txa_seqpending;	/* new txa_start pending BAR response */
 	uint16_t	txa_wnd;	/* BA window size */
-	uint8_t		txa_attempts;	/* # ADDBA requests w/o a response */
-	int		txa_nextrequest;/* soonest to make next ADDBA request */
+	uint8_t		txa_attempts;	/* # ADDBA/BAR requests w/o a response*/
+	int		txa_nextrequest;/* soonest to make next request */
 	struct callout	txa_timer;
 	void		*txa_private;	/* driver-private storage */
 };
@@ -187,8 +189,8 @@ int	ieee80211_ampdu_request(struct ieee8
 		struct ieee80211_tx_ampdu *);
 void	ieee80211_ampdu_stop(struct ieee80211_node *,
 		struct ieee80211_tx_ampdu *, int);
-int	ieee80211_send_bar(struct ieee80211_node *,
-		const struct ieee80211_tx_ampdu *);
+int	ieee80211_send_bar(struct ieee80211_node *, struct ieee80211_tx_ampdu *,
+		ieee80211_seq);
 int	ieee80211_send_action(struct ieee80211_node *,
 		int, int, uint16_t [4]);
 uint8_t	*ieee80211_add_htcap(uint8_t *, struct ieee80211_node *);

Modified: head/sys/net80211/ieee80211_var.h
==============================================================================
--- head/sys/net80211/ieee80211_var.h	Sat Oct 25 23:44:25 2008	(r184279)
+++ head/sys/net80211/ieee80211_var.h	Sat Oct 25 23:58:59 2008	(r184280)
@@ -273,6 +273,9 @@ struct ieee80211com {
 				    int status, int baparamset, int batimeout);
 	void			(*ic_addba_stop)(struct ieee80211_node *,
 				    struct ieee80211_tx_ampdu *);
+	/* BAR response received */
+	void			(*ic_bar_response)(struct ieee80211_node *,
+				    struct ieee80211_tx_ampdu *, int status);
 };
 
 struct ieee80211_aclator;



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