summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2009-07-05 17:59:19 +0000
committersam <sam@FreeBSD.org>2009-07-05 17:59:19 +0000
commitedf89f716262ec28b66e3ba8f49c4a1c11ff0f4c (patch)
tree2b0355c63191e76e8d9a8248e3dcb6081298f0c7
parentc67dff7aca2dbc37c9abe5f0d576016dd2b9905c (diff)
downloadFreeBSD-src-edf89f716262ec28b66e3ba8f49c4a1c11ff0f4c.zip
FreeBSD-src-edf89f716262ec28b66e3ba8f49c4a1c11ff0f4c.tar.gz
Revamp 802.11 action frame handling:
o add a new facility for components to register send+recv handlers o ieee80211_send_action and ieee80211_recv_action now use the registered handlers to dispatch operations o rev ieee80211_send_action api to enable passing arbitrary data o rev ieee80211_recv_action api to pass the 802.11 frame header as it may be difficult to locate o update existing IEEE80211_ACTION_CAT_BA and IEEE80211_ACTION_CAT_HT handling o update mwl for api rev Reviewed by: rpaulo Approved by: re (kensmith)
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/mwl/if_mwl.c11
-rw-r--r--sys/dev/mwl/if_mwlvar.h3
-rw-r--r--sys/net80211/ieee80211_action.c291
-rw-r--r--sys/net80211/ieee80211_action.h52
-rw-r--r--sys/net80211/ieee80211_adhoc.c2
-rw-r--r--sys/net80211/ieee80211_hostap.c2
-rw-r--r--sys/net80211/ieee80211_ht.c708
-rw-r--r--sys/net80211/ieee80211_ht.h4
-rw-r--r--sys/net80211/ieee80211_sta.c2
-rw-r--r--sys/net80211/ieee80211_var.h7
-rw-r--r--sys/net80211/ieee80211_wds.c2
12 files changed, 726 insertions, 359 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 3108570..fa3f29c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2231,6 +2231,7 @@ net/zlib.c optional crypto | geom_uzip | ipsec | \
ddb_ctf
net80211/ieee80211.c optional wlan
net80211/ieee80211_acl.c optional wlan wlan_acl
+net80211/ieee80211_action.c optional wlan
net80211/ieee80211_adhoc.c optional wlan
net80211/ieee80211_amrr.c optional wlan wlan_amrr
net80211/ieee80211_crypto.c optional wlan
diff --git a/sys/dev/mwl/if_mwl.c b/sys/dev/mwl/if_mwl.c
index ca3c96c..dbbdca7 100644
--- a/sys/dev/mwl/if_mwl.c
+++ b/sys/dev/mwl/if_mwl.c
@@ -144,7 +144,8 @@ static void mwl_tx_proc(void *, int);
static int mwl_chan_set(struct mwl_softc *, struct ieee80211_channel *);
static void mwl_draintxq(struct mwl_softc *);
static void mwl_cleartxq(struct mwl_softc *, struct ieee80211vap *);
-static void mwl_recv_action(struct ieee80211_node *,
+static int mwl_recv_action(struct ieee80211_node *,
+ const struct ieee80211_frame *,
const uint8_t *, const uint8_t *);
static int mwl_addba_request(struct ieee80211_node *,
struct ieee80211_tx_ampdu *, int dialogtoken,
@@ -3656,8 +3657,9 @@ mwl_cleartxq(struct mwl_softc *sc, struct ieee80211vap *vap)
}
}
-static void
-mwl_recv_action(struct ieee80211_node *ni, const uint8_t *frm, const uint8_t *efrm)
+static int
+mwl_recv_action(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
{
struct mwl_softc *sc = ni->ni_ic->ic_ifp->if_softc;
const struct ieee80211_action *ia;
@@ -3671,8 +3673,9 @@ mwl_recv_action(struct ieee80211_node *ni, const uint8_t *frm, const uint8_t *ef
mwl_hal_setmimops(sc->sc_mh, ni->ni_macaddr,
mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA,
MS(mps->am_control, IEEE80211_A_HT_MIMOPWRSAVE_MODE));
+ return 0;
} else
- sc->sc_recv_action(ni, frm, efrm);
+ return sc->sc_recv_action(ni, wh, frm, efrm);
}
static int
diff --git a/sys/dev/mwl/if_mwlvar.h b/sys/dev/mwl/if_mwlvar.h
index 182321a..d69285d 100644
--- a/sys/dev/mwl/if_mwlvar.h
+++ b/sys/dev/mwl/if_mwlvar.h
@@ -289,7 +289,8 @@ struct mwl_softc {
enum ieee80211_state, int);
void (*sc_node_cleanup)(struct ieee80211_node *);
void (*sc_node_drain)(struct ieee80211_node *);
- void (*sc_recv_action)(struct ieee80211_node *,
+ int (*sc_recv_action)(struct ieee80211_node *,
+ const struct ieee80211_frame *,
const uint8_t *, const uint8_t *);
int (*sc_addba_request)(struct ieee80211_node *,
struct ieee80211_tx_ampdu *,
diff --git a/sys/net80211/ieee80211_action.c b/sys/net80211/ieee80211_action.c
new file mode 100644
index 0000000..a694d25
--- /dev/null
+++ b/sys/net80211/ieee80211_action.c
@@ -0,0 +1,291 @@
+/*-
+ * Copyright (c) 2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __FreeBSD__
+__FBSDID("$FreeBSD$");
+#endif
+
+/*
+ * IEEE 802.11 send/recv action frame support.
+ */
+
+#include "opt_inet.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/ethernet.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_action.h>
+
+static int
+send_inval(struct ieee80211_node *ni, int cat, int act, void *sa)
+{
+ return EINVAL;
+}
+
+static ieee80211_send_action_func *ba_send_action[8] = {
+ send_inval, send_inval, send_inval, send_inval,
+ send_inval, send_inval, send_inval, send_inval,
+};
+static ieee80211_send_action_func *ht_send_action[8] = {
+ send_inval, send_inval, send_inval, send_inval,
+ send_inval, send_inval, send_inval, send_inval,
+};
+/* NB: temporary until 802.11s support is added */
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+static ieee80211_send_action_func *meshpl_send_action[8] = {
+ send_inval, send_inval, send_inval, send_inval,
+ send_inval, send_inval, send_inval, send_inval,
+};
+static ieee80211_send_action_func *meshlm_send_action[4] = {
+ send_inval, send_inval, send_inval, send_inval,
+};
+static ieee80211_send_action_func *hwmp_send_action[8] = {
+ send_inval, send_inval, send_inval, send_inval,
+ send_inval, send_inval, send_inval, send_inval,
+};
+#endif
+static ieee80211_send_action_func *vendor_send_action[8] = {
+ send_inval, send_inval, send_inval, send_inval,
+ send_inval, send_inval, send_inval, send_inval,
+};
+
+int
+ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ switch (cat) {
+ case IEEE80211_ACTION_CAT_BA:
+ if (act >= N(ba_send_action))
+ break;
+ ba_send_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_HT:
+ if (act >= N(ht_send_action))
+ break;
+ ht_send_action[act] = f;
+ return 0;
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ if (act >= N(meshpl_send_action))
+ break;
+ meshpl_send_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_MESHLMETRIC:
+ if (act >= N(meshlm_send_action))
+ break;
+ meshlm_send_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_MESHPATH:
+ if (act > N(hwmp_send_action))
+ break;
+ hwmp_send_action[act] = f;
+ return 0;
+#endif
+ case IEEE80211_ACTION_CAT_VENDOR:
+ if (act >= N(vendor_send_action))
+ break;
+ vendor_send_action[act] = f;
+ return 0;
+ }
+ return EINVAL;
+#undef N
+}
+
+void
+ieee80211_send_action_unregister(int cat, int act)
+{
+ ieee80211_send_action_register(cat, act, send_inval);
+}
+
+int
+ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ ieee80211_send_action_func *f = send_inval;
+
+ switch (cat) {
+ case IEEE80211_ACTION_CAT_BA:
+ if (act < N(ba_send_action))
+ f = ba_send_action[act];
+ break;
+ case IEEE80211_ACTION_CAT_HT:
+ if (act < N(ht_send_action))
+ f = ht_send_action[act];
+ break;
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ if (act < N(meshpl_send_action))
+ f = meshpl_send_action[act];
+ break;
+ case IEEE80211_ACTION_CAT_MESHLMETRIC:
+ if (act < N(meshlm_send_action))
+ f = meshlm_send_action[act];
+ break;
+ case IEEE80211_ACTION_CAT_MESHPATH:
+ if (act < N(hwmp_send_action))
+ f = hwmp_send_action[act];
+ break;
+#endif
+ case IEEE80211_ACTION_CAT_VENDOR:
+ if (act < N(vendor_send_action))
+ f = vendor_send_action[act];
+ break;
+ }
+ return f(ni, cat, act, sa);
+#undef N
+}
+
+static int
+recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ return EINVAL;
+}
+
+static ieee80211_recv_action_func *ba_recv_action[8] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+static ieee80211_recv_action_func *ht_recv_action[8] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+static ieee80211_recv_action_func *meshpl_recv_action[8] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+static ieee80211_recv_action_func *meshlm_recv_action[4] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+static ieee80211_recv_action_func *hwmp_recv_action[8] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+#endif
+static ieee80211_recv_action_func *vendor_recv_action[8] = {
+ recv_inval, recv_inval, recv_inval, recv_inval,
+ recv_inval, recv_inval, recv_inval, recv_inval,
+};
+
+int
+ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ switch (cat) {
+ case IEEE80211_ACTION_CAT_BA:
+ if (act >= N(ba_recv_action))
+ break;
+ ba_recv_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_HT:
+ if (act >= N(ht_recv_action))
+ break;
+ ht_recv_action[act] = f;
+ return 0;
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ if (act >= N(meshpl_recv_action))
+ break;
+ meshpl_recv_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_MESHLMETRIC:
+ if (act >= N(meshlm_recv_action))
+ break;
+ meshlm_recv_action[act] = f;
+ return 0;
+ case IEEE80211_ACTION_CAT_MESHPATH:
+ if (act >= N(hwmp_recv_action))
+ break;
+ hwmp_recv_action[act] = f;
+ return 0;
+#endif
+ case IEEE80211_ACTION_CAT_VENDOR:
+ if (act >= N(vendor_recv_action))
+ break;
+ vendor_recv_action[act] = f;
+ return 0;
+ }
+ return EINVAL;
+#undef N
+}
+
+void
+ieee80211_recv_action_unregister(int cat, int act)
+{
+ ieee80211_recv_action_register(cat, act, recv_inval);
+}
+
+int
+ieee80211_recv_action(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ ieee80211_recv_action_func *f = recv_inval;
+ const struct ieee80211_action *ia =
+ (const struct ieee80211_action *) frm;
+
+ switch (ia->ia_category) {
+ case IEEE80211_ACTION_CAT_BA:
+ if (ia->ia_action < N(ba_recv_action))
+ f = ba_recv_action[ia->ia_action];
+ break;
+ case IEEE80211_ACTION_CAT_HT:
+ if (ia->ia_action < N(ht_recv_action))
+ f = ht_recv_action[ia->ia_action];
+ break;
+#ifdef IEEE80211_ACTION_CAT_MESHPEERING
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ if (ia->ia_action < N(meshpl_recv_action))
+ f = meshpl_recv_action[ia->ia_action];
+ break;
+ case IEEE80211_ACTION_CAT_MESHLMETRIC:
+ if (ia->ia_action < N(meshlm_recv_action))
+ f = meshlm_recv_action[ia->ia_action];
+ break;
+ case IEEE80211_ACTION_CAT_MESHPATH:
+ if (ia->ia_action < N(hwmp_recv_action))
+ f = hwmp_recv_action[ia->ia_action];
+ break;
+#endif
+ case IEEE80211_ACTION_CAT_VENDOR:
+ if (ia->ia_action < N(vendor_recv_action))
+ f = vendor_recv_action[ia->ia_action];
+ break;
+ }
+ return f(ni, wh, frm, efrm);
+#undef N
+}
diff --git a/sys/net80211/ieee80211_action.h b/sys/net80211/ieee80211_action.h
new file mode 100644
index 0000000..4ee2aff
--- /dev/null
+++ b/sys/net80211/ieee80211_action.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef _NET80211_IEEE80211_ACTION_H_
+#define _NET80211_IEEE80211_ACTION_H_
+
+/*
+ * 802.11 send/recv action frame support.
+ */
+
+struct ieee80211_node;
+struct ieee80211_frame;
+
+typedef int ieee80211_send_action_func(struct ieee80211_node *,
+ int, int, void *);
+int ieee80211_send_action_register(int cat, int act,
+ ieee80211_send_action_func *f);
+void ieee80211_send_action_unregister(int cat, int act);
+int ieee80211_send_action(struct ieee80211_node *, int, int, void *);
+
+typedef int ieee80211_recv_action_func(struct ieee80211_node *,
+ const struct ieee80211_frame *, const uint8_t *, const uint8_t *);
+int ieee80211_recv_action_register(int cat, int act,
+ ieee80211_recv_action_func *);
+void ieee80211_recv_action_unregister(int cat, int act);
+int ieee80211_recv_action(struct ieee80211_node *,
+ const struct ieee80211_frame *,
+ const uint8_t *, const uint8_t *);
+#endif /* _NET80211_IEEE80211_ACTION_H_ */
diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c
index ed3f6f8..8055890 100644
--- a/sys/net80211/ieee80211_adhoc.c
+++ b/sys/net80211/ieee80211_adhoc.c
@@ -879,7 +879,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
}
break;
}
- ic->ic_recv_action(ni, frm, efrm);
+ ic->ic_recv_action(ni, wh, frm, efrm);
break;
}
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index 3c5bb78..240ea7c 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -2189,7 +2189,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_ACTION:
if (vap->iv_state == IEEE80211_S_RUN) {
if (ieee80211_parse_action(ni, m0) == 0)
- ic->ic_recv_action(ni, frm, efrm);
+ ic->ic_recv_action(ni, wh, frm, efrm);
} else
vap->iv_stats.is_rx_mgtdiscard++;
break;
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 182d052..2ce1b92 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_action.h>
#include <net80211/ieee80211_input.h>
/* define here, used throughout file */
@@ -104,20 +105,52 @@ SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW,
static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
static int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
-/*
- * Setup HT parameters that depends on the clock frequency.
- */
+static ieee80211_recv_action_func ht_recv_action_ba_addba_request;
+static ieee80211_recv_action_func ht_recv_action_ba_addba_response;
+static ieee80211_recv_action_func ht_recv_action_ba_delba;
+static ieee80211_recv_action_func ht_recv_action_ht_mimopwrsave;
+static ieee80211_recv_action_func ht_recv_action_ht_txchwidth;
+
+static ieee80211_send_action_func ht_send_action_ba_addba;
+static ieee80211_send_action_func ht_send_action_ba_delba;
+static ieee80211_send_action_func ht_send_action_ht_txchwidth;
+
static void
-ieee80211_ht_setup(void)
+ieee80211_ht_init(void)
{
+ /*
+ * Setup HT parameters that depends on the clock frequency.
+ */
#ifdef IEEE80211_AMPDU_AGE
ieee80211_ampdu_age = msecs_to_ticks(500);
#endif
ieee80211_addba_timeout = msecs_to_ticks(250);
ieee80211_addba_backoff = msecs_to_ticks(10*1000);
ieee80211_bar_timeout = msecs_to_ticks(250);
-}
-SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
+ /*
+ * Register action frame handlers.
+ */
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_recv_action_ba_addba_request);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_recv_action_ba_addba_response);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_DELBA, ht_recv_action_ba_delba);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
+ IEEE80211_ACTION_HT_MIMOPWRSAVE, ht_recv_action_ht_mimopwrsave);
+ ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
+ IEEE80211_ACTION_HT_TXCHWIDTH, ht_recv_action_ht_txchwidth);
+
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_send_action_ba_addba);
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_send_action_ba_addba);
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_DELBA, ht_send_action_ba_delba);
+ ieee80211_send_action_register(IEEE80211_ACTION_CAT_HT,
+ IEEE80211_ACTION_HT_TXCHWIDTH, ht_send_action_ht_txchwidth);
+}
+SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap);
@@ -129,8 +162,6 @@ static int ieee80211_addba_response(struct ieee80211_node *ni,
int code, int baparamset, int batimeout);
static void ieee80211_addba_stop(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap);
-static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
- const uint8_t *frm, const uint8_t *efrm);
static void ieee80211_bar_response(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap, int status);
static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
@@ -143,7 +174,7 @@ void
ieee80211_ht_attach(struct ieee80211com *ic)
{
/* setup default aggregation policy */
- ic->ic_recv_action = ieee80211_aggr_recv_action;
+ ic->ic_recv_action = ieee80211_recv_action;
ic->ic_send_action = ieee80211_send_action;
ic->ic_ampdu_enable = ieee80211_ampdu_enable;
ic->ic_addba_request = ieee80211_addba_request;
@@ -1580,247 +1611,221 @@ ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
* update our aggregation state. All other frames are passed up
* for processing by ieee80211_recv_action.
*/
-static void
-ieee80211_aggr_recv_action(struct ieee80211_node *ni,
+static int
+ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
- const struct ieee80211_action *ia;
struct ieee80211_rx_ampdu *rap;
+ uint8_t dialogtoken;
+ uint16_t baparamset, batimeout, baseqctl;
+ uint16_t args[4];
+ int tid;
+
+ dialogtoken = frm[2];
+ baparamset = LE_READ_2(frm+3);
+ batimeout = LE_READ_2(frm+5);
+ baseqctl = LE_READ_2(frm+7);
+
+ tid = MS(baparamset, IEEE80211_BAPS_TID);
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "recv ADDBA request: dialogtoken %u baparamset 0x%x "
+ "(tid %d bufsiz %d) batimeout %d baseqctl %d:%d",
+ dialogtoken, baparamset,
+ tid, MS(baparamset, IEEE80211_BAPS_BUFSIZ),
+ batimeout,
+ MS(baseqctl, IEEE80211_BASEQ_START),
+ MS(baseqctl, IEEE80211_BASEQ_FRAG));
+
+ rap = &ni->ni_rx_ampdu[tid];
+
+ /* Send ADDBA response */
+ args[0] = dialogtoken;
+ /*
+ * NB: We ack only if the sta associated with HT and
+ * the ap is configured to do AMPDU rx (the latter
+ * violates the 11n spec and is mostly for testing).
+ */
+ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
+ (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
+ /* XXX handle ampdu_rx_start failure */
+ ic->ic_ampdu_rx_start(ni, rap,
+ baparamset, batimeout, baseqctl);
+
+ args[1] = IEEE80211_STATUS_SUCCESS;
+ } else {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
+ ni, "reject ADDBA request: %s",
+ ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
+ "administratively disabled" :
+ "not negotiated for station");
+ vap->iv_stats.is_addba_reject++;
+ args[1] = IEEE80211_STATUS_UNSPECIFIED;
+ }
+ /* XXX honor rap flags? */
+ args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
+ | SM(tid, IEEE80211_BAPS_TID)
+ | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
+ ;
+ args[3] = 0;
+ ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
+ IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
+ return 0;
+}
+
+static int
+ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tx_ampdu *tap;
uint8_t dialogtoken, policy;
- uint16_t baparamset, batimeout, baseqctl, code;
- uint16_t args[4];
+ uint16_t baparamset, batimeout, code;
int tid, ac, bufsiz;
- ia = (const struct ieee80211_action *) frm;
- switch (ia->ia_category) {
- case IEEE80211_ACTION_CAT_BA:
- switch (ia->ia_action) {
- case IEEE80211_ACTION_BA_ADDBA_REQUEST:
- dialogtoken = frm[2];
- baparamset = LE_READ_2(frm+3);
- batimeout = LE_READ_2(frm+5);
- baseqctl = LE_READ_2(frm+7);
-
- tid = MS(baparamset, IEEE80211_BAPS_TID);
+ dialogtoken = frm[2];
+ code = LE_READ_2(frm+3);
+ baparamset = LE_READ_2(frm+5);
+ tid = MS(baparamset, IEEE80211_BAPS_TID);
+ bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
+ policy = MS(baparamset, IEEE80211_BAPS_POLICY);
+ batimeout = LE_READ_2(frm+7);
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "recv ADDBA request: dialogtoken %u "
- "baparamset 0x%x (tid %d bufsiz %d) batimeout %d "
- "baseqctl %d:%d",
- dialogtoken, baparamset,
- tid, MS(baparamset, IEEE80211_BAPS_BUFSIZ),
- batimeout,
- MS(baseqctl, IEEE80211_BASEQ_START),
- MS(baseqctl, IEEE80211_BASEQ_FRAG));
-
- rap = &ni->ni_rx_ampdu[tid];
-
- /* Send ADDBA response */
- args[0] = dialogtoken;
- /*
- * NB: We ack only if the sta associated with HT and
- * the ap is configured to do AMPDU rx (the latter
- * violates the 11n spec and is mostly for testing).
- */
- if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
- (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
- /* XXX handle ampdu_rx_start failure */
- ic->ic_ampdu_rx_start(ni, rap,
- baparamset, batimeout, baseqctl);
-
- args[1] = IEEE80211_STATUS_SUCCESS;
- } else {
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni, "reject ADDBA request: %s",
- ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
- "administratively disabled" :
- "not negotiated for station");
- vap->iv_stats.is_addba_reject++;
- args[1] = IEEE80211_STATUS_UNSPECIFIED;
- }
- /* XXX honor rap flags? */
- args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
- | SM(tid, IEEE80211_BAPS_TID)
- | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
- ;
- args[3] = 0;
- ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
- IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
- return;
-
- case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
- dialogtoken = frm[2];
- code = LE_READ_2(frm+3);
- baparamset = LE_READ_2(frm+5);
- tid = MS(baparamset, IEEE80211_BAPS_TID);
- bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
- policy = MS(baparamset, IEEE80211_BAPS_POLICY);
- batimeout = LE_READ_2(frm+7);
-
- ac = TID_TO_WME_AC(tid);
- tap = &ni->ni_tx_ampdu[ac];
- if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni->ni_macaddr, "ADDBA response",
- "no pending ADDBA, tid %d dialogtoken %u "
- "code %d", tid, dialogtoken, code);
- vap->iv_stats.is_addba_norequest++;
- return;
- }
- if (dialogtoken != tap->txa_token) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni->ni_macaddr, "ADDBA response",
- "dialogtoken mismatch: waiting for %d, "
- "received %d, tid %d code %d",
- tap->txa_token, dialogtoken, tid, code);
- vap->iv_stats.is_addba_badtoken++;
- return;
- }
- /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
- if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni->ni_macaddr, "ADDBA response",
- "policy mismatch: expecting %s, "
- "received %s, tid %d code %d",
- tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
- policy, tid, code);
- vap->iv_stats.is_addba_badpolicy++;
- return;
- }
+ ac = TID_TO_WME_AC(tid);
+ tap = &ni->ni_tx_ampdu[ac];
+ if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
+ ni->ni_macaddr, "ADDBA response",
+ "no pending ADDBA, tid %d dialogtoken %u "
+ "code %d", tid, dialogtoken, code);
+ vap->iv_stats.is_addba_norequest++;
+ return 0;
+ }
+ if (dialogtoken != tap->txa_token) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
+ ni->ni_macaddr, "ADDBA response",
+ "dialogtoken mismatch: waiting for %d, "
+ "received %d, tid %d code %d",
+ tap->txa_token, dialogtoken, tid, code);
+ vap->iv_stats.is_addba_badtoken++;
+ return 0;
+ }
+ /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
+ if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
+ ni->ni_macaddr, "ADDBA response",
+ "policy mismatch: expecting %s, "
+ "received %s, tid %d code %d",
+ tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
+ policy, tid, code);
+ vap->iv_stats.is_addba_badpolicy++;
+ return 0;
+ }
#if 0
- /* XXX we take MIN in ieee80211_addba_response */
- if (bufsiz > IEEE80211_AGGR_BAWMAX) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni->ni_macaddr, "ADDBA response",
- "BA window too large: max %d, "
- "received %d, tid %d code %d",
- bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
- vap->iv_stats.is_addba_badbawinsize++;
- return;
- }
+ /* XXX we take MIN in ieee80211_addba_response */
+ if (bufsiz > IEEE80211_AGGR_BAWMAX) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
+ ni->ni_macaddr, "ADDBA response",
+ "BA window too large: max %d, "
+ "received %d, tid %d code %d",
+ bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
+ vap->iv_stats.is_addba_badbawinsize++;
+ return 0;
+ }
#endif
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "recv ADDBA response: dialogtoken %u code %d "
- "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
- dialogtoken, code, baparamset, tid, bufsiz,
- batimeout);
- ic->ic_addba_response(ni, tap,
- code, baparamset, batimeout);
- return;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "recv ADDBA response: dialogtoken %u code %d "
+ "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
+ dialogtoken, code, baparamset, tid, bufsiz,
+ batimeout);
+ ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
+ return 0;
+}
+
+static int
+ht_recv_action_ba_delba(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_rx_ampdu *rap;
+ struct ieee80211_tx_ampdu *tap;
+ uint16_t baparamset, code;
+ int tid, ac;
- case IEEE80211_ACTION_BA_DELBA:
- baparamset = LE_READ_2(frm+2);
- code = LE_READ_2(frm+4);
+ baparamset = LE_READ_2(frm+2);
+ code = LE_READ_2(frm+4);
- tid = MS(baparamset, IEEE80211_DELBAPS_TID);
+ tid = MS(baparamset, IEEE80211_DELBAPS_TID);
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
- "code %d", baparamset, tid,
- MS(baparamset, IEEE80211_DELBAPS_INIT), code);
-
- if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
- ac = TID_TO_WME_AC(tid);
- tap = &ni->ni_tx_ampdu[ac];
- ic->ic_addba_stop(ni, tap);
- } else {
- rap = &ni->ni_rx_ampdu[tid];
- ic->ic_ampdu_rx_stop(ni, rap);
- }
- return;
- }
- break;
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
+ "code %d", baparamset, tid,
+ MS(baparamset, IEEE80211_DELBAPS_INIT), code);
+
+ if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
+ ac = TID_TO_WME_AC(tid);
+ tap = &ni->ni_tx_ampdu[ac];
+ ic->ic_addba_stop(ni, tap);
+ } else {
+ rap = &ni->ni_rx_ampdu[tid];
+ ic->ic_ampdu_rx_stop(ni, rap);
}
- ieee80211_recv_action(ni, frm, efrm);
+ return 0;
}
-/*
- * Process a received 802.11n action frame.
- * Aggregation-related frames are assumed to be handled
- * already; we handle any other frames we can, otherwise
- * complain about being unsupported (with debugging).
- */
-void
-ieee80211_recv_action(struct ieee80211_node *ni,
+static int
+ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
const uint8_t *frm, const uint8_t *efrm)
{
- struct ieee80211vap *vap = ni->ni_vap;
- const struct ieee80211_action *ia;
int chw;
- ia = (const struct ieee80211_action *) frm;
- switch (ia->ia_category) {
- case IEEE80211_ACTION_CAT_BA:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: BA action %d not implemented", __func__,
- ia->ia_action);
- vap->iv_stats.is_rx_mgtdiscard++;
- break;
- case IEEE80211_ACTION_CAT_HT:
- switch (ia->ia_action) {
- case IEEE80211_ACTION_HT_TXCHWIDTH:
- chw = frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040 ? 40 : 20;
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: HT txchwidth, width %d%s",
- __func__, chw, ni->ni_chw != chw ? "*" : "");
- if (chw != ni->ni_chw) {
- ni->ni_chw = chw;
- /* XXX notify on change */
- }
- break;
- case IEEE80211_ACTION_HT_MIMOPWRSAVE: {
- const struct ieee80211_action_ht_mimopowersave *mps =
- (const struct ieee80211_action_ht_mimopowersave *) ia;
- /* XXX check iv_htcaps */
- if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
- ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
- else
- ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
- if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
- ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
- else
- ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
- /* XXX notify on change */
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: HT MIMO PS (%s%s)", __func__,
- (ni->ni_flags & IEEE80211_NODE_MIMO_PS) ?
- "on" : "off",
- (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ?
- "+rts" : ""
- );
- break;
- }
- default:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: HT action %d not implemented", __func__,
- ia->ia_action);
- vap->iv_stats.is_rx_mgtdiscard++;
- break;
- }
- break;
- default:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: category %d not implemented", __func__,
- ia->ia_category);
- vap->iv_stats.is_rx_mgtdiscard++;
- break;
+ chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ? 40 : 20;
+
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "%s: HT txchwidth, width %d%s",
+ __func__, chw, ni->ni_chw != chw ? "*" : "");
+ if (chw != ni->ni_chw) {
+ ni->ni_chw = chw;
+ /* XXX notify on change */
}
+ return 0;
+}
+
+static int
+ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
+ const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ const struct ieee80211_action_ht_mimopowersave *mps =
+ (const struct ieee80211_action_ht_mimopowersave *) frm;
+
+ /* XXX check iv_htcaps */
+ if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
+ ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
+ else
+ ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
+ if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
+ ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
+ else
+ ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
+ /* XXX notify on change */
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "%s: HT MIMO PS (%s%s)", __func__,
+ (ni->ni_flags & IEEE80211_NODE_MIMO_PS) ? "on" : "off",
+ (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ? "+rts" : ""
+ );
+ return 0;
}
/*
@@ -1937,7 +1942,7 @@ ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
args[0] = WME_AC_TO_TID(tap->txa_ac);
args[1] = IEEE80211_DELBAPS_INIT;
args[2] = reason; /* XXX reason code */
- ieee80211_send_action(ni, IEEE80211_ACTION_CAT_BA,
+ ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
IEEE80211_ACTION_BA_DELBA, args);
} else {
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
@@ -2115,143 +2120,160 @@ bad:
#undef senderr
}
-/*
- * Send an action management frame. The arguments are stuff
- * into a frame without inspection; the caller is assumed to
- * prepare them carefully (e.g. based on the aggregation state).
- */
-int
-ieee80211_send_action(struct ieee80211_node *ni,
- int category, int action, uint16_t args[4])
+static int
+ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
{
-#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
+ struct ieee80211_bpf_params params;
+
+ memset(&params, 0, sizeof(params));
+ params.ibp_pri = WME_AC_VO;
+ params.ibp_rate0 = ni->ni_txparms->mgmtrate;
+ /* NB: we know all frames are unicast */
+ params.ibp_try0 = ni->ni_txparms->maxretry;
+ params.ibp_power = ni->ni_txpower;
+ return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
+ &params);
+}
+
#define ADDSHORT(frm, v) do { \
frm[0] = (v) & 0xff; \
frm[1] = (v) >> 8; \
frm += 2; \
} while (0)
+
+/*
+ * Send an action management frame. The arguments are stuff
+ * into a frame without inspection; the caller is assumed to
+ * prepare them carefully (e.g. based on the aggregation state).
+ */
+static int
+ht_send_action_ba_addba(struct ieee80211_node *ni,
+ int category, int action, void *arg0)
+{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
- struct ieee80211_bpf_params params;
+ uint16_t *args = arg0;
struct mbuf *m;
uint8_t *frm;
- uint16_t baparamset;
- int ret;
- KASSERT(ni != NULL, ("null node"));
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "send ADDBA %s: dialogtoken %d "
+ "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
+ (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
+ "request" : "response",
+ args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
+ args[2], args[3]);
- /*
- * Hold a reference on the node so it doesn't go away until after
- * the xmit is complete all the way in the driver. On error we
- * will remove our reference.
- */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
- "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
- __func__, __LINE__,
- ni, ether_sprintf(ni->ni_macaddr),
- ieee80211_node_refcnt(ni)+1);
+ "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
+ ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
ieee80211_ref_node(ni);
m = ieee80211_getmgtframe(&frm,
- ic->ic_headroom + sizeof(struct ieee80211_frame),
- sizeof(uint16_t) /* action+category */
- /* XXX may action payload */
- + sizeof(struct ieee80211_action_ba_addbaresponse)
+ ic->ic_headroom + sizeof(struct ieee80211_frame),
+ sizeof(uint16_t) /* action+category */
+ /* XXX may action payload */
+ + sizeof(struct ieee80211_action_ba_addbaresponse)
);
- if (m == NULL)
- senderr(ENOMEM, is_tx_nobuf);
-
- *frm++ = category;
- *frm++ = action;
- switch (category) {
- case IEEE80211_ACTION_CAT_BA:
- switch (action) {
- case IEEE80211_ACTION_BA_ADDBA_REQUEST:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "send ADDBA request: dialogtoken %d "
- "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
- args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
- args[2], args[3]);
-
- *frm++ = args[0]; /* dialog token */
- ADDSHORT(frm, args[1]); /* baparamset */
- ADDSHORT(frm, args[2]); /* batimeout */
+ if (m != NULL) {
+ *frm++ = category;
+ *frm++ = action;
+ *frm++ = args[0]; /* dialog token */
+ ADDSHORT(frm, args[1]); /* baparamset */
+ ADDSHORT(frm, args[2]); /* batimeout */
+ if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
ADDSHORT(frm, args[3]); /* baseqctl */
- break;
- case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "send ADDBA response: dialogtoken %d status %d "
- "baparamset 0x%x (tid %d) batimeout %d",
- args[0], args[1], args[2],
- MS(args[2], IEEE80211_BAPS_TID), args[3]);
-
- *frm++ = args[0]; /* dialog token */
- ADDSHORT(frm, args[1]); /* statuscode */
- ADDSHORT(frm, args[2]); /* baparamset */
- ADDSHORT(frm, args[3]); /* batimeout */
- break;
- case IEEE80211_ACTION_BA_DELBA:
- /* XXX */
- baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
- | args[1]
- ;
- ADDSHORT(frm, baparamset);
- ADDSHORT(frm, args[2]); /* reason code */
+ m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
+ return ht_action_output(ni, m);
+ } else {
+ vap->iv_stats.is_tx_nobuf++;
+ ieee80211_free_node(ni);
+ return ENOMEM;
+ }
+}
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "send DELBA action: tid %d, initiator %d reason %d",
- args[0], args[1], args[2]);
- break;
- default:
- goto badaction;
- }
- break;
- case IEEE80211_ACTION_CAT_HT:
- switch (action) {
- case IEEE80211_ACTION_HT_TXCHWIDTH:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
- ni, "send HT txchwidth: width %d",
- IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20
- );
- *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
- IEEE80211_A_HT_TXCHWIDTH_2040 :
- IEEE80211_A_HT_TXCHWIDTH_20;
- break;
- default:
- goto badaction;
- }
- break;
- default:
- badaction:
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
- "%s: unsupported category %d action %d", __func__,
- category, action);
- senderr(EINVAL, is_tx_unknownmgt);
- /* NOTREACHED */
+static int
+ht_send_action_ba_delba(struct ieee80211_node *ni,
+ int category, int action, void *arg0)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
+ uint16_t *args = arg0;
+ struct mbuf *m;
+ uint16_t baparamset;
+ uint8_t *frm;
+
+ baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
+ | args[1]
+ ;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "send DELBA action: tid %d, initiator %d reason %d",
+ args[0], args[1], args[2]);
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
+ ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
+ ieee80211_ref_node(ni);
+
+ m = ieee80211_getmgtframe(&frm,
+ ic->ic_headroom + sizeof(struct ieee80211_frame),
+ sizeof(uint16_t) /* action+category */
+ /* XXX may action payload */
+ + sizeof(struct ieee80211_action_ba_addbaresponse)
+ );
+ if (m != NULL) {
+ *frm++ = category;
+ *frm++ = action;
+ ADDSHORT(frm, baparamset);
+ ADDSHORT(frm, args[2]); /* reason code */
+ m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
+ return ht_action_output(ni, m);
+ } else {
+ vap->iv_stats.is_tx_nobuf++;
+ ieee80211_free_node(ni);
+ return ENOMEM;
}
- m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
+}
- memset(&params, 0, sizeof(params));
- params.ibp_pri = WME_AC_VO;
- params.ibp_rate0 = ni->ni_txparms->mgmtrate;
- /* NB: we know all frames are unicast */
- params.ibp_try0 = ni->ni_txparms->maxretry;
- params.ibp_power = ni->ni_txpower;
- return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
- &params);
-bad:
- ieee80211_free_node(ni);
- if (m != NULL)
- m_freem(m);
- return ret;
-#undef ADDSHORT
-#undef senderr
+static int
+ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
+ int category, int action, void *arg0)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct mbuf *m;
+ uint8_t *frm;
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
+ "send HT txchwidth: width %d",
+ IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
+ ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
+ ieee80211_ref_node(ni);
+
+ m = ieee80211_getmgtframe(&frm,
+ ic->ic_headroom + sizeof(struct ieee80211_frame),
+ sizeof(uint16_t) /* action+category */
+ /* XXX may action payload */
+ + sizeof(struct ieee80211_action_ba_addbaresponse)
+ );
+ if (m != NULL) {
+ *frm++ = category;
+ *frm++ = action;
+ *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
+ IEEE80211_A_HT_TXCHWIDTH_2040 :
+ IEEE80211_A_HT_TXCHWIDTH_20;
+ m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
+ return ht_action_output(ni, m);
+ } else {
+ vap->iv_stats.is_tx_nobuf++;
+ ieee80211_free_node(ni);
+ return ENOMEM;
+ }
}
+#undef ADDSHORT
/*
* Construct the MCS bit mask for inclusion
diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h
index f1ed36b..7b0eab7 100644
--- a/sys/net80211/ieee80211_ht.h
+++ b/sys/net80211/ieee80211_ht.h
@@ -186,16 +186,12 @@ void ieee80211_parse_htinfo(struct ieee80211_node *, const uint8_t *);
void ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
const uint8_t *);
void ieee80211_ht_updatehtcap(struct ieee80211_node *, const uint8_t *);
-void ieee80211_recv_action(struct ieee80211_node *,
- const uint8_t *, const uint8_t *);
int ieee80211_ampdu_request(struct ieee80211_node *,
struct ieee80211_tx_ampdu *);
void ieee80211_ampdu_stop(struct ieee80211_node *,
struct ieee80211_tx_ampdu *, int);
int ieee80211_send_bar(struct ieee80211_node *, struct ieee80211_tx_ampdu *,
ieee80211_seq);
-int ieee80211_send_action(struct ieee80211_node *,
- int, int, uint16_t [4]);
uint8_t *ieee80211_add_htcap(uint8_t *, struct ieee80211_node *);
uint8_t *ieee80211_add_htcap_vendor(uint8_t *, struct ieee80211_node *);
uint8_t *ieee80211_add_htinfo(uint8_t *, struct ieee80211_node *);
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 3b0c13b..fe8c9fa 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1717,7 +1717,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_ACTION:
if (vap->iv_state == IEEE80211_S_RUN) {
if (ieee80211_parse_action(ni, m0) == 0)
- ic->ic_recv_action(ni, frm, efrm);
+ ic->ic_recv_action(ni, wh, frm, efrm);
} else
vap->iv_stats.is_rx_mgtdiscard++;
break;
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index d0cfe9f..8859c2f 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -112,6 +112,7 @@ struct ieee80211_rate_table;
struct ieee80211_tx_ampdu;
struct ieee80211_rx_ampdu;
struct ieee80211_superg;
+struct ieee80211_frame;
struct ieee80211com {
struct ifnet *ic_ifp; /* associated device */
@@ -282,11 +283,11 @@ struct ieee80211com {
* driver passes out-of-order frames to ieee80211_input
* from an assocated HT station.
*/
- void (*ic_recv_action)(struct ieee80211_node *,
+ int (*ic_recv_action)(struct ieee80211_node *,
+ const struct ieee80211_frame *,
const uint8_t *frm, const uint8_t *efrm);
int (*ic_send_action)(struct ieee80211_node *,
- int category, int action,
- uint16_t args[4]);
+ int category, int action, void *);
/* check if A-MPDU should be enabled this station+ac */
int (*ic_ampdu_enable)(struct ieee80211_node *,
struct ieee80211_tx_ampdu *);
diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c
index 78529ed..18c4544 100644
--- a/sys/net80211/ieee80211_wds.c
+++ b/sys/net80211/ieee80211_wds.c
@@ -838,7 +838,7 @@ wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
}
ni->ni_inact = ni->ni_inact_reload;
if (ieee80211_parse_action(ni, m0) == 0)
- ic->ic_recv_action(ni, frm, efrm);
+ ic->ic_recv_action(ni, wh, frm, efrm);
break;
default:
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
OpenPOWER on IntegriCloud