Date: Sun, 5 Jul 2009 17:59:19 +0000 (UTC) From: Sam Leffler <sam@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r195377 - in head/sys: conf dev/mwl net80211 Message-ID: <200907051759.n65HxJ3v056078@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: sam Date: Sun Jul 5 17:59:19 2009 New Revision: 195377 URL: http://svn.freebsd.org/changeset/base/195377 Log: 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) Added: head/sys/net80211/ieee80211_action.c (contents, props changed) head/sys/net80211/ieee80211_action.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/mwl/if_mwl.c head/sys/dev/mwl/if_mwlvar.h head/sys/net80211/ieee80211_adhoc.c head/sys/net80211/ieee80211_hostap.c head/sys/net80211/ieee80211_ht.c head/sys/net80211/ieee80211_ht.h head/sys/net80211/ieee80211_sta.c head/sys/net80211/ieee80211_var.h head/sys/net80211/ieee80211_wds.c Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/conf/files Sun Jul 5 17:59:19 2009 (r195377) @@ -2231,6 +2231,7 @@ net/zlib.c optional crypto | geom_uzip 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 Modified: head/sys/dev/mwl/if_mwl.c ============================================================================== --- head/sys/dev/mwl/if_mwl.c Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/dev/mwl/if_mwl.c Sun Jul 5 17:59:19 2009 (r195377) @@ -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, struc } } -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 *n 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 Modified: head/sys/dev/mwl/if_mwlvar.h ============================================================================== --- head/sys/dev/mwl/if_mwlvar.h Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/dev/mwl/if_mwlvar.h Sun Jul 5 17:59:19 2009 (r195377) @@ -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 *, Added: head/sys/net80211/ieee80211_action.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/net80211/ieee80211_action.c Sun Jul 5 17:59:19 2009 (r195377) @@ -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 +} Added: head/sys/net80211/ieee80211_action.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/net80211/ieee80211_action.h Sun Jul 5 17:59:19 2009 (r195377) @@ -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_ */ Modified: head/sys/net80211/ieee80211_adhoc.c ============================================================================== --- head/sys/net80211/ieee80211_adhoc.c Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/net80211/ieee80211_adhoc.c Sun Jul 5 17:59:19 2009 (r195377) @@ -879,7 +879,7 @@ adhoc_recv_mgmt(struct ieee80211_node *n } break; } - ic->ic_recv_action(ni, frm, efrm); + ic->ic_recv_action(ni, wh, frm, efrm); break; } Modified: head/sys/net80211/ieee80211_hostap.c ============================================================================== --- head/sys/net80211/ieee80211_hostap.c Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/net80211/ieee80211_hostap.c Sun Jul 5 17:59:19 2009 (r195377) @@ -2189,7 +2189,7 @@ hostap_recv_mgmt(struct ieee80211_node * 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; Modified: head/sys/net80211/ieee80211_ht.c ============================================================================== --- head/sys/net80211/ieee80211_ht.c Sun Jul 5 17:45:48 2009 (r195376) +++ head/sys/net80211/ieee80211_ht.c Sun Jul 5 17:59:19 2009 (r195377) @@ -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_ma 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); + /* + * 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_setup, NULL); +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(stru 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_no * 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; - struct ieee80211_tx_ampdu *tap; - uint8_t dialogtoken, policy; - uint16_t baparamset, batimeout, baseqctl, code; + uint8_t dialogtoken; + uint16_t baparamset, batimeout, baseqctl; uint16_t args[4]; - int tid, ac, bufsiz; + int tid; - 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); + 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)); - tid = MS(baparamset, IEEE80211_BAPS_TID); + rap = &ni->ni_rx_ampdu[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)); + /* 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); - rap = &ni->ni_rx_ampdu[tid]; + 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; +} - /* 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); +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, code; + int tid, ac, bufsiz; - 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; - } + 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 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; - - case IEEE80211_ACTION_BA_DELBA: - baparamset = LE_READ_2(frm+2); - code = LE_READ_2(frm+4); + 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; +} - tid = MS(baparamset, IEEE80211_DELBAPS_TID); +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; - 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; + baparamset = LE_READ_2(frm+2); + code = LE_READ_2(frm+4); + + tid = MS(baparamset, IEEE80211_DELBAPS_TID); + + 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_no 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(¶ms, 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, + ¶ms); +} + #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). *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907051759.n65HxJ3v056078>