From 7a8139bec34979455320162a624d9f5762a864d0 Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 21 Sep 2008 23:00:19 +0000 Subject: [PATCH] Cleanup AMPDU handling: For receive: o explicitly tag rx frames w/ M_AMPDU instead of passing frames through the reorder processing according to the node having HT and the frame being QoS data o relax ieee80211_ampdu_reorder asserts to allow any frame to be passed in, unsuitable frames are returned to the caller for normal processing; this permits drivers that cannot inspect the PLCP to mark all data frames as potential ampdu candidates with only a small penalty o add M_AMPDU_MPDU to identify frames resubmitted from the reorder q For transmit: o tag aggregation candidates with M_AMPDU_MPDU o fix the QoS ack policy set in ampdu subframes; we only support immediate BA streams which should be marked for "normal ack" to get implicit block ack behaviour; interestingly certain vendor parts BA'd frames with the 11e BA ack policy set o do not assign a sequence # to aggregation candidates; this must be done when frames are submitted for transmit (NB: this can/will be handled better when aggregation is pulled up to net80211) --- sys/net80211/ieee80211_adhoc.c | 22 +++++++++------------- sys/net80211/ieee80211_freebsd.h | 10 +++++++--- sys/net80211/ieee80211_hostap.c | 22 +++++++++------------- sys/net80211/ieee80211_ht.c | 16 ++++++++++++---- sys/net80211/ieee80211_output.c | 26 +++++++++++++++++++++++--- sys/net80211/ieee80211_sta.c | 22 +++++++++------------- sys/net80211/ieee80211_wds.c | 22 +++++++++------------- 7 files changed, 78 insertions(+), 62 deletions(-) diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c index e0a5bdf56cdc..32de8cc95089 100644 --- a/sys/net80211/ieee80211_adhoc.c +++ b/sys/net80211/ieee80211_adhoc.c @@ -262,14 +262,14 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, uint8_t *bssid; uint16_t rxseq; - if (m->m_flags & M_AMPDU) { + if (m->m_flags & M_AMPDU_MPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames - * w/ M_AMPDU marked have already passed through here - * but were received out of order and been held on the - * reorder queue. When resubmitted they are marked - * with the M_AMPDU flag and we can bypass most of the - * normal processing. + * w/ M_AMPDU_MPDU marked have already passed through + * here but were received out of order and been held on + * the reorder queue. When resubmitted they are marked + * with the M_AMPDU_MPDU flag and we can bypass most of + * the normal processing. */ wh = mtod(m, struct ieee80211_frame *); type = IEEE80211_FC0_TYPE_DATA; @@ -406,16 +406,12 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, /* XXX no power-save support */ /* - * Handle A-MPDU re-ordering. The station must be - * associated and negotiated HT. The frame must be - * a QoS frame (not QoS null data) and not previously - * processed for A-MPDU re-ordering. If the frame is - * to be processed directly then ieee80211_ampdu_reorder + * Handle A-MPDU re-ordering. If the frame is to be + * processed directly then ieee80211_ampdu_reorder * will return 0; otherwise it has consumed the mbuf * and we should do nothing more with it. */ - if ((ni->ni_flags & IEEE80211_NODE_HT) && - subtype == IEEE80211_FC0_SUBTYPE_QOS && + if ((m->m_flags & M_AMPDU) && ieee80211_ampdu_reorder(ni, m) != 0) { m = NULL; goto out; diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h index fcd1b3fa8b8c..448bd787e3f5 100644 --- a/sys/net80211/ieee80211_freebsd.h +++ b/sys/net80211/ieee80211_freebsd.h @@ -246,13 +246,17 @@ struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen); #define M_MORE_DATA M_PROTO5 /* more data frames to follow */ #define M_FF M_PROTO6 /* fast frame */ #define M_TXCB M_PROTO7 /* do tx complete callback */ +#define M_AMPDU_MPDU M_PROTO8 /* ok for A-MPDU aggregation */ #define M_80211_TX \ - (M_LINK0|M_WDS|M_EAPOL|M_PWR_SAV|M_MORE_DATA|M_FF|M_TXCB) + (M_LINK0|M_WDS|M_EAPOL|M_PWR_SAV|M_MORE_DATA|M_FF|M_TXCB|M_AMPDU_MPDU) /* rx path usage */ -#define M_AMPDU M_PROTO1 /* A-MPDU processing done */ +#define M_AMPDU M_PROTO1 /* A-MPDU subframe */ #define M_WEP M_PROTO2 /* WEP done by hardware */ -#define M_80211_RX (M_AMPDU|M_WEP) +#if 0 +#define M_AMPDU_MPDU M_PROTO8 /* A-MPDU re-order done */ +#endif +#define M_80211_RX (M_AMPDU|M_WEP|M_AMPDU_MPDU) /* * Store WME access control bits in the vlan tag. * This is safe since it's done after the packet is classified diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index 492ef13418cb..c876dab84fb2 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -429,14 +429,14 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, uint8_t *bssid; uint16_t rxseq; - if (m->m_flags & M_AMPDU) { + if (m->m_flags & M_AMPDU_MPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames - * w/ M_AMPDU marked have already passed through here - * but were received out of order and been held on the - * reorder queue. When resubmitted they are marked - * with the M_AMPDU flag and we can bypass most of the - * normal processing. + * w/ M_AMPDU_MPDU marked have already passed through + * here but were received out of order and been held on + * the reorder queue. When resubmitted they are marked + * with the M_AMPDU_MPDU flag and we can bypass most of + * the normal processing. */ wh = mtod(m, struct ieee80211_frame *); type = IEEE80211_FC0_TYPE_DATA; @@ -616,16 +616,12 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, } /* - * Handle A-MPDU re-ordering. The station must be - * associated and negotiated HT. The frame must be - * a QoS frame (not QoS null data) and not previously - * processed for A-MPDU re-ordering. If the frame is - * to be processed directly then ieee80211_ampdu_reorder + * Handle A-MPDU re-ordering. If the frame is to be + * processed directly then ieee80211_ampdu_reorder * will return 0; otherwise it has consumed the mbuf * and we should do nothing more with it. */ - if ((ni->ni_flags & IEEE80211_NODE_HT) && - subtype == IEEE80211_FC0_SUBTYPE_QOS && + if ((m->m_flags & M_AMPDU) && ieee80211_ampdu_reorder(ni, m) != 0) { m = NULL; goto out; diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 5356a66b5844..f3c0adf14633 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -335,14 +335,14 @@ ampdu_rx_stop(struct ieee80211_rx_ampdu *rap) /* * Dispatch a frame from the A-MPDU reorder queue. The * frame is fed back into ieee80211_input marked with an - * M_AMPDU flag so it doesn't come back to us (it also + * M_AMPDU_MPDU flag so it doesn't come back to us (it also * permits ieee80211_input to optimize re-processing). */ static __inline void ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m) { - m->m_flags |= M_AMPDU; /* bypass normal processing */ - /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU set */ + m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */ + /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU_MPDU set */ (void) ieee80211_input(ni, m, 0, 0, 0); } @@ -517,11 +517,19 @@ ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m) uint8_t tid; int off; + KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU, + ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags)); KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta")); /* NB: m_len known to be sufficient */ wh = mtod(m, struct ieee80211_qosframe *); - KASSERT(wh->i_fc[0] == IEEE80211_FC0_QOSDATA, ("not QoS data")); + if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) { + /* + * Not QoS data, shouldn't get here but just + * return it to the caller for processing. + */ + return PROCESS; + } if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0]; diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index b1488ca4aa20..9df35f36de22 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -1050,8 +1050,13 @@ ieee80211_encap(struct ieee80211_node *ni, struct mbuf *m) if (IEEE80211_AMPDU_RUNNING(tap)) { /* * Operational, mark frame for aggregation. + * + * NB: We support only immediate BA's for + * AMPDU which means we set the QoS control + * field to "normal ack" (0) to get "implicit + * block ack" behaviour. */ - qos[0] |= IEEE80211_QOS_ACKPOLICY_BA; + m->m_flags |= M_AMPDU_MPDU; } else if (!IEEE80211_AMPDU_REQUESTED(tap) && ic->ic_ampdu_enable(ni, tap)) { /* @@ -1066,8 +1071,23 @@ ieee80211_encap(struct ieee80211_node *ni, struct mbuf *m) qos[1] = 0; wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; - *(uint16_t *)wh->i_seq = - htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); + if ((m->m_flags & M_AMPDU_MPDU) == 0) { + /* + * NB: don't assign a sequence # to potential + * aggregates; we expect this happens at the + * point the frame comes off any aggregation q + * as otherwise we may introduce holes in the + * BA sequence space and/or make window accouting + * more difficult. + * + * XXX may want to control this with a driver + * capability; this may also change when we pull + * aggregation up into net80211 + */ + *(uint16_t *)wh->i_seq = + htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); + ni->ni_txseqs[tid]++; + } ni->ni_txseqs[tid]++; } else { *(uint16_t *)wh->i_seq = diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c index af25bb658c65..d98c6dda9706 100644 --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -494,14 +494,14 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, uint8_t *bssid; uint16_t rxseq; - if (m->m_flags & M_AMPDU) { + if (m->m_flags & M_AMPDU_MPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames - * w/ M_AMPDU marked have already passed through here - * but were received out of order and been held on the - * reorder queue. When resubmitted they are marked - * with the M_AMPDU flag and we can bypass most of the - * normal processing. + * w/ M_AMPDU_MPDU marked have already passed through + * here but were received out of order and been held on + * the reorder queue. When resubmitted they are marked + * with the M_AMPDU_MPDU flag and we can bypass most of + * the normal processing. */ wh = mtod(m, struct ieee80211_frame *); type = IEEE80211_FC0_TYPE_DATA; @@ -595,16 +595,12 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, goto out; /* XXX */ } /* - * Handle A-MPDU re-ordering. The station must be - * associated and negotiated HT. The frame must be - * a QoS frame (not QoS null data) and not previously - * processed for A-MPDU re-ordering. If the frame is - * to be processed directly then ieee80211_ampdu_reorder + * Handle A-MPDU re-ordering. If the frame is to be + * processed directly then ieee80211_ampdu_reorder * will return 0; otherwise it has consumed the mbuf * and we should do nothing more with it. */ - if ((ni->ni_flags & IEEE80211_NODE_HT) && - subtype == IEEE80211_FC0_SUBTYPE_QOS && + if ((m->m_flags & M_AMPDU) && (dir == IEEE80211_FC1_DIR_FROMDS || dir == IEEE80211_FC1_DIR_DSTODS) && ieee80211_ampdu_reorder(ni, m) != 0) { diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c index ede739d61441..ff55ed7ab6dd 100644 --- a/sys/net80211/ieee80211_wds.c +++ b/sys/net80211/ieee80211_wds.c @@ -468,14 +468,14 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, uint8_t dir, type, subtype, qos; uint16_t rxseq; - if (m->m_flags & M_AMPDU) { + if (m->m_flags & M_AMPDU_MPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames - * w/ M_AMPDU marked have already passed through here - * but were received out of order and been held on the - * reorder queue. When resubmitted they are marked - * with the M_AMPDU flag and we can bypass most of the - * normal processing. + * w/ M_AMPDU_MPDU marked have already passed through + * here but were received out of order and been held on + * the reorder queue. When resubmitted they are marked + * with the M_AMPDU_MPDU flag and we can bypass most of + * the normal processing. */ wh = mtod(m, struct ieee80211_frame *); type = IEEE80211_FC0_TYPE_DATA; @@ -590,16 +590,12 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) ni->ni_inact = ni->ni_inact_reload; /* - * Handle A-MPDU re-ordering. The station must be - * associated and negotiated HT. The frame must be - * a QoS frame (not QoS null data) and not previously - * processed for A-MPDU re-ordering. If the frame is - * to be processed directly then ieee80211_ampdu_reorder + * Handle A-MPDU re-ordering. If the frame is to be + * processed directly then ieee80211_ampdu_reorder * will return 0; otherwise it has consumed the mbuf * and we should do nothing more with it. */ - if ((ni->ni_flags & IEEE80211_NODE_HT) && - subtype == IEEE80211_FC0_SUBTYPE_QOS && + if ((m->m_flags & M_AMPDU) && ieee80211_ampdu_reorder(ni, m) != 0) { m = NULL; goto out;