summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordamien <damien@openbsd.org>2009-01-28 18:55:18 +0000
committerdamien <damien@openbsd.org>2009-01-28 18:55:18 +0000
commitec69e05a7853b967e62e2e5011939cf6238bf5b5 (patch)
tree6475b64bf4cea61f6d2ec14260fbefbd870b7061
parentreuse recipient_to_path; ok gilles@ (diff)
downloadwireguard-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.h9
-rw-r--r--sys/net80211/ieee80211_input.c164
-rw-r--r--sys/net80211/ieee80211_node.c6
-rw-r--r--sys/net80211/ieee80211_node.h29
-rw-r--r--sys/net80211/ieee80211_output.c40
-rw-r--r--sys/net80211/ieee80211_proto.c99
-rw-r--r--sys/net80211/ieee80211_proto.h7
-rw-r--r--sys/net80211/ieee80211_var.h10
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];