summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2015-12-12 11:25:47 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2015-12-12 11:25:47 +0000
commit873d5db1732810777f3fb64f8fb0a922d35ae825 (patch)
tree7826d8ed76d03877a08191466ef2727c6e18f795
parent55da5363222bceb8d8002b97c1d8fccecd8bf66b (diff)
Finish support for receiving 11n A-MPDUs.
The initial implementation was added by damien@ years ago. Summary of the changes made in this commit: - In ieee80211_input(), process A-MPDUs before duplicate detection. - Don't forget to set ba->ba_ni in ieee80211_recv_addba_req() so we don't crash in ieee80211_rx_ba_timeout(). - In ieee80211_recv_addba_req(), tweak the logic to deny BlockAck requests if the driver has no callback for doing so. - Implement ieee80211_ba_del() which cleans up BlockAck state. - Increase the minimum and maximum lifetime for BlockAck agrements. ok mpi@
-rw-r--r--sys/net80211/ieee80211_input.c63
-rw-r--r--sys/net80211/ieee80211_node.c37
-rw-r--r--sys/net80211/ieee80211_node.h6
3 files changed, 79 insertions, 27 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 2da9eeefc9e..c1b05365d6b 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_input.c,v 1.142 2015/11/15 11:14:17 stsp Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.143 2015/12/12 11:25:46 stsp Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -280,6 +280,43 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
tid = 0;
}
+#ifndef IEEE80211_NO_HT
+ if (type == IEEE80211_FC0_TYPE_DATA && hasqos &&
+ !(rxi->rxi_flags & IEEE80211_RXI_AMPDU_DONE)) {
+ int ba_state = ni->ni_rx_ba[tid].ba_state;
+
+ /*
+ * If Block Ack was explicitly requested, check
+ * if we have a BA agreement for this RA/TID.
+ */
+ if ((qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
+ IEEE80211_QOS_ACK_POLICY_BA &&
+ ba_state != IEEE80211_BA_AGREED) {
+ DPRINTF(("no BA agreement for %s, TID %d\n",
+ ether_sprintf(ni->ni_macaddr), tid));
+ /* send a DELBA with reason code UNKNOWN-BA */
+ IEEE80211_SEND_ACTION(ic, ni,
+ IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA,
+ IEEE80211_REASON_SETUP_REQUIRED << 16 | tid);
+ goto err;
+ }
+
+ /*
+ * Check if we have an explicit or implicit
+ * Block Ack Request for a valid BA agreement.
+ */
+ if (ba_state == IEEE80211_BA_AGREED &&
+ ((qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
+ IEEE80211_QOS_ACK_POLICY_BA ||
+ (qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
+ IEEE80211_QOS_ACK_POLICY_NORMAL)) {
+ /* go through A-MPDU reordering */
+ ieee80211_input_ba(ifp, m, ni, tid, rxi);
+ return; /* don't free m! */
+ }
+ }
+#endif
+
/* duplicate detection (see 9.2.9) */
if (ieee80211_has_seq(wh) &&
ic->ic_state != IEEE80211_S_SCAN) {
@@ -430,27 +467,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
goto out;
}
-#ifndef IEEE80211_NO_HT
- if (!(rxi->rxi_flags & IEEE80211_RXI_AMPDU_DONE) &&
- hasqos && (qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
- IEEE80211_QOS_ACK_POLICY_BA) {
- /* check if we have a BA agreement for this RA/TID */
- if (ni->ni_rx_ba[tid].ba_state !=
- IEEE80211_BA_AGREED) {
- DPRINTF(("no BA agreement for %s, TID %d\n",
- ether_sprintf(ni->ni_macaddr), tid));
- /* send a DELBA with reason code UNKNOWN-BA */
- IEEE80211_SEND_ACTION(ic, ni,
- IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA,
- IEEE80211_REASON_SETUP_REQUIRED << 16 |
- tid);
- goto err;
- }
- /* go through A-MPDU reordering */
- ieee80211_input_ba(ifp, m, ni, tid, rxi);
- return; /* don't free m! */
- }
-#endif
if ((ic->ic_flags & IEEE80211_F_WEPON) ||
((ic->ic_flags & IEEE80211_F_RSNON) &&
(ni->ni_flags & IEEE80211_NODE_RXPROT))) {
@@ -2449,6 +2465,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m,
ba->ba_timeout_val = IEEE80211_BA_MIN_TIMEOUT;
else if (ba->ba_timeout_val > IEEE80211_BA_MAX_TIMEOUT)
ba->ba_timeout_val = IEEE80211_BA_MAX_TIMEOUT;
+ ba->ba_ni = ni;
timeout_set(&ba->ba_to, ieee80211_rx_ba_timeout, ba);
ba->ba_winsize = bufsz;
if (ba->ba_winsize == 0 || ba->ba_winsize > IEEE80211_BA_MAX_WINSZ)
@@ -2465,7 +2482,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m,
ba->ba_head = 0;
/* notify drivers of this new Block Ack agreement */
- if (ic->ic_ampdu_rx_start != NULL &&
+ if (ic->ic_ampdu_rx_start == NULL ||
ic->ic_ampdu_rx_start(ic, ni, tid) != 0) {
/* driver failed to setup, rollback */
free(ba->ba_buf, M_DEVBUF, 0);
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index aa6d5c97a7b..ebe90d16374 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.c,v 1.92 2015/11/24 13:45:06 mpi Exp $ */
+/* $OpenBSD: ieee80211_node.c,v 1.93 2015/12/12 11:25:46 stsp Exp $ */
/* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */
/*-
@@ -68,6 +68,9 @@ u_int8_t ieee80211_node_getrssi(struct ieee80211com *,
void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *,
const u_int8_t *);
void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
+#ifndef IEEE80211_NO_HT
+void ieee80211_ba_del(struct ieee80211_node *);
+#endif
struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *);
void ieee80211_needs_auth(struct ieee80211com *, struct ieee80211_node *);
@@ -757,6 +760,9 @@ ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni)
free(ni->ni_rsnie, M_DEVBUF, 0);
ni->ni_rsnie = NULL;
}
+#ifndef IEEE80211_NO_HT
+ ieee80211_ba_del(ni);
+#endif
}
void
@@ -1065,6 +1071,32 @@ ieee80211_find_node_for_beacon(struct ieee80211com *ic,
return (keep);
}
+#ifndef IEEE80211_NO_HT
+void
+ieee80211_ba_del(struct ieee80211_node *ni)
+{
+ int tid;
+
+ for (tid = 0; tid < nitems(ni->ni_rx_ba); tid++) {
+ struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
+ if (ba->ba_state == IEEE80211_BA_AGREED) {
+ if (timeout_pending(&ba->ba_to))
+ timeout_del(&ba->ba_to);
+ ba->ba_state = IEEE80211_BA_INIT;
+ }
+ }
+
+ for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++) {
+ struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
+ if (ba->ba_state == IEEE80211_BA_AGREED) {
+ if (timeout_pending(&ba->ba_to))
+ timeout_del(&ba->ba_to);
+ ba->ba_state = IEEE80211_BA_INIT;
+ }
+ }
+}
+#endif
+
void
ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
{
@@ -1079,6 +1111,9 @@ ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
timeout_del(&ni->ni_sa_query_to);
IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
#endif
+#ifndef IEEE80211_NO_HT
+ ieee80211_ba_del(ni);
+#endif
RB_REMOVE(ieee80211_tree, &ic->ic_tree, ni);
ic->ic_nnodes--;
#ifndef IEEE80211_STA_ONLY
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 59f17633cc4..12341b6c4ea 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.h,v 1.49 2015/11/15 12:34:07 stsp Exp $ */
+/* $OpenBSD: ieee80211_node.h,v 1.50 2015/12/12 11:25:46 stsp Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
/*-
@@ -112,8 +112,8 @@ struct ieee80211_tx_ba {
struct ieee80211_node *ba_ni; /* backpointer for callbacks */
struct timeout ba_to;
int ba_timeout_val;
-#define IEEE80211_BA_MIN_TIMEOUT (10 * 1000) /* 10msec */
-#define IEEE80211_BA_MAX_TIMEOUT (10 * 1000 * 1000) /* 10sec */
+#define IEEE80211_BA_MIN_TIMEOUT (10 * 1000 * 1000) /* 10 sec */
+#define IEEE80211_BA_MAX_TIMEOUT (60 * 1000 * 1000) /* 60 sec */
int ba_state;
#define IEEE80211_BA_INIT 0