diff options
author | 2009-01-28 18:55:18 +0000 | |
---|---|---|
committer | 2009-01-28 18:55:18 +0000 | |
commit | ec69e05a7853b967e62e2e5011939cf6238bf5b5 (patch) | |
tree | 6475b64bf4cea61f6d2ec14260fbefbd870b7061 | |
parent | reuse recipient_to_path; ok gilles@ (diff) | |
download | wireguard-openbsd-ec69e05a7853b967e62e2e5011939cf6238bf5b5.tar.xz wireguard-openbsd-ec69e05a7853b967e62e2e5011939cf6238bf5b5.zip |
Block Ack agreements are unidirectional.
Maintain state for both originator and recipient roles separately.
Do not allocate receive reordering buffer in addba_request().
Test the "initiator" bit in incoming DELBA frames and set it appropriately
in outgoing DELBA frames.
Separate callbacks for Tx/Rx too.
no binary change since all this is #ifdef'ed out.
-rw-r--r-- | sys/net80211/ieee80211.h | 9 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 164 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 6 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 29 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 40 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 99 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.h | 7 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 10 |
8 files changed, 215 insertions, 149 deletions
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h index 11d337f248d..1dd6f33186f 100644 --- a/sys/net80211/ieee80211.h +++ b/sys/net80211/ieee80211.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.h,v 1.48 2009/01/26 19:09:41 damien Exp $ */ +/* $OpenBSD: ieee80211.h,v 1.49 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */ /*- @@ -373,7 +373,7 @@ enum { #define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ /* - * BA/BAR Control field (see Figure 7-13). + * BlockAck/BlockAckReq Control field (see Figure 7-13). */ #define IEEE80211_BA_ACK_POLICY 0x0001 #define IEEE80211_BA_MULTI_TID 0x0002 @@ -382,6 +382,11 @@ enum { #define IEEE80211_BA_TID_INFO_SHIFT 12 /* + * DELBA Parameter Set field (see Figure 7-34). + */ +#define IEEE80211_DELBA_INITIATOR 0x0800 + +/* * ERP information element (see 7.3.2.13). */ #define IEEE80211_ERP_NON_ERP_PRESENT 0x01 diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 13afce16102..5140ccdf636 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_input.c,v 1.107 2009/01/26 19:09:41 damien Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.108 2009/01/28 18:55:18 damien Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe @@ -364,7 +364,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, 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_ba[tid].ba_state != IEEE80211_BA_AGREED) { + 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 */ @@ -558,7 +559,7 @@ void ieee80211_input_ba(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; struct ieee80211_frame *wh; int idx, count; u_int16_t sn; @@ -622,14 +623,14 @@ ieee80211_input_ba(struct ifnet *ifp, struct mbuf *m, /* * Change the value of WinStartB (move window forward) upon reception of a - * Block Ack Request frame or an ADDBA Request (PBAC). + * BlockAckReq frame or an ADDBA Request (PBAC). */ void ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int16_t ssn) { struct ifnet *ifp = &ic->ic_if; - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; int count; /* assert(WinStartB <= SSN) */ @@ -747,7 +748,7 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m, * always possible because 802.11 header length may vary (non-QoS+LLC * is 32 bytes while QoS+LLC is 34 bytes). Some devices are smart and * add 2 padding bytes after the 802.11 header in the QoS case so this - * function is there for brain-dead devices only. + * function is there for stupid drivers/devices only. */ struct mbuf * ieee80211_align_mbuf(struct mbuf *m) @@ -1210,7 +1211,7 @@ ieee80211_save_ie(const u_int8_t *frm, u_int8_t **ie) * [tlv] HT Operation (802.11n) */ void -ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, int isprobe) { const struct ieee80211_frame *wh; @@ -1244,13 +1245,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0, } #endif /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + 12) { + if (m->m_len < sizeof(*wh) + 12) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; + efrm = mtod(m, u_int8_t *) + m->m_len; tstamp = frm; frm += 8; bintval = LE_READ_2(frm); frm += 2; @@ -1533,7 +1534,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m0, * [tlv] HT Capabilities (802.11n) */ void -ieee80211_recv_probe_req(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_probe_req(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { const struct ieee80211_frame *wh; @@ -1545,9 +1546,9 @@ ieee80211_recv_probe_req(struct ieee80211com *ic, struct mbuf *m0, ic->ic_state != IEEE80211_S_RUN) return; - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; + efrm = mtod(m, u_int8_t *) + m->m_len; ssid = rates = xrates = htcaps = NULL; while (frm + 2 <= efrm) { @@ -1625,7 +1626,7 @@ ieee80211_recv_probe_req(struct ieee80211com *ic, struct mbuf *m0, * [2] Status code */ void -ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { const struct ieee80211_frame *wh; @@ -1633,11 +1634,11 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, u_int16_t algo, seq, status; /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + 6) { + if (m->m_len < sizeof(*wh) + 6) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; algo = LE_READ_2(frm); frm += 2; @@ -1678,7 +1679,7 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, * [tlv] HT Capabilities (802.11n) */ void -ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, int reassoc) { const struct ieee80211_frame *wh; @@ -1694,13 +1695,13 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0, return; /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + (reassoc ? 10 : 4)) { + if (m->m_len < sizeof(*wh) + (reassoc ? 10 : 4)) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; + efrm = mtod(m, u_int8_t *) + m->m_len; if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) { DPRINTF(("ignore other bss from %s\n", @@ -1972,7 +1973,7 @@ ieee80211_recv_assoc_req(struct ieee80211com *ic, struct mbuf *m0, * [tlv] HT Operation (802.11n) */ void -ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni, int reassoc) { struct ifnet *ifp = &ic->ic_if; @@ -1989,13 +1990,13 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0, } /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + 6) { + if (m->m_len < sizeof(*wh) + 6) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; - efrm = mtod(m0, u_int8_t *) + m0->m_len; + efrm = mtod(m, u_int8_t *) + m->m_len; capinfo = LE_READ_2(frm); frm += 2; status = LE_READ_2(frm); frm += 2; @@ -2115,7 +2116,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m0, * [2] Reason code */ void -ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; @@ -2123,11 +2124,11 @@ ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, u_int16_t reason; /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + 2) { + if (m->m_len < sizeof(*wh) + 2) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; reason = LE_READ_2(frm); @@ -2161,7 +2162,7 @@ ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, * [2] Reason code */ void -ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0, +ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; @@ -2169,11 +2170,11 @@ ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0, u_int16_t reason; /* make sure all mandatory fixed fields are present */ - if (m0->m_len < sizeof(*wh) + 2) { + if (m->m_len < sizeof(*wh) + 2) { DPRINTF(("frame too short\n")); return; } - wh = mtod(m0, struct ieee80211_frame *); + wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; reason = LE_READ_2(frm); @@ -2218,7 +2219,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m, { const struct ieee80211_frame *wh; const u_int8_t *frm; - struct ieee80211_ba *ba; + struct ieee80211_rx_ba *ba; u_int16_t params, ssn, bufsz, timeout, status; u_int8_t token, tid; @@ -2242,11 +2243,11 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m, timeout = LE_READ_2(&frm[5]); ssn = LE_READ_2(&frm[7]) >> 4; - ba = &ni->ni_ba[tid]; - /* check if we already have a BA agreement for this RA/TID */ + ba = &ni->ni_rx_ba[tid]; + /* check if we already have a Block Ack agreement for this RA/TID */ if (ba->ba_state == IEEE80211_BA_AGREED) { /* XXX should we update the timeout value? */ - /* reset BA inactivity timer */ + /* reset Block Ack inactivity timer */ timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); /* check if it's a Protected Block Ack agreement */ @@ -2254,7 +2255,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m, !(ni->ni_rsncaps & IEEE80211_RSNCAP_PBAC)) return; /* not a PBAC, ignore */ - /* PBAC: treat the ADDBA Request like a BAR */ + /* PBAC: treat the ADDBA Request like a BlockAckReq */ if (SEQ_LT(ba->ba_winstart, ssn)) ieee80211_ba_move_window(ic, ni, tid, ssn); return; @@ -2283,13 +2284,12 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m, /* setup Block Ack agreement */ ba->ba_state = IEEE80211_BA_INIT; - ba->ba_token = token; /* save Dialog Token for ADDBA Resp */ ba->ba_timeout_val = timeout * IEEE80211_DUR_TU; if (ba->ba_timeout_val < IEEE80211_BA_MIN_TIMEOUT) 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; - timeout_set(&ba->ba_to, ieee80211_ba_timeout, ba); + 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) ba->ba_winsize = IEEE80211_BA_MAX_WINSZ; @@ -2305,8 +2305,8 @@ 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_htimmba_start != NULL && - ic->ic_htimmba_start(ic, ni, tid) != 0) { + 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); ba->ba_buf = NULL; @@ -2320,7 +2320,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m, resp: /* MLME-ADDBA.response */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, - IEEE80211_ACTION_ADDBA_RESP, status << 16 | tid); + IEEE80211_ACTION_ADDBA_RESP, status << 16 | token << 8 | tid); } /*- @@ -2338,7 +2338,7 @@ ieee80211_recv_addba_resp(struct ieee80211com *ic, struct mbuf *m, { const struct ieee80211_frame *wh; const u_int8_t *frm; - struct ieee80211_ba *ba; + struct ieee80211_tx_ba *ba; u_int16_t status, params, bufsz, timeout; u_int8_t token, tid; @@ -2363,7 +2363,7 @@ ieee80211_recv_addba_resp(struct ieee80211com *ic, struct mbuf *m, * Ignore if no ADDBA request has been sent for this RA/TID or * if we already have a Block Ack agreement. */ - ba = &ni->ni_ba[tid]; + ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_REQUESTED) { DPRINTF(("no matching ADDBA req found\n")); return; @@ -2385,11 +2385,12 @@ ieee80211_recv_addba_resp(struct ieee80211com *ic, struct mbuf *m, ba->ba_state = IEEE80211_BA_AGREED; /* notify drivers of this new Block Ack agreement */ - if (ic->ic_htimmba_start != NULL) - (void)ic->ic_htimmba_start(ic, ni, tid); + if (ic->ic_ampdu_tx_start != NULL) + (void)ic->ic_ampdu_tx_start(ic, ni, tid); /* start Block Ack inactivity timeout */ - timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); + if (ba->ba_timeout_val != 0) + timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); } /*- @@ -2405,7 +2406,6 @@ ieee80211_recv_delba(struct ieee80211com *ic, struct mbuf *m, { const struct ieee80211_frame *wh; const u_int8_t *frm; - struct ieee80211_ba *ba; u_int16_t params, reason; u_int8_t tid; int i; @@ -2424,29 +2424,46 @@ ieee80211_recv_delba(struct ieee80211com *ic, struct mbuf *m, DPRINTF(("received DELBA from %s, TID %d, reason %d\n", ether_sprintf(ni->ni_macaddr), tid, reason)); - ba = &ni->ni_ba[tid]; - if (ba->ba_state != IEEE80211_BA_AGREED && - ba->ba_state != IEEE80211_BA_REQUESTED) { - DPRINTF(("no matching BA agreement found\n")); - return; - } - /* MLME-DELBA.indication */ + if (params & IEEE80211_DELBA_INITIATOR) { + /* MLME-DELBA.indication(Originator) */ + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; - /* notify drivers of the end of the Block Ack agreement */ - if (ic->ic_htimmba_stop != NULL) - ic->ic_htimmba_stop(ic, ni, tid); + if (ba->ba_state != IEEE80211_BA_AGREED) { + DPRINTF(("no matching Block Ack agreement\n")); + return; + } + /* notify drivers of the end of the Block Ack agreement */ + if (ic->ic_ampdu_rx_stop != NULL) + ic->ic_ampdu_rx_stop(ic, ni, tid); - ba->ba_state = IEEE80211_BA_INIT; - /* stop Block Ack inactivity timer */ - timeout_del(&ba->ba_to); - if (ba->ba_buf != NULL) { - /* free all MSDUs stored in reordering buffer */ - for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) - if (ba->ba_buf[i].m != NULL) - m_freem(ba->ba_buf[i].m); - /* free reordering buffer */ - free(ba->ba_buf, M_DEVBUF); - ba->ba_buf = NULL; + ba->ba_state = IEEE80211_BA_INIT; + /* stop Block Ack inactivity timer */ + timeout_del(&ba->ba_to); + + if (ba->ba_buf != NULL) { + /* free all MSDUs stored in reordering buffer */ + for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) + if (ba->ba_buf[i].m != NULL) + m_freem(ba->ba_buf[i].m); + /* free reordering buffer */ + free(ba->ba_buf, M_DEVBUF); + ba->ba_buf = NULL; + } + } else { + /* MLME-DELBA.indication(Recipient) */ + struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; + + if (ba->ba_state != IEEE80211_BA_AGREED) { + DPRINTF(("no matching Block Ack agreement\n")); + return; + } + /* notify drivers of the end of the Block Ack agreement */ + if (ic->ic_ampdu_tx_stop != NULL) + ic->ic_ampdu_tx_stop(ic, ni, tid); + + ba->ba_state = IEEE80211_BA_INIT; + /* stop Block Ack inactivity timer */ + timeout_del(&ba->ba_to); } } #endif /* !IEEE80211_NO_HT */ @@ -2684,7 +2701,7 @@ ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m, #ifndef IEEE80211_NO_HT /* - * Process an incoming Block Ack Request control frame (see 7.2.1.7). + * Process an incoming BlockAckReq control frame (see 7.2.1.7). */ void ieee80211_recv_bar(struct ieee80211com *ic, struct mbuf *m, @@ -2696,7 +2713,7 @@ ieee80211_recv_bar(struct ieee80211com *ic, struct mbuf *m, u_int8_t tid, ntids; if (!(ni->ni_flags & IEEE80211_NODE_HT)) { - DPRINTF(("received BAR from non-HT STA %s\n", + DPRINTF(("received BlockAckReq from non-HT STA %s\n", ether_sprintf(ni->ni_macaddr))); return; } @@ -2707,7 +2724,7 @@ ieee80211_recv_bar(struct ieee80211com *ic, struct mbuf *m, wh = mtod(m, struct ieee80211_frame_min *); frm = (const u_int8_t *)&wh[1]; - /* read BAR Control field */ + /* read BlockAckReq Control field */ ctl = LE_READ_2(&frm[0]); tid = ctl >> 12; @@ -2720,7 +2737,7 @@ ieee80211_recv_bar(struct ieee80211com *ic, struct mbuf *m, DPRINTF(("MTBAR frame too short\n")); return; } - frm += 2; /* skip BAR Control field */ + frm += 2; /* skip BlockAckReq Control field */ while (ntids-- > 0) { /* read MTBAR Information field */ tid = LE_READ_2(&frm[0]) >> 12; @@ -2736,14 +2753,14 @@ ieee80211_recv_bar(struct ieee80211com *ic, struct mbuf *m, } /* - * Process a Block Ack Request for a specific TID (see 9.10.7.6.3). + * Process a BlockAckReq for a specific TID (see 9.10.7.6.3). * This is the common back-end for all BlockAckReq frame variants. */ void ieee80211_bar_tid(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int16_t ssn) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; /* check if we have a Block Ack agreement for RA/TID */ if (ba->ba_state != IEEE80211_BA_AGREED) { @@ -2770,4 +2787,3 @@ ieee80211_bar_tid(struct ieee80211com *ic, struct ieee80211_node *ni, ieee80211_ba_move_window(ic, ni, tid, ssn); } #endif /* !IEEE80211_NO_HT */ - diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index e034fd6e730..741359f6c11 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.c,v 1.53 2009/01/28 17:15:21 damien Exp $ */ +/* $OpenBSD: ieee80211_node.c,v 1.54 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- @@ -1392,13 +1392,13 @@ ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, void ieee80211_node_leave_ht(struct ieee80211com *ic, struct ieee80211_node *ni) { - struct ieee80211_ba *ba; + struct ieee80211_rx_ba *ba; u_int8_t tid; int i; /* free all Block Ack records */ for (tid = 0; tid < IEEE80211_NUM_TID; tid++) { - ba = &ni->ni_ba[tid]; + ba = &ni->ni_rx_ba[tid]; if (ba->ba_buf != NULL) { for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) if (ba->ba_buf[i].m != NULL) diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 961ace16a8f..dd259bd129c 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.38 2009/01/28 17:15:21 damien Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.39 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -105,12 +105,8 @@ struct ieee80211_rxinfo { #define IEEE80211_RXI_AMPDU_DONE 0x00000002 /* Block Acknowledgement Record */ -struct ieee80211_ba { +struct ieee80211_tx_ba { struct ieee80211_node *ba_ni; /* backpointer for callbacks */ - struct { - struct mbuf *m; - struct ieee80211_rxinfo rxi; - } *ba_buf; struct timeout ba_to; int ba_timeout_val; #define IEEE80211_BA_MIN_TIMEOUT (10 * 1000) /* 10msec */ @@ -126,10 +122,24 @@ struct ieee80211_ba { u_int16_t ba_winsize; #define IEEE80211_BA_MAX_WINSZ 128 /* maximum we will accept */ - u_int16_t ba_head; u_int8_t ba_token; }; +struct ieee80211_rx_ba { + struct ieee80211_node *ba_ni; /* backpointer for callbacks */ + struct { + struct mbuf *m; + struct ieee80211_rxinfo rxi; + } *ba_buf; + struct timeout ba_to; + int ba_timeout_val; + int ba_state; + u_int16_t ba_winstart; + u_int16_t ba_winend; + u_int16_t ba_winsize; + u_int16_t ba_head; +}; + /* * Node specific information. Note that drivers are expected * to derive from this structure to add device-specific per-node @@ -208,8 +218,9 @@ struct ieee80211_node { int ni_sa_query_count; #ifdef notyet - /* HT-immediate Block Ack */ - struct ieee80211_ba ni_ba[IEEE80211_NUM_TID]; + /* Block Ack records */ + struct ieee80211_tx_ba ni_tx_ba[IEEE80211_NUM_TID]; + struct ieee80211_rx_ba ni_rx_ba[IEEE80211_NUM_TID]; #endif /* others */ diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 3186d6e1b97..cb33f7600da 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_output.c,v 1.82 2009/01/26 21:28:55 damien Exp $ */ +/* $OpenBSD: ieee80211_output.c,v 1.83 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ /*- @@ -97,9 +97,9 @@ struct mbuf *ieee80211_get_disassoc(struct ieee80211com *, struct mbuf *ieee80211_get_addba_req(struct ieee80211com *, struct ieee80211_node *, u_int8_t); struct mbuf *ieee80211_get_addba_resp(struct ieee80211com *, - struct ieee80211_node *, u_int8_t, u_int16_t); + struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t); struct mbuf *ieee80211_get_delba(struct ieee80211com *, - struct ieee80211_node *, u_int8_t, u_int16_t); + struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t); #endif struct mbuf *ieee80211_get_sa_query(struct ieee80211com *, struct ieee80211_node *, u_int8_t); @@ -600,7 +600,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni) if (ic->ic_tid_noack & (1 << tid)) qos |= IEEE80211_QOS_ACK_POLICY_NOACK; #ifndef IEEE80211_NO_HT - else if (ni->ni_ba[tid].ba_state == IEEE80211_BA_AGREED) + else if (ni->ni_tx_ba[tid].ba_state == IEEE80211_BA_AGREED) qos |= IEEE80211_QOS_ACK_POLICY_BA; #endif qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; @@ -1046,6 +1046,7 @@ ieee80211_add_htcaps(u_int8_t *frm, struct ieee80211com *ic) return frm; } +#ifndef IEEE80211_STA_ONLY /* * Add an HT Operation element to a frame (see 7.3.2.58). */ @@ -1060,6 +1061,7 @@ ieee80211_add_htop(u_int8_t *frm, struct ieee80211com *ic) memset(frm, 0, 16); frm += 16; return frm; } +#endif /* !IEEE80211_STA_ONLY */ #endif /* !IEEE80211_NO_HT */ #ifndef IEEE80211_STA_ONLY @@ -1440,7 +1442,7 @@ struct mbuf * ieee80211_get_addba_req(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct mbuf *m; u_int8_t *frm; u_int16_t params; @@ -1474,9 +1476,9 @@ ieee80211_get_addba_req(struct ieee80211com *ic, struct ieee80211_node *ni, */ struct mbuf * ieee80211_get_addba_resp(struct ieee80211com *ic, struct ieee80211_node *ni, - u_int8_t tid, u_int16_t status) + u_int8_t tid, u_int8_t token, u_int16_t status) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct mbuf *m; u_int8_t *frm; u_int16_t params; @@ -1488,11 +1490,17 @@ ieee80211_get_addba_resp(struct ieee80211com *ic, struct ieee80211_node *ni, frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_BA; *frm++ = IEEE80211_ACTION_ADDBA_RESP; - *frm++ = ba->ba_token; + *frm++ = token; LE_WRITE_2(frm, status); frm += 2; - params = ba->ba_winsize << 6 | tid << 2 | IEEE80211_BA_ACK_POLICY; + params = tid << 2 | IEEE80211_BA_ACK_POLICY; + if (status == 0) + params |= ba->ba_winsize << 6; LE_WRITE_2(frm, params); frm += 2; - LE_WRITE_2(frm, ba->ba_timeout_val); frm += 2; + if (status == 0) + LE_WRITE_2(frm, ba->ba_timeout_val); + else + LE_WRITE_2(frm, 0); + frm += 2; m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); @@ -1508,7 +1516,7 @@ ieee80211_get_addba_resp(struct ieee80211com *ic, struct ieee80211_node *ni, */ struct mbuf * ieee80211_get_delba(struct ieee80211com *ic, struct ieee80211_node *ni, - u_int8_t tid, u_int16_t reason) + u_int8_t tid, u_int8_t dir, u_int16_t reason) { struct mbuf *m; u_int8_t *frm; @@ -1521,7 +1529,9 @@ ieee80211_get_delba(struct ieee80211com *ic, struct ieee80211_node *ni, frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_BA; *frm++ = IEEE80211_ACTION_DELBA; - params = tid << 12; /* XXX initiator */ + params = tid << 12; + if (dir) + params |= IEEE80211_DELBA_INITIATOR; LE_WRITE_2(frm, params); frm += 2; LE_WRITE_2(frm, reason); frm += 2; @@ -1570,11 +1580,11 @@ ieee80211_get_action(struct ieee80211com *ic, struct ieee80211_node *ni, m = ieee80211_get_addba_req(ic, ni, arg & 0xffff); break; case IEEE80211_ACTION_ADDBA_RESP: - m = ieee80211_get_addba_resp(ic, ni, arg & 0xffff, - arg >> 16); + m = ieee80211_get_addba_resp(ic, ni, arg & 0xff, + arg >> 8, arg >> 16); break; case IEEE80211_ACTION_DELBA: - m = ieee80211_get_delba(ic, ni, arg & 0xffff, + m = ieee80211_get_delba(ic, ni, arg & 0xff, arg >> 8, arg >> 16); break; } diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index b1eb2f5dcbe..a53a8da33ba 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.c,v 1.38 2009/01/26 19:09:41 damien Exp $ */ +/* $OpenBSD: ieee80211_proto.c,v 1.39 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- @@ -554,9 +554,9 @@ ieee80211_sa_query_request(struct ieee80211com *ic, struct ieee80211_node *ni) #ifndef IEEE80211_NO_HT void -ieee80211_ba_timeout(void *arg) +ieee80211_tx_ba_timeout(void *arg) { - struct ieee80211_ba *ba = arg; + struct ieee80211_tx_ba *ba = arg; struct ieee80211_node *ni = ba->ba_ni; struct ieee80211com *ic = ni->ni_ic; u_int8_t tid; @@ -566,17 +566,34 @@ ieee80211_ba_timeout(void *arg) if (ba->ba_state == IEEE80211_BA_REQUESTED) { /* MLME-ADDBA.confirm(TIMEOUT) */ ba->ba_state = IEEE80211_BA_INIT; - free(ba->ba_buf, M_DEVBUF); - ba->ba_buf = NULL; } else if (ba->ba_state == IEEE80211_BA_AGREED) { /* Block Ack inactivity timeout */ - tid = ((caddr_t)ba - (caddr_t)ni->ni_ba) / sizeof(*ba); - ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, tid); + tid = ((caddr_t)ba - (caddr_t)ni->ni_tx_ba) / sizeof(*ba); + ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, + 1, tid); } splx(s); } +void +ieee80211_rx_ba_timeout(void *arg) +{ + struct ieee80211_rx_ba *ba = arg; + struct ieee80211_node *ni = ba->ba_ni; + struct ieee80211com *ic = ni->ni_ic; + u_int8_t tid; + int s; + + s = splnet(); + + /* Block Ack inactivity timeout */ + tid = ((caddr_t)ba - (caddr_t)ni->ni_rx_ba) / sizeof(*ba); + ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, 0, tid); + + splx(s); +} + /* * Request initiation of Block Ack with the specified peer. */ @@ -584,7 +601,7 @@ int ieee80211_addba_request(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t ssn, u_int8_t tid) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; + struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; /* MLME-ADDBA.request */ @@ -592,16 +609,10 @@ ieee80211_addba_request(struct ieee80211com *ic, struct ieee80211_node *ni, ba->ba_state = IEEE80211_BA_REQUESTED; ba->ba_token = ic->ic_dialog_token++; ba->ba_timeout_val = IEEE80211_BA_MAX_TIMEOUT; - timeout_set(&ba->ba_to, ieee80211_ba_timeout, ba); + timeout_set(&ba->ba_to, ieee80211_tx_ba_timeout, ba); ba->ba_winsize = IEEE80211_BA_MAX_WINSZ; ba->ba_winstart = ssn; ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; - /* allocate and setup our reordering buffer */ - ba->ba_buf = malloc(IEEE80211_BA_MAX_WINSZ * sizeof(*ba->ba_buf), - M_DEVBUF, M_NOWAIT | M_ZERO); - if (ba->ba_buf == NULL) - return ENOMEM; - ba->ba_head = 0; timeout_add_sec(&ba->ba_to, 1); /* dot11ADDBAResponseTimeout */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, @@ -614,36 +625,44 @@ ieee80211_addba_request(struct ieee80211com *ic, struct ieee80211_node *ni, */ void ieee80211_delba_request(struct ieee80211com *ic, struct ieee80211_node *ni, - u_int16_t reason, u_int8_t tid) + u_int16_t reason, u_int8_t dir, u_int8_t tid) { - struct ieee80211_ba *ba = &ni->ni_ba[tid]; - int i; - /* MLME-DELBA.request */ /* transmit a DELBA frame */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, - IEEE80211_ACTION_DELBA, reason << 16 | tid); - /* - * XXX We should wait for an acknowledgment of the DELBA frame but - * drivers are not necessarily notified when a frame is ACK'ed by - * hardware. - */ - /* MLME-DELBA.confirm */ - if (ic->ic_htimmba_stop != NULL) - ic->ic_htimmba_stop(ic, ni, tid); - - ba->ba_state = IEEE80211_BA_INIT; - /* stop Block Ack inactivity timer */ - timeout_del(&ba->ba_to); - if (ba->ba_buf != NULL) { - /* free all MSDUs stored in reordering buffer */ - for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) - if (ba->ba_buf[i].m != NULL) - m_freem(ba->ba_buf[i].m); - /* free reordering buffer */ - free(ba->ba_buf, M_DEVBUF); - ba->ba_buf = NULL; + IEEE80211_ACTION_DELBA, reason << 16 | dir << 8 | tid); + if (dir) { + /* MLME-DELBA.confirm(Originator) */ + struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; + + if (ic->ic_ampdu_tx_stop != NULL) + ic->ic_ampdu_tx_stop(ic, ni, tid); + + ba->ba_state = IEEE80211_BA_INIT; + /* stop Block Ack inactivity timer */ + timeout_del(&ba->ba_to); + } else { + /* MLME-DELBA.confirm(Recipient) */ + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; + int i; + + if (ic->ic_ampdu_rx_stop != NULL) + ic->ic_ampdu_rx_stop(ic, ni, tid); + + ba->ba_state = IEEE80211_BA_INIT; + /* stop Block Ack inactivity timer */ + timeout_del(&ba->ba_to); + + if (ba->ba_buf != NULL) { + /* free all MSDUs stored in reordering buffer */ + for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) + if (ba->ba_buf[i].m != NULL) + m_freem(ba->ba_buf[i].m); + /* free reordering buffer */ + free(ba->ba_buf, M_DEVBUF); + ba->ba_buf = NULL; + } } } #endif /* !IEEE80211_NO_HT */ diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index f5c57028ddc..ba94c86c9e9 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.h,v 1.37 2009/01/26 19:09:41 damien Exp $ */ +/* $OpenBSD: ieee80211_proto.h,v 1.38 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */ /*- @@ -153,11 +153,12 @@ extern void ieee80211_sa_query_timeout(void *); extern void ieee80211_sa_query_request(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_NO_HT -extern void ieee80211_ba_timeout(void *); +extern void ieee80211_tx_ba_timeout(void *); +extern void ieee80211_rx_ba_timeout(void *); extern int ieee80211_addba_request(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int8_t); extern void ieee80211_delba_request(struct ieee80211com *, - struct ieee80211_node *, u_int16_t, u_int8_t); + struct ieee80211_node *, u_int16_t, u_int8_t, u_int8_t); #endif #endif /* _NET80211_IEEE80211_PROTO_H_ */ diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 13e6ff1bc8a..2860ffef826 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_var.h,v 1.56 2009/01/26 19:09:41 damien Exp $ */ +/* $OpenBSD: ieee80211_var.h,v 1.57 2009/01/28 18:55:18 damien Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- @@ -200,9 +200,13 @@ struct ieee80211com { void (*ic_delete_key)(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); - int (*ic_htimmba_start)(struct ieee80211com *, + int (*ic_ampdu_tx_start)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); - void (*ic_htimmba_stop)(struct ieee80211com *, + void (*ic_ampdu_tx_stop)(struct ieee80211com *, + struct ieee80211_node *, u_int8_t); + int (*ic_ampdu_rx_start)(struct ieee80211com *, + struct ieee80211_node *, u_int8_t); + void (*ic_ampdu_rx_stop)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); u_int8_t ic_myaddr[IEEE80211_ADDR_LEN]; struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; |