diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2015-12-12 11:25:47 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2015-12-12 11:25:47 +0000 |
commit | 873d5db1732810777f3fb64f8fb0a922d35ae825 (patch) | |
tree | 7826d8ed76d03877a08191466ef2727c6e18f795 | |
parent | 55da5363222bceb8d8002b97c1d8fccecd8bf66b (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.c | 63 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 37 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 6 |
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 |