[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
This commit is contained in:
Adrian Chadd 2020-06-05 07:38:10 +00:00
parent d20ff6e680
commit ebb9b25672
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=361825
3 changed files with 60 additions and 13 deletions

View File

@ -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.

View File

@ -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 ieee80211_rx_ampdu *rap,
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, int tid, int seq, int ba
}
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 ieee80211_tx_ampdu *tap)
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 *ni,
*/
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 *ni,
| 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 *ni,
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 *ni,
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 *ni,
}
#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,7 +2541,11 @@ 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 */
@ -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__,

View File

@ -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 */
@ -68,6 +69,14 @@ struct ieee80211_tx_ampdu {
#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)\
(!! ((tap)->txa_flags & IEEE80211_AGGR_NAK))