Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Jun 2020 07:38:11 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r361825 - head/sys/net80211
Message-ID:  <202006050738.0557cBWA085832@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Fri Jun  5 07:38:10 2020
New Revision: 361825
URL: https://svnweb.freebsd.org/changeset/base/361825

Log:
  [net80211] Add initial A-MSDU in A-MPDU negotation support.
  
  This is hopefully a big no-op unless you're running some extra
  patches to flip on A-MSDU options in a driver.
  
  802.11n supports sending A-MSDU in A-MPDU. That lets you do things
  like pack small frames into an A-MSDU and stuff /those/ into an A-MPDU.
  It allows for much more efficient airtime because you're not
  wasting time sending small frames - which is still a problem when
  doing A-MPDU as there's still per-frame overhead and minimum A-MPDU
  density requirements.
  
  It, however, is optional for 802.11n.  A lot of stuff doesn't advertise
  it (but does it, just wait!); and I know that ath10k does it and my
  ath(4) driver work supports it.
  
  Now, 802.11ac makes A-MSDU in A-MPDU something that can happen more
  frequently, because even though you can send very large A-MPDUs
  (like 1 megabyte and larger) you still have the small frame problem.
  So, 802.11ac NICs like ath10k and iwm will support A-MSDU in A-MPDU
  out of the box if it's enabled - and you can negotiate it.
  
  So, let's lay down the ground work to enable A-MSDU in A-MPDU.
  This will allow hardware like iwn(4) and ath(4) which supports
  software A-MSDU but hardware A-MPDU to be more efficient.
  
  Drivers that support A-MSDU in A-MPDU will set TX/RX htcap flags.
  Note this is separate from the software A-MSDU encap path; /that/
  dictates whether net80211 is doing A-MSDU encapsulation or not.
  These HTC flags control negotiation, NOT encapsulation.
  
  Once this negotiation and driver bits are done, hardware like
  rtwn(4), run(4), and others will be able to use A-MSDU even without
  A-MPDU working;  right now FF and A-MSDU aren't even attempted
  if you're an 11n node.  It's a small hold-over from the initial
  A-MPDU work and I know how to fix it, but to flip it on properly
  I need to be able to negotiate or ignore A-MSDU in A-MPDU.
  
  Oh and the fun part - some 11ac APs I've tested will quite happily
  decap A-MSDU in A-MPDU even though they don't negotiate it when
  doing 802.11n.  So hey, I know it works - I just want to properly
  handle things. :-)
  
  Tested:
  
  * AR9380, STA/AP mode

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

Modified: head/sys/net80211/_ieee80211.h
==============================================================================
--- head/sys/net80211/_ieee80211.h	Fri Jun  5 07:37:52 2020	(r361824)
+++ head/sys/net80211/_ieee80211.h	Fri Jun  5 07:38:10 2020	(r361825)
@@ -529,10 +529,13 @@ struct ieee80211_mimo_info {
 #define	IEEE80211_HTC_TXUNEQUAL	0x00800000	/* CAPABILITY: TX unequal MCS */
 #define	IEEE80211_HTC_TXMCS32	0x01000000	/* CAPABILITY: MCS32 support */
 #define	IEEE80211_HTC_TXLDPC	0x02000000	/* CAPABILITY: TX using LDPC */
+#define	IEEE80211_HTC_RX_AMSDU_AMPDU	0x04000000	/* CAPABILITY: RX A-MSDU in A-MPDU */
+#define	IEEE80211_HTC_TX_AMSDU_AMPDU	0x08000000	/* CAPABILITY: TX A-MSDU in A-MPDU */
 
 #define	IEEE80211_C_HTCAP_BITS \
 	"\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \
-	"\21AMPDU\22AMSDU\23HT\24SMPS\25RIFS\32TXLDPC"
+	"\21AMPDU\22AMSDU\23HT\24SMPS\25RIFS\32TXLDPC\33RXAMSDUAMPDU" \
+	"\34TXAMSDUAMPDU"
 
 /*
  * RX status notification - which fields are valid.

Modified: head/sys/net80211/ieee80211_ht.c
==============================================================================
--- head/sys/net80211/ieee80211_ht.c	Fri Jun  5 07:37:52 2020	(r361824)
+++ head/sys/net80211/ieee80211_ht.c	Fri Jun  5 07:38:10 2020	(r361825)
@@ -592,6 +592,7 @@ static int
 ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,
 	int baparamset, int batimeout, int baseqctl)
 {
+	struct ieee80211vap *vap = ni->ni_vap;
 	int bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
 
 	if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
@@ -607,6 +608,13 @@ ampdu_rx_start(struct ieee80211_node *ni, struct ieee8
 	rap->rxa_start = MS(baseqctl, IEEE80211_BASEQ_START);
 	rap->rxa_flags |=  IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
 
+	/* XXX this should be a configuration flag */
+	if ((vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU) &&
+	    (MS(baparamset, IEEE80211_BAPS_AMSDU)))
+		rap->rxa_flags |= IEEE80211_AGGR_AMSDU;
+	else
+		rap->rxa_flags &= ~IEEE80211_AGGR_AMSDU;
+
 	return 0;
 }
 
@@ -642,6 +650,8 @@ ieee80211_ampdu_rx_start_ext(struct ieee80211_node *ni
 	}
 	rap->rxa_flags |=  IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
 
+	/* XXX TODO: no amsdu flag */
+
 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
 	    "%s: tid=%d, start=%d, wnd=%d, flags=0x%08x",
 	    __func__,
@@ -1163,7 +1173,8 @@ ieee80211_ht_node_init(struct ieee80211_node *ni)
 		ieee80211_txampdu_init_pps(tap);
 		/* NB: further initialization deferred */
 	}
-	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
+	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
+	    IEEE80211_NODE_AMSDU;
 }
 
 /*
@@ -1329,7 +1340,8 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni)
 		ieee80211_txampdu_init_pps(tap);
 	}
 	/* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
-	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
+	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
+	    IEEE80211_NODE_AMSDU;
 }
 
 /*
@@ -2173,6 +2185,7 @@ ieee80211_addba_response(struct ieee80211_node *ni,
 	struct ieee80211_tx_ampdu *tap,
 	int status, int baparamset, int batimeout)
 {
+	struct ieee80211vap *vap = ni->ni_vap;
 	int bufsiz, tid;
 
 	/* XXX locking */
@@ -2182,10 +2195,16 @@ ieee80211_addba_response(struct ieee80211_node *ni,
 		/* 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;
+		/* TODO: this should be a vap flag */
+		if ((vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU) &&
+		    (ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
+		    (MS(baparamset, IEEE80211_BAPS_AMSDU)))
+			tap->txa_flags |= IEEE80211_AGGR_AMSDU;
+		else
+			tap->txa_flags &= ~IEEE80211_AGGR_AMSDU;
 	} else {
 		/* mark tid so we don't try again */
 		tap->txa_flags |= IEEE80211_AGGR_NAK;
@@ -2204,7 +2223,7 @@ ieee80211_addba_stop(struct ieee80211_node *ni, struct
 	addba_stop_timeout(tap);
 	if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
 		/* XXX clear aggregation queue */
-		tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
+		tap->txa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU);
 	}
 	tap->txa_attempts = 0;
 }
@@ -2256,7 +2275,7 @@ ht_recv_action_ba_addba_request(struct ieee80211_node 
 	 */
 	if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
 	    (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
-		/* XXX handle ampdu_rx_start failure */
+		/* XXX TODO: handle ampdu_rx_start failure */
 		ic->ic_ampdu_rx_start(ni, rap,
 		    baparamset, batimeout, baseqctl);
 
@@ -2275,7 +2294,16 @@ ht_recv_action_ba_addba_request(struct ieee80211_node 
 		| SM(tid, IEEE80211_BAPS_TID)
 		| SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
 		;
-	/* XXX AMSDU in AMPDU? */
+
+	/*
+	 * TODO: we're out of iv_flags_ht fields; once
+	 * this is extended we should make this configurable.
+	 */
+	if ((baparamset & IEEE80211_BAPS_AMSDU) &&
+	    (ni->ni_flags & IEEE80211_NODE_AMSDU_RX) &&
+	    (vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU))
+		args[2] |= IEEE80211_BAPS_AMSDU;
+
 	args[3] = 0;
 	args[4] = 0;
 	ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
@@ -2294,6 +2322,7 @@ ht_recv_action_ba_addba_response(struct ieee80211_node
 	uint8_t dialogtoken, policy;
 	uint16_t baparamset, batimeout, code;
 	int tid, bufsiz;
+	int amsdu;
 
 	dialogtoken = frm[2];
 	code = le16dec(frm+3);
@@ -2301,6 +2330,7 @@ ht_recv_action_ba_addba_response(struct ieee80211_node
 	tid = MS(baparamset, IEEE80211_BAPS_TID);
 	bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
 	policy = MS(baparamset, IEEE80211_BAPS_POLICY);
+	amsdu = !! MS(baparamset, IEEE80211_BAPS_AMSDU);
 	batimeout = le16dec(frm+7);
 
 	tap = &ni->ni_tx_ampdu[tid];
@@ -2349,11 +2379,12 @@ ht_recv_action_ba_addba_response(struct ieee80211_node
 	}
 #endif
 
-	/* XXX TODO: check AMSDU in AMPDU configuration */
 	IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 	    "recv ADDBA response: dialogtoken %u code %d "
-	    "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
-	    dialogtoken, code, baparamset, tid, bufsiz,
+	    "baparamset 0x%x (tid %d bufsiz %d amsdu %d) batimeout %d",
+	    dialogtoken, code, baparamset, tid,
+	    bufsiz,
+	    amsdu,
 	    batimeout);
 	ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
 	return 0;
@@ -2510,8 +2541,12 @@ ieee80211_ampdu_request(struct ieee80211_node *ni,
 		| SM(tid, IEEE80211_BAPS_TID)
 		| SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
 		;
-	/* XXX TODO: check AMSDU in AMPDU configuration */
 
+	/* XXX TODO: this should be a flag, not iv_htcaps */
+	if ((ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
+	    (ni->ni_vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU))
+		args[2] |= IEEE80211_BAPS_AMSDU;
+
 	args[3] = 0;	/* batimeout */
 	/* NB: do first so there's no race against reply */
 	if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
@@ -2843,11 +2878,11 @@ ht_send_action_ba_addba(struct ieee80211_node *ni,
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 	    "send ADDBA %s: dialogtoken %d status %d "
-	    "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
+	    "baparamset 0x%x (tid %d amsdu %d) batimeout 0x%x baseqctl 0x%x",
 	    (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
 		"request" : "response",
 	    args[0], args[1], args[2], MS(args[2], IEEE80211_BAPS_TID),
-	    args[3], args[4]);
+	    MS(args[2], IEEE80211_BAPS_AMSDU), args[3], args[4]);
 
 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
 	    "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,

Modified: head/sys/net80211/ieee80211_ht.h
==============================================================================
--- head/sys/net80211/ieee80211_ht.h	Fri Jun  5 07:37:52 2020	(r361824)
+++ head/sys/net80211/ieee80211_ht.h	Fri Jun  5 07:38:10 2020	(r361825)
@@ -47,6 +47,7 @@ struct ieee80211_tx_ampdu {
 #define	IEEE80211_AGGR_NAK		0x0010	/* peer NAK'd ADDBA request */
 #define	IEEE80211_AGGR_BARPEND		0x0020	/* BAR response pending */
 #define	IEEE80211_AGGR_WAITRX		0x0040	/* Wait for first RX frame to define BAW */
+#define	IEEE80211_AGGR_AMSDU		0x0080	/* A-MSDU in A-MPDU TX allowed */
 	uint8_t		txa_tid;
 	uint8_t		txa_token;	/* dialog token */
 	int		txa_lastsample;	/* ticks @ last traffic sample */
@@ -67,6 +68,14 @@ struct ieee80211_tx_ampdu {
 /* return non-zero if AMPDU tx for the TID is running */
 #define	IEEE80211_AMPDU_RUNNING(tap) \
 	(((tap)->txa_flags & IEEE80211_AGGR_RUNNING) != 0)
+
+/*
+ * Return non-zero if AMPDU tx for the TID is running and we can do
+ * A-MSDU in A-MPDU
+ */
+#define	IEEE80211_AMPDU_RUNNING_AMSDU(tap) \
+	((((tap)->txa_flags & (IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU)) \
+	    == (IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU))
 
 /* return non-zero if AMPDU tx for the TID was NACKed */
 #define	IEEE80211_AMPDU_NACKED(tap)\



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