PERFORCE change 149552 for review

Sam Leffler sam at FreeBSD.org
Wed Sep 10 17:58:49 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=149552

Change 149552 by sam at sam_ebb on 2008/09/10 17:57:49

	Checkpoint support for sending BAR:
	o set the start seq# from ni_txseqs
	o add callback for response processing for driver to override
	o don't commit the new seq# until we believe the BAR has been
	  delivered; this is problematic for drivers that don't give
	  back ACK status (so they'll just have to assume it goes through)
	
	NB: there is no locking and we should allocate tap struct's
	  on demand instead of statically allocating them in the node
	NB: we are super aggressive sending BAR as it's delivery is
	  critical; this may need to be rethought
	NB: we reuse the addba request state which is a hack
	  done w/ the assumption there should never be an
	  addba request pending at the same time we send BAR

Affected files ...

.. //depot/projects/vap/sys/net80211/ieee80211_ht.c#48 edit
.. //depot/projects/vap/sys/net80211/ieee80211_ht.h#21 edit
.. //depot/projects/vap/sys/net80211/ieee80211_var.h#52 edit

Differences ...

==== //depot/projects/vap/sys/net80211/ieee80211_ht.c#48 (text+ko) ====

@@ -86,6 +86,8 @@
 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 @@
 #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,8 @@
 	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);
 
 void
 ieee80211_ht_attach(struct ieee80211com *ic)
@@ -124,6 +129,7 @@
 	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;
@@ -802,6 +808,7 @@
 	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;
@@ -1485,7 +1492,7 @@
 	struct ieee80211_tx_ampdu *tap,
 	int status, int baparamset, int batimeout)
 {
-	int bufsiz;
+	int bufsiz, tid;
 
 	/* XXX locking */
 	addba_stop_timeout(tap);
@@ -1494,7 +1501,11 @@
 		/* 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_seqstart = tap->txa_start = ni->ni_txseqs[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;
@@ -1868,6 +1879,7 @@
 	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)",
@@ -1888,6 +1900,83 @@
 	}
 }
 
+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);
+	} else {
+		/* 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
@@ -1904,17 +1993,30 @@
 	struct ieee80211com *ic = ni->ni_ic;
 	struct ieee80211_frame_bar *bar;
 	struct mbuf *m;
+	uint16_t barctl, barseqctl;
 	uint8_t *frm;
-	uint16_t barctl, barseqctl;
 	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_bar));
+	m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
 	if (m == NULL)
 		senderr(ENOMEM, is_tx_nobuf);
 
+	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;
@@ -1938,11 +2040,29 @@
 
 	IEEE80211_NODE_STAT(ni, tx_mgmt);	/* XXX tx_ctl? */
 
+	/* 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);
 
-	return ic->ic_raw_xmit(ni, m, NULL);
+	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;

==== //depot/projects/vap/sys/net80211/ieee80211_ht.h#21 (text+ko) ====

@@ -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 */
@@ -53,9 +55,10 @@
 	short		txa_qframes;	/* data queued (frames) */
 	ieee80211_seq	txa_seqstart;
 	ieee80211_seq	txa_start;
+	ieee80211_seq	txa_seqpending;	/* new 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 +190,8 @@
 		struct ieee80211_tx_ampdu *);
 void	ieee80211_ampdu_stop(struct ieee80211_node *,
 		struct ieee80211_tx_ampdu *, int);
-int	ieee80211_send_bar(struct ieee80211_node *,
-		struct ieee80211_tx_ampdu *tap, ieee80211_seq seq);
+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 *);

==== //depot/projects/vap/sys/net80211/ieee80211_var.h#52 (text+ko) ====

@@ -273,6 +273,9 @@
 				    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;


More information about the p4-projects mailing list