Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 May 2011 17:01:11 +0800
From:      Adrian Chadd <adrian@freebsd.org>
To:        freebsd-wireless@freebsd.org
Subject:   Re: [net80211] patch: properly handle sequence checking for HT non-aggregation; refactor out shared code
Message-ID:  <BANLkTimrLqOFA9w7Lp3w-HTa7JyZeGBU%2BA@mail.gmail.com>
In-Reply-To: <BANLkTimseMFe-=y-1rkK%2BhaAxskV6usSfg@mail.gmail.com>
References:  <BANLkTimseMFe-=y-1rkK%2BhaAxskV6usSfg@mail.gmail.com>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
Hi,

Here's an updated diff. I noticed that with this diff, the number of
TCP out of order complaints dropped dramatically but I was seeing them
when the following occured:

wlan0: [00:23:6c:bf:38:3e] discard duplicate frame, seqno <0,4095>
fragno <0,0> tid 0

This is likely also occuring with non-HT (11a/11bg) QoS operation
chips in -HEAD and -8.

Whenever I saw that above being logged (among lots of other logged
duplicate discards, so I know it wasn't just "serial IO" related) I
saw a burst of out-of-order packets/bytes in the receiving side TCP
stack and a drop in throughput.

The current patch adds the following checks:

* if the last seen seqnum is 4095, then retransmissions of the last
seen fragment is eliminated (like the normal codepath intended to do
but didn't);
* else if the last seen seqnum is 4095, allow any subsequent packet.
This may be wrong for fragments (and I may add a check for rxseq !=
4095)) but any subsequent sequence will have a seqnum of < 4095
because of the 12 bit seqnum wrap.
* else (ie, the last seen seqnum isn't 4095), eliminate retransmits
for seq+frag <= last seen.

This almost entirely eliminates the speed drops I've seen in 11n
non-aggregation mode and almost entirely eliminates the burst of
out-of-order packets/bytes. The only time I'm seeing them now is when
the baseband hangs and the interface is reset.



Adrian

[-- Attachment #2 --]
Index: sys/net80211/ieee80211_sta.c
===================================================================
--- sys/net80211/ieee80211_sta.c	(revision 220911)
+++ sys/net80211/ieee80211_sta.c	(working copy)
@@ -512,7 +512,6 @@
 static int
 sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
-#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -591,9 +590,7 @@
 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
 				ic->ic_wme.wme_hipri_traffic++;
 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
-			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
-			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
+			if (! ieee80211_check_rxseq(ni, wh)) {
 				/* duplicate, discard */
 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
 				    bssid, "duplicate",
@@ -910,7 +907,6 @@
 		m_freem(m);
 	}
 	return type;
-#undef SEQ_LEQ
 }
 
 static void
Index: sys/net80211/ieee80211_wds.c
===================================================================
--- sys/net80211/ieee80211_wds.c	(revision 220911)
+++ sys/net80211/ieee80211_wds.c	(working copy)
@@ -406,7 +406,6 @@
 static int
 wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
-#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -495,9 +494,7 @@
 		    TID_TO_WME_AC(tid) >= WME_AC_VI)
 			ic->ic_wme.wme_hipri_traffic++;
 		rxseq = le16toh(*(uint16_t *)wh->i_seq);
-		if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
-		    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-		    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
+		if (! ieee80211_check_rxseq(ni, wh)) {
 			/* duplicate, discard */
 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
 			    wh->i_addr1, "duplicate",
@@ -741,7 +738,6 @@
 		m_freem(m);
 	}
 	return type;
-#undef SEQ_LEQ
 }
 
 static void
Index: sys/net80211/ieee80211_hostap.c
===================================================================
--- sys/net80211/ieee80211_hostap.c	(revision 220911)
+++ sys/net80211/ieee80211_hostap.c	(working copy)
@@ -472,7 +472,6 @@
 static int
 hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
-#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -572,9 +571,7 @@
 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
 				ic->ic_wme.wme_hipri_traffic++;
 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
-			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
-			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
+			if (! ieee80211_check_rxseq(ni, wh)) {
 				/* duplicate, discard */
 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
 				    bssid, "duplicate",
@@ -914,7 +911,6 @@
 		m_freem(m);
 	}
 	return type;
-#undef SEQ_LEQ
 }
 
 static void
Index: sys/net80211/ieee80211_mesh.c
===================================================================
--- sys/net80211/ieee80211_mesh.c	(revision 220911)
+++ sys/net80211/ieee80211_mesh.c	(working copy)
@@ -1040,7 +1040,6 @@
 static int
 mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
-#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -1094,9 +1093,7 @@
 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
 				ic->ic_wme.wme_hipri_traffic++;
 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
-			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
-			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
+			if (! ieee80211_check_rxseq(ni, wh)) {
 				/* duplicate, discard */
 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
 				    wh->i_addr1, "duplicate",
Index: sys/net80211/ieee80211_input.c
===================================================================
--- sys/net80211/ieee80211_input.c	(revision 220911)
+++ sys/net80211/ieee80211_input.c	(working copy)
@@ -760,6 +760,90 @@
 	return 0;
 }
 
+/*
+ * Check the current frame sequence number against the current TID
+ * state and return whether it's in sequence or should be dropped.
+ */
+int
+ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
+{
+#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
+#define	SEQ_EQ(a,b)	((int)((a)-(b)) == 0)
+#define	HAS_SEQ(type)	((type & 0x4) == 0)
+#define	SEQNO(a)	((a) >> IEEE80211_SEQ_SEQ_SHIFT)
+#define	FRAGNO(a)	((a) & IEEE80211_SEQ_FRAG_MASK)
+	uint16_t rxseq;
+	uint8_t type;
+	uint8_t tid;
+	struct ieee80211_rx_ampdu *rap;
+
+	rxseq = le16toh(*(uint16_t *)wh->i_seq);
+	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+	/* Types with no sequence number are always treated valid */
+	if (! HAS_SEQ(type))
+		return 1;
+
+	tid = ieee80211_gettid(wh);
+
+	/*
+	 * Only do the HT AMPDU check for WME stations; non-WME HT stations
+	 * shouldn't exist outside of debugging. We should at least
+	 * handle that.
+	 */
+	if (tid < WME_NUM_TID) {
+		rap = &ni->ni_rx_ampdu[tid];
+		/* HT nodes currently doing RX AMPDU are always valid */
+		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+		    (rap->rxa_flags & IEEE80211_AGGR_RUNNING))
+			return 1;
+	}
+
+	/*	
+	 * Otherwise, retries for packets below or equal to the last
+	 * seen sequence number should be dropped.
+	 *
+	 * XXX This should be revisited to truely identify/log very
+	 * XXX out of order packets (due to vendor bugs), rather than
+	 * XXX simply retransmits.
+	 */
+
+	/* For now, treat frame seqnum 4095 as special. */
+
+	/*
+	 * Drop retransmits on seqnum 4095 for itself.
+	 */
+	if ((SEQNO(ni->ni_rxseqs[tid]) == 4095) &&
+	    SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) &&
+	    (wh->i_fc[1] & IEEE80211_FC1_RETRY))
+		return 0;
+
+	/*
+	 * Treat any subsequent frame as fine if the last seen frame
+	 * is 4095 and it's not a retransmit for the same sequence
+	 * number.
+	 */
+	if (SEQNO(ni->ni_rxseqs[tid]) == 4095)
+		return 1;
+
+	/*
+	 * At this point we assume that seqnums below
+	 * the current are retransmits/out of order packets.
+	 * Eliminate retransmits for those.
+	 */
+	if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
+	    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid]))
+		return 0;
+
+	return 1;
+#undef	SEQ_LEQ
+#undef	SEQ_EQ
+#undef	HAS_SEQ
+#undef	SEQNO
+#undef	FRAGNO
+
+}
+
 #ifdef IEEE80211_DEBUG
 /*
  * Debugging support.
Index: sys/net80211/ieee80211_input.h
===================================================================
--- sys/net80211/ieee80211_input.h	(revision 220911)
+++ sys/net80211/ieee80211_input.h	(working copy)
@@ -157,4 +157,6 @@
 int	ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
 		struct ieee80211_scanparams *);
 int	ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
+int	ieee80211_check_rxseq(struct ieee80211_node *ni,
+		struct ieee80211_frame *wh);
 #endif /* _NET80211_IEEE80211_INPUT_H_ */
Index: sys/net80211/ieee80211_adhoc.c
===================================================================
--- sys/net80211/ieee80211_adhoc.c	(revision 220911)
+++ sys/net80211/ieee80211_adhoc.c	(working copy)
@@ -285,7 +285,6 @@
 static int
 adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
-#define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -412,9 +411,7 @@
 			    TID_TO_WME_AC(tid) >= WME_AC_VI)
 				ic->ic_wme.wme_hipri_traffic++;
 			rxseq = le16toh(*(uint16_t *)wh->i_seq);
-			if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 &&
-			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
-			    SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
+			if (! ieee80211_check_rxseq(ni, wh)) {
 				/* duplicate, discard */
 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
 				    bssid, "duplicate",
@@ -660,7 +657,6 @@
 		m_freem(m);
 	}
 	return type;
-#undef SEQ_LEQ
 }
 
 static int
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?BANLkTimrLqOFA9w7Lp3w-HTa7JyZeGBU%2BA>