diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-06 16:20:21 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-11-11 10:08:08 +0100 |
commit | 66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch) | |
tree | 48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/net80211 | |
parent | Define __GLOBL1() and __GLOBL() (diff) | |
download | rtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2 |
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/net80211')
32 files changed, 1111 insertions, 365 deletions
diff --git a/freebsd/sys/net80211/_ieee80211.h b/freebsd/sys/net80211/_ieee80211.h index c488c006..3793c661 100644 --- a/freebsd/sys/net80211/_ieee80211.h +++ b/freebsd/sys/net80211/_ieee80211.h @@ -133,7 +133,7 @@ enum ieee80211_roamingmode { */ struct ieee80211_channel { uint32_t ic_flags; /* see below */ - uint16_t ic_freq; /* setting in Mhz */ + uint16_t ic_freq; /* setting in MHz */ uint8_t ic_ieee; /* IEEE channel number */ int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */ int8_t ic_maxpower; /* maximum tx power in .5 dBm */ @@ -335,7 +335,7 @@ struct ieee80211_rateset { * the structure such that it can be used interchangeably * with an ieee80211_rateset (modulo structure size). */ -#define IEEE80211_HTRATE_MAXSIZE 127 +#define IEEE80211_HTRATE_MAXSIZE 77 struct ieee80211_htrateset { uint8_t rs_nrates; @@ -387,9 +387,16 @@ struct ieee80211_regdomain { /* * MIMO antenna/radio state. */ + +#define IEEE80211_MAX_CHAINS 3 +#define IEEE80211_MAX_EVM_PILOTS 6 + +/* + * XXX This doesn't yet export both ctl/ext chain details + */ struct ieee80211_mimo_info { - int8_t rssi[3]; /* per-antenna rssi */ - int8_t noise[3]; /* per-antenna noise floor */ + int8_t rssi[IEEE80211_MAX_CHAINS]; /* per-antenna rssi */ + int8_t noise[IEEE80211_MAX_CHAINS]; /* per-antenna noise floor */ uint8_t pad[2]; uint32_t evm[3]; /* EVM data */ }; diff --git a/freebsd/sys/net80211/ieee80211.c b/freebsd/sys/net80211/ieee80211.c index 3d121987..7021ff31 100644 --- a/freebsd/sys/net80211/ieee80211.c +++ b/freebsd/sys/net80211/ieee80211.c @@ -208,6 +208,15 @@ ieee80211_chan_init(struct ieee80211com *ic) DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); /* + * Setup required information to fill the mcsset field, if driver did + * not. Assume a 2T2R setup for historic reasons. + */ + if (ic->ic_rxstream == 0) + ic->ic_rxstream = 2; + if (ic->ic_txstream == 0) + ic->ic_txstream = 2; + + /* * Set auto mode to reset active channel state and any desired channel. */ (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); @@ -377,9 +386,9 @@ default_reset(struct ieee80211vap *vap, u_long cmd) */ int ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, - const char name[IFNAMSIZ], int unit, int opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t macaddr[IEEE80211_ADDR_LEN]) + const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t macaddr[IEEE80211_ADDR_LEN]) { struct ifnet *ifp; @@ -407,6 +416,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, vap->iv_flags_ven = ic->ic_flags_ven; vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE; vap->iv_htcaps = ic->ic_htcaps; + vap->iv_htextcaps = ic->ic_htextcaps; vap->iv_opmode = opmode; vap->iv_caps |= ieee80211_opcap[opmode]; switch (opmode) { @@ -439,6 +449,8 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap, } break; #endif + default: + break; } /* auto-enable s/w beacon miss support */ if (flags & IEEE80211_CLONE_NOBEACONS) @@ -1000,7 +1012,8 @@ ieee80211_media_setup(struct ieee80211com *ic, struct ifmedia *media, int caps, int addsta, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { - int i, j, mode, rate, maxrate, mword, r; + int i, j, rate, maxrate, mword, r; + enum ieee80211_phymode mode; const struct ieee80211_rateset *rs; struct ieee80211_rateset allrates; @@ -1068,10 +1081,18 @@ ieee80211_media_setup(struct ieee80211com *ic, isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { addmedia(media, caps, addsta, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); - /* XXX could walk htrates */ - /* XXX known array size */ - if (ieee80211_htrates[15].ht40_rate_400ns > maxrate) - maxrate = ieee80211_htrates[15].ht40_rate_400ns; + i = ic->ic_txstream * 8 - 1; + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) + rate = ieee80211_htrates[i].ht40_rate_400ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) + rate = ieee80211_htrates[i].ht40_rate_800ns; + else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) + rate = ieee80211_htrates[i].ht20_rate_400ns; + else + rate = ieee80211_htrates[i].ht20_rate_800ns; + if (rate > maxrate) + maxrate = rate; } return maxrate; } @@ -1121,7 +1142,8 @@ void ieee80211_announce(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; - int i, mode, rate, mword; + int i, rate, mword; + enum ieee80211_phymode mode; const struct ieee80211_rateset *rs; /* NB: skip AUTO since it has no rates */ @@ -1514,6 +1536,67 @@ ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode m { 13, IFM_IEEE80211_MCS }, { 14, IFM_IEEE80211_MCS }, { 15, IFM_IEEE80211_MCS }, + { 16, IFM_IEEE80211_MCS }, + { 17, IFM_IEEE80211_MCS }, + { 18, IFM_IEEE80211_MCS }, + { 19, IFM_IEEE80211_MCS }, + { 20, IFM_IEEE80211_MCS }, + { 21, IFM_IEEE80211_MCS }, + { 22, IFM_IEEE80211_MCS }, + { 23, IFM_IEEE80211_MCS }, + { 24, IFM_IEEE80211_MCS }, + { 25, IFM_IEEE80211_MCS }, + { 26, IFM_IEEE80211_MCS }, + { 27, IFM_IEEE80211_MCS }, + { 28, IFM_IEEE80211_MCS }, + { 29, IFM_IEEE80211_MCS }, + { 30, IFM_IEEE80211_MCS }, + { 31, IFM_IEEE80211_MCS }, + { 32, IFM_IEEE80211_MCS }, + { 33, IFM_IEEE80211_MCS }, + { 34, IFM_IEEE80211_MCS }, + { 35, IFM_IEEE80211_MCS }, + { 36, IFM_IEEE80211_MCS }, + { 37, IFM_IEEE80211_MCS }, + { 38, IFM_IEEE80211_MCS }, + { 39, IFM_IEEE80211_MCS }, + { 40, IFM_IEEE80211_MCS }, + { 41, IFM_IEEE80211_MCS }, + { 42, IFM_IEEE80211_MCS }, + { 43, IFM_IEEE80211_MCS }, + { 44, IFM_IEEE80211_MCS }, + { 45, IFM_IEEE80211_MCS }, + { 46, IFM_IEEE80211_MCS }, + { 47, IFM_IEEE80211_MCS }, + { 48, IFM_IEEE80211_MCS }, + { 49, IFM_IEEE80211_MCS }, + { 50, IFM_IEEE80211_MCS }, + { 51, IFM_IEEE80211_MCS }, + { 52, IFM_IEEE80211_MCS }, + { 53, IFM_IEEE80211_MCS }, + { 54, IFM_IEEE80211_MCS }, + { 55, IFM_IEEE80211_MCS }, + { 56, IFM_IEEE80211_MCS }, + { 57, IFM_IEEE80211_MCS }, + { 58, IFM_IEEE80211_MCS }, + { 59, IFM_IEEE80211_MCS }, + { 60, IFM_IEEE80211_MCS }, + { 61, IFM_IEEE80211_MCS }, + { 62, IFM_IEEE80211_MCS }, + { 63, IFM_IEEE80211_MCS }, + { 64, IFM_IEEE80211_MCS }, + { 65, IFM_IEEE80211_MCS }, + { 66, IFM_IEEE80211_MCS }, + { 67, IFM_IEEE80211_MCS }, + { 68, IFM_IEEE80211_MCS }, + { 69, IFM_IEEE80211_MCS }, + { 70, IFM_IEEE80211_MCS }, + { 71, IFM_IEEE80211_MCS }, + { 72, IFM_IEEE80211_MCS }, + { 73, IFM_IEEE80211_MCS }, + { 74, IFM_IEEE80211_MCS }, + { 75, IFM_IEEE80211_MCS }, + { 76, IFM_IEEE80211_MCS }, }; int m; diff --git a/freebsd/sys/net80211/ieee80211.h b/freebsd/sys/net80211/ieee80211.h index e567d9de..9c12ef0c 100644 --- a/freebsd/sys/net80211/ieee80211.h +++ b/freebsd/sys/net80211/ieee80211.h @@ -131,6 +131,7 @@ struct ieee80211_qosframe_addr4 { #define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 #define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 #define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 +#define IEEE80211_FC0_SUBTYPE_ACTION_NOACK 0xe0 /* for TYPE_CTL */ #define IEEE80211_FC0_SUBTYPE_BAR 0x80 #define IEEE80211_FC0_SUBTYPE_BA 0x90 diff --git a/freebsd/sys/net80211/ieee80211_acl.c b/freebsd/sys/net80211/ieee80211_acl.c index 0d26a4e2..3bfb0a30 100644 --- a/freebsd/sys/net80211/ieee80211_acl.c +++ b/freebsd/sys/net80211/ieee80211_acl.c @@ -79,7 +79,7 @@ struct acl { struct aclstate { acl_lock_t as_lock; int as_policy; - int as_nacls; + uint32_t as_nacls; TAILQ_HEAD(, acl) as_list; /* list of all ACL's */ LIST_HEAD(, acl) as_hash[ACL_HASHSIZE]; struct ieee80211vap *as_vap; @@ -89,7 +89,7 @@ struct aclstate { #define ACL_HASH(addr) \ (((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE) -MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl"); +static MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl"); static int acl_free_all(struct ieee80211vap *); @@ -291,7 +291,8 @@ acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq) struct aclstate *as = vap->iv_as; struct acl *acl; struct ieee80211req_maclist *ap; - int error, space, i; + int error; + uint32_t i, space; switch (ireq->i_val) { case IEEE80211_MACCMD_POLICY: diff --git a/freebsd/sys/net80211/ieee80211_adhoc.c b/freebsd/sys/net80211/ieee80211_adhoc.c index b7933a17..4c330976 100644 --- a/freebsd/sys/net80211/ieee80211_adhoc.c +++ b/freebsd/sys/net80211/ieee80211_adhoc.c @@ -287,7 +287,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -414,9 +413,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -662,7 +659,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static int @@ -825,80 +821,44 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0); break; - case IEEE80211_FC0_SUBTYPE_ACTION: { - const struct ieee80211_action *ia; - - if (vap->iv_state != IEEE80211_S_RUN) { + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "wrong state %s", ieee80211_state_name[vap->iv_state]); vap->iv_stats.is_rx_mgtdiscard++; - return; - } - /* - * action frame format: - * [1] category - * [1] action - * [tlv] parameters - */ - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action), return); - ia = (const struct ieee80211_action *) frm; - - vap->iv_stats.is_rx_action++; - IEEE80211_NODE_STAT(ni, rx_action); - - /* verify frame payloads but defer processing */ - /* XXX maybe push this to method */ - switch (ia->ia_category) { - case IEEE80211_ACTION_CAT_BA: - switch (ia->ia_action) { - case IEEE80211_ACTION_BA_ADDBA_REQUEST: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_addbarequest), - return); - break; - case IEEE80211_ACTION_BA_ADDBA_RESPONSE: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_addbaresponse), - return); - break; - case IEEE80211_ACTION_BA_DELBA: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ba_delba), - return); - break; - } - break; - case IEEE80211_ACTION_CAT_HT: - switch (ia->ia_action) { - case IEEE80211_ACTION_HT_TXCHWIDTH: - IEEE80211_VERIFY_LENGTH(efrm - frm, - sizeof(struct ieee80211_action_ht_txchwidth), - return); - break; - } - break; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); } - ic->ic_recv_action(ni, wh, frm, efrm); break; - } - case IEEE80211_FC0_SUBTYPE_AUTH: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: - case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, - wh, NULL, "%s", "not handled"); + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } @@ -912,6 +872,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_frame *wh; /* * Process management frames when scanning; useful for doing @@ -919,11 +880,42 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, */ if (ic->ic_flags & IEEE80211_F_SCAN) adhoc_recv_mgmt(ni, m0, subtype, rssi, nf); - else - vap->iv_stats.is_rx_mgtdiscard++; + else { + wh = mtod(m0, struct ieee80211_frame *); + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + case IEEE80211_FC0_SUBTYPE_ATIM: + case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); + vap->iv_stats.is_rx_mgtdiscard++; + break; + default: + IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, + wh, "mgt", "subtype 0x%x not handled", subtype); + vap->iv_stats.is_rx_badsubtype++; + break; + } + } } static void -adhoc_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype) +adhoc_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } } diff --git a/freebsd/sys/net80211/ieee80211_ageq.c b/freebsd/sys/net80211/ieee80211_ageq.c index 349345cb..2c6f0475 100644 --- a/freebsd/sys/net80211/ieee80211_ageq.c +++ b/freebsd/sys/net80211/ieee80211_ageq.c @@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$"); void ieee80211_ageq_init(struct ieee80211_ageq *aq, int maxlen, const char *name) { - memset(aq, 0, sizeof(aq)); + memset(aq, 0, sizeof(*aq)); aq->aq_maxlen = maxlen; IEEE80211_AGEQ_INIT(aq, name); /* OS-dependent setup */ } diff --git a/freebsd/sys/net80211/ieee80211_crypto.h b/freebsd/sys/net80211/ieee80211_crypto.h index 57d05ad7..d7ac436f 100644 --- a/freebsd/sys/net80211/ieee80211_crypto.h +++ b/freebsd/sys/net80211/ieee80211_crypto.h @@ -78,6 +78,7 @@ struct ieee80211_key { #define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */ #define IEEE80211_KEY_RECV 0x0002 /* key used for recv */ #define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */ +#define IEEE80211_KEY_NOREPLAY 0x0008 /* ignore replay failures */ #define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */ #define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */ #define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */ @@ -98,7 +99,8 @@ struct ieee80211_key { uint8_t wk_macaddr[IEEE80211_ADDR_LEN]; }; #define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ - (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP) + (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP | \ + IEEE80211_KEY_NOREPLAY) #define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1) diff --git a/freebsd/sys/net80211/ieee80211_crypto_ccmp.c b/freebsd/sys/net80211/ieee80211_crypto_ccmp.c index 81ce4df4..13843744 100644 --- a/freebsd/sys/net80211/ieee80211_crypto_ccmp.c +++ b/freebsd/sys/net80211/ieee80211_crypto_ccmp.c @@ -228,7 +228,8 @@ ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) } tid = ieee80211_gettid(wh); pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); - if (pn <= k->wk_keyrsc[tid]) { + if (pn <= k->wk_keyrsc[tid] && + (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { /* * Replay violation. */ diff --git a/freebsd/sys/net80211/ieee80211_crypto_tkip.c b/freebsd/sys/net80211/ieee80211_crypto_tkip.c index d75baeda..9bc51743 100644 --- a/freebsd/sys/net80211/ieee80211_crypto_tkip.c +++ b/freebsd/sys/net80211/ieee80211_crypto_tkip.c @@ -283,7 +283,8 @@ tkip_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) tid = ieee80211_gettid(wh); ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]); - if (ctx->rx_rsc <= k->wk_keyrsc[tid]) { + if (ctx->rx_rsc <= k->wk_keyrsc[tid] && + (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { /* * Replay violation; notify upper layer. */ diff --git a/freebsd/sys/net80211/ieee80211_dfs.c b/freebsd/sys/net80211/ieee80211_dfs.c index 948a4dc5..708cfc90 100644 --- a/freebsd/sys/net80211/ieee80211_dfs.c +++ b/freebsd/sys/net80211/ieee80211_dfs.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_var.h> -MALLOC_DEFINE(M_80211_DFS, "80211dfs", "802.11 DFS state"); +static MALLOC_DEFINE(M_80211_DFS, "80211dfs", "802.11 DFS state"); static int ieee80211_nol_timeout = 30*60; /* 30 minutes */ SYSCTL_INT(_net_wlan, OID_AUTO, nol_timeout, CTLFLAG_RW, @@ -322,6 +322,8 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch * on the NOL to expire. */ /*XXX*/ + if_printf(ic->ic_ifp, "%s: No free channels; waiting for entry " + "on NOL to expire\n", __func__); } } else { /* diff --git a/freebsd/sys/net80211/ieee80211_freebsd.c b/freebsd/sys/net80211/ieee80211_freebsd.c index 7cfa4a81..5e2abf8a 100644 --- a/freebsd/sys/net80211/ieee80211_freebsd.c +++ b/freebsd/sys/net80211/ieee80211_freebsd.c @@ -65,7 +65,7 @@ SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 0, "debugging printfs"); #endif -MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); +static MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); /* * Allocate/free com structure in conjunction with ifnet; diff --git a/freebsd/sys/net80211/ieee80211_hostap.c b/freebsd/sys/net80211/ieee80211_hostap.c index 12970428..63809ea3 100644 --- a/freebsd/sys/net80211/ieee80211_hostap.c +++ b/freebsd/sys/net80211/ieee80211_hostap.c @@ -474,7 +474,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -574,9 +573,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -916,7 +913,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -2196,18 +2192,38 @@ 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, wh, frm, efrm); - } else + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } break; case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_ATIM: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); + vap->iv_stats.is_rx_mgtdiscard++; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } diff --git a/freebsd/sys/net80211/ieee80211_ht.c b/freebsd/sys/net80211/ieee80211_ht.c index da1bb26b..69e64a02 100644 --- a/freebsd/sys/net80211/ieee80211_ht.c +++ b/freebsd/sys/net80211/ieee80211_ht.c @@ -56,31 +56,86 @@ __FBSDID("$FreeBSD$"); #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define SM(_v, _f) (((_v) << _f##_S) & _f) -const struct ieee80211_mcs_rates ieee80211_htrates[16] = { - { 13, 14, 27, 30 }, /* MCS 0 */ - { 26, 29, 54, 60 }, /* MCS 1 */ - { 39, 43, 81, 90 }, /* MCS 2 */ - { 52, 58, 108, 120 }, /* MCS 3 */ - { 78, 87, 162, 180 }, /* MCS 4 */ - { 104, 116, 216, 240 }, /* MCS 5 */ - { 117, 130, 243, 270 }, /* MCS 6 */ - { 130, 144, 270, 300 }, /* MCS 7 */ - { 26, 29, 54, 60 }, /* MCS 8 */ - { 52, 58, 108, 120 }, /* MCS 9 */ - { 78, 87, 162, 180 }, /* MCS 10 */ - { 104, 116, 216, 240 }, /* MCS 11 */ - { 156, 173, 324, 360 }, /* MCS 12 */ - { 208, 231, 432, 480 }, /* MCS 13 */ - { 234, 260, 486, 540 }, /* MCS 14 */ - { 260, 289, 540, 600 } /* MCS 15 */ +const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = { + { 13, 14, 27, 30 }, /* MCS 0 */ + { 26, 29, 54, 60 }, /* MCS 1 */ + { 39, 43, 81, 90 }, /* MCS 2 */ + { 52, 58, 108, 120 }, /* MCS 3 */ + { 78, 87, 162, 180 }, /* MCS 4 */ + { 104, 116, 216, 240 }, /* MCS 5 */ + { 117, 130, 243, 270 }, /* MCS 6 */ + { 130, 144, 270, 300 }, /* MCS 7 */ + { 26, 29, 54, 60 }, /* MCS 8 */ + { 52, 58, 108, 120 }, /* MCS 9 */ + { 78, 87, 162, 180 }, /* MCS 10 */ + { 104, 116, 216, 240 }, /* MCS 11 */ + { 156, 173, 324, 360 }, /* MCS 12 */ + { 208, 231, 432, 480 }, /* MCS 13 */ + { 234, 260, 486, 540 }, /* MCS 14 */ + { 260, 289, 540, 600 }, /* MCS 15 */ + { 39, 43, 81, 90 }, /* MCS 16 */ + { 78, 87, 162, 180 }, /* MCS 17 */ + { 117, 130, 243, 270 }, /* MCS 18 */ + { 156, 173, 324, 360 }, /* MCS 19 */ + { 234, 260, 486, 540 }, /* MCS 20 */ + { 312, 347, 648, 720 }, /* MCS 21 */ + { 351, 390, 729, 810 }, /* MCS 22 */ + { 390, 433, 810, 900 }, /* MCS 23 */ + { 52, 58, 108, 120 }, /* MCS 24 */ + { 104, 116, 216, 240 }, /* MCS 25 */ + { 156, 173, 324, 360 }, /* MCS 26 */ + { 208, 231, 432, 480 }, /* MCS 27 */ + { 312, 347, 648, 720 }, /* MCS 28 */ + { 416, 462, 864, 960 }, /* MCS 29 */ + { 468, 520, 972, 1080 }, /* MCS 30 */ + { 520, 578, 1080, 1200 }, /* MCS 31 */ + { 0, 0, 12, 13 }, /* MCS 32 */ + { 78, 87, 162, 180 }, /* MCS 33 */ + { 104, 116, 216, 240 }, /* MCS 34 */ + { 130, 144, 270, 300 }, /* MCS 35 */ + { 117, 130, 243, 270 }, /* MCS 36 */ + { 156, 173, 324, 360 }, /* MCS 37 */ + { 195, 217, 405, 450 }, /* MCS 38 */ + { 104, 116, 216, 240 }, /* MCS 39 */ + { 130, 144, 270, 300 }, /* MCS 40 */ + { 130, 144, 270, 300 }, /* MCS 41 */ + { 156, 173, 324, 360 }, /* MCS 42 */ + { 182, 202, 378, 420 }, /* MCS 43 */ + { 182, 202, 378, 420 }, /* MCS 44 */ + { 208, 231, 432, 480 }, /* MCS 45 */ + { 156, 173, 324, 360 }, /* MCS 46 */ + { 195, 217, 405, 450 }, /* MCS 47 */ + { 195, 217, 405, 450 }, /* MCS 48 */ + { 234, 260, 486, 540 }, /* MCS 49 */ + { 273, 303, 567, 630 }, /* MCS 50 */ + { 273, 303, 567, 630 }, /* MCS 51 */ + { 312, 347, 648, 720 }, /* MCS 52 */ + { 130, 144, 270, 300 }, /* MCS 53 */ + { 156, 173, 324, 360 }, /* MCS 54 */ + { 182, 202, 378, 420 }, /* MCS 55 */ + { 156, 173, 324, 360 }, /* MCS 56 */ + { 182, 202, 378, 420 }, /* MCS 57 */ + { 208, 231, 432, 480 }, /* MCS 58 */ + { 234, 260, 486, 540 }, /* MCS 59 */ + { 208, 231, 432, 480 }, /* MCS 60 */ + { 234, 260, 486, 540 }, /* MCS 61 */ + { 260, 289, 540, 600 }, /* MCS 62 */ + { 260, 289, 540, 600 }, /* MCS 63 */ + { 286, 318, 594, 660 }, /* MCS 64 */ + { 195, 217, 405, 450 }, /* MCS 65 */ + { 234, 260, 486, 540 }, /* MCS 66 */ + { 273, 303, 567, 630 }, /* MCS 67 */ + { 234, 260, 486, 540 }, /* MCS 68 */ + { 273, 303, 567, 630 }, /* MCS 69 */ + { 312, 347, 648, 720 }, /* MCS 70 */ + { 351, 390, 729, 810 }, /* MCS 71 */ + { 312, 347, 648, 720 }, /* MCS 72 */ + { 351, 390, 729, 810 }, /* MCS 73 */ + { 390, 433, 810, 900 }, /* MCS 74 */ + { 390, 433, 810, 900 }, /* MCS 75 */ + { 429, 477, 891, 990 }, /* MCS 76 */ }; -static const struct ieee80211_htrateset ieee80211_rateset_11n = - { 16, { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15 } - }; - #ifdef IEEE80211_AMPDU_AGE static int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */ SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, @@ -164,6 +219,9 @@ 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 null_addba_response_timeout(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap); + 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); @@ -181,6 +239,7 @@ ieee80211_ht_attach(struct ieee80211com *ic) ic->ic_ampdu_enable = ieee80211_ampdu_enable; ic->ic_addba_request = ieee80211_addba_request; ic->ic_addba_response = ieee80211_addba_response; + ic->ic_addba_response_timeout = null_addba_response_timeout; ic->ic_addba_stop = ieee80211_addba_stop; ic->ic_bar_response = ieee80211_bar_response; ic->ic_ampdu_rx_start = ampdu_rx_start; @@ -249,40 +308,150 @@ ieee80211_ht_vdetach(struct ieee80211vap *vap) { } +static int +ht_getrate(struct ieee80211com *ic, int index, enum ieee80211_phymode mode, + int ratetype) +{ + int mword, rate; + + mword = ieee80211_rate2media(ic, index | IEEE80211_RATE_MCS, mode); + if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS) + return (0); + switch (ratetype) { + case 0: + rate = ieee80211_htrates[index].ht20_rate_800ns; + break; + case 1: + rate = ieee80211_htrates[index].ht20_rate_400ns; + break; + case 2: + rate = ieee80211_htrates[index].ht40_rate_800ns; + break; + default: + rate = ieee80211_htrates[index].ht40_rate_400ns; + break; + } + return (rate); +} + +static struct printranges { + int minmcs; + int maxmcs; + int txstream; + int ratetype; + int htcapflags; +} ranges[] = { + { 0, 7, 1, 0, 0 }, + { 8, 15, 2, 0, 0 }, + { 16, 23, 3, 0, 0 }, + { 24, 31, 4, 0, 0 }, + { 32, 0, 1, 2, IEEE80211_HTC_TXMCS32 }, + { 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL }, + { 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL }, + { 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL }, + { 0, 0, 0, 0, 0 }, +}; + static void -ht_announce(struct ieee80211com *ic, int mode, - const struct ieee80211_htrateset *rs) +ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype) { struct ifnet *ifp = ic->ic_ifp; - int i, rate, mword; + int minrate, maxrate; + struct printranges *range; - if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]); - for (i = 0; i < rs->rs_nrates; i++) { - mword = ieee80211_rate2media(ic, - rs->rs_rates[i] | IEEE80211_RATE_MCS, mode); - if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS) + for (range = ranges; range->txstream != 0; range++) { + if (ic->ic_txstream < range->txstream) + continue; + if (range->htcapflags && + (ic->ic_htcaps & range->htcapflags) == 0) continue; - rate = ieee80211_htrates[rs->rs_rates[i]].ht40_rate_400ns; - printf("%s%d%sMbps", (i != 0 ? " " : ""), - rate / 2, ((rate & 0x1) != 0 ? ".5" : "")); + if (ratetype < range->ratetype) + continue; + minrate = ht_getrate(ic, range->minmcs, mode, ratetype); + maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype); + if (range->maxmcs) { + if_printf(ifp, "MCS %d-%d: %d%sMbps - %d%sMbps\n", + range->minmcs, range->maxmcs, + minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""), + maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : "")); + } else { + if_printf(ifp, "MCS %d: %d%sMbps\n", range->minmcs, + minrate/2, ((minrate & 0x1) != 0 ? ".5" : "")); + } + } +} + +static void +ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode) +{ + struct ifnet *ifp = ic->ic_ifp; + const char *modestr = ieee80211_phymode_name[mode]; + + if_printf(ifp, "%s MCS 20MHz\n", modestr); + ht_rateprint(ic, mode, 0); + if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) { + if_printf(ifp, "%s MCS 20MHz SGI\n", modestr); + ht_rateprint(ic, mode, 1); + } + if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) { + if_printf(ifp, "%s MCS 40MHz:\n", modestr); + ht_rateprint(ic, mode, 2); + } + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) { + if_printf(ifp, "%s MCS 40MHz SGI:\n", modestr); + ht_rateprint(ic, mode, 3); } - printf("\n"); } void ieee80211_ht_announce(struct ieee80211com *ic) { + struct ifnet *ifp = ic->ic_ifp; + + if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || + isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) + if_printf(ifp, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream); if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA)) - ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n); + ht_announce(ic, IEEE80211_MODE_11NA); if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) - ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n); + ht_announce(ic, IEEE80211_MODE_11NG); } +static struct ieee80211_htrateset htrateset; + const struct ieee80211_htrateset * ieee80211_get_suphtrates(struct ieee80211com *ic, - const struct ieee80211_channel *c) + const struct ieee80211_channel *c) { - return &ieee80211_rateset_11n; +#define ADDRATE(x) do { \ + htrateset.rs_rates[htrateset.rs_nrates] = x; \ + htrateset.rs_nrates++; \ +} while (0) + int i; + + memset(&htrateset, 0, sizeof(struct ieee80211_htrateset)); + for (i = 0; i < ic->ic_txstream * 8; i++) + ADDRATE(i); + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTC_TXMCS32)) + ADDRATE(32); + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { + if (ic->ic_txstream >= 2) { + for (i = 33; i <= 38; i++) + ADDRATE(i); + } + if (ic->ic_txstream >= 3) { + for (i = 39; i <= 52; i++) + ADDRATE(i); + } + if (ic->ic_txstream == 4) { + for (i = 53; i <= 76; i++) + ADDRATE(i); + } + } + return &htrateset; +#undef ADDRATE } /* @@ -398,6 +567,7 @@ ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap, static void ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap) { + ampdu_rx_purge(rap); rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND); } @@ -658,7 +828,7 @@ again: if (off < rap->rxa_wnd) { /* * Common case (hopefully): in the BA window. - * Sec 9.10.7.6 a) (D2.04 p.118 line 47) + * Sec 9.10.7.6.2 a) (p.137) */ #ifdef IEEE80211_AMPDU_AGE /* @@ -723,7 +893,7 @@ again: /* * Outside the BA window, but within range; * flush the reorder q and move the window. - * Sec 9.10.7.6 b) (D2.04 p.118 line 60) + * Sec 9.10.7.6.2 b) (p.138) */ IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni, "move BA win <%u:%u> (%u frames) rxseq %u tid %u", @@ -747,7 +917,7 @@ again: } else { /* * Outside the BA window and out of range; toss. - * Sec 9.10.7.6 c) (D2.04 p.119 line 16) + * Sec 9.10.7.6.2 c) (p.138) */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr, @@ -811,7 +981,7 @@ ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0) if (off < IEEE80211_SEQ_BA_RANGE) { /* * Flush the reorder q up to rxseq and move the window. - * Sec 9.10.7.6 a) (D2.04 p.119 line 22) + * Sec 9.10.7.6.3 a) (p.138) */ IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni, "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u", @@ -832,7 +1002,7 @@ ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0) } else { /* * Out of range; toss. - * Sec 9.10.7.6 b) (D2.04 p.119 line 41) + * Sec 9.10.7.6.3 b) (p.138) */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr, @@ -1400,7 +1570,7 @@ ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie) htcap_update_shortgi(ni); /* NB: honor operating mode constraint */ - /* XXX 40 MHZ intolerant */ + /* XXX 40 MHz intolerant */ htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ? IEEE80211_CHAN_HT20 : 0; if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) && @@ -1419,10 +1589,22 @@ ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie) int ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) { + struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; const struct ieee80211_ie_htcap *htcap; struct ieee80211_htrateset *rs; - int i; + int i, maxequalmcs, maxunequalmcs; + + maxequalmcs = ic->ic_txstream * 8 - 1; + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { + if (ic->ic_txstream >= 2) + maxunequalmcs = 38; + if (ic->ic_txstream >= 3) + maxunequalmcs = 52; + if (ic->ic_txstream >= 4) + maxunequalmcs = 76; + } else + maxunequalmcs = 0; rs = &ni->ni_htrates; memset(rs, 0, sizeof(*rs)); @@ -1441,6 +1623,13 @@ ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) vap->iv_stats.is_rx_rstoobig++; break; } + if (i <= 31 && i > maxequalmcs) + continue; + if (i == 32 && + (ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0) + continue; + if (i > 32 && i > maxunequalmcs) + continue; rs->rs_rates[rs->rs_nrates++] = i; } } @@ -1509,14 +1698,23 @@ ampdu_tx_stop(struct ieee80211_tx_ampdu *tap) tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK); } +/* + * ADDBA response timeout. + * + * If software aggregation and per-TID queue management was done here, + * that queue would be unpaused after the ADDBA timeout occurs. + */ static void addba_timeout(void *arg) { struct ieee80211_tx_ampdu *tap = arg; + struct ieee80211_node *ni = tap->txa_ni; + struct ieee80211com *ic = ni->ni_ic; /* XXX ? */ tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND; tap->txa_attempts++; + ic->ic_addba_response_timeout(ni, tap); } static void @@ -1539,6 +1737,12 @@ addba_stop_timeout(struct ieee80211_tx_ampdu *tap) } } +static void +null_addba_response_timeout(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap) +{ +} + /* * Default method for requesting A-MPDU tx aggregation. * We setup the specified state block and start a timer @@ -1623,7 +1827,7 @@ ht_recv_action_ba_addba_request(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap; uint8_t dialogtoken; uint16_t baparamset, batimeout, baseqctl; - uint16_t args[4]; + uint16_t args[5]; int tid; dialogtoken = frm[2]; @@ -1673,6 +1877,7 @@ ht_recv_action_ba_addba_request(struct ieee80211_node *ni, | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ) ; args[3] = 0; + args[4] = 0; ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA, IEEE80211_ACTION_BA_ADDBA_RESPONSE, args); return 0; @@ -1876,7 +2081,7 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { struct ieee80211com *ic = ni->ni_ic; - uint16_t args[4]; + uint16_t args[5]; int tid, dialogtoken; static int tokens = 0; /* XXX */ @@ -1893,13 +2098,14 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, tap->txa_start = ni->ni_txseqs[tid]; args[0] = dialogtoken; - args[1] = IEEE80211_BAPS_POLICY_IMMEDIATE + args[1] = 0; /* NB: status code not used */ + args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE | SM(tid, IEEE80211_BAPS_TID) | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ) ; - args[2] = 0; /* batimeout */ + args[3] = 0; /* batimeout */ /* NB: do first so there's no race against reply */ - if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) { + if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) { /* unable to setup state, don't make request */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, "%s: could not setup BA stream for AC %d", @@ -1913,7 +2119,7 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, } tokens = dialogtoken; /* allocate token */ /* NB: after calling ic_addba_request so driver can set txa_start */ - args[3] = SM(tap->txa_start, IEEE80211_BASEQ_START) + args[4] = SM(tap->txa_start, IEEE80211_BASEQ_START) | SM(0, IEEE80211_BASEQ_FRAG) ; return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA, @@ -2004,7 +2210,7 @@ bar_tx_complete(struct ieee80211_node *ni, void *arg, int status) callout_pending(&tap->txa_timer)) { struct ieee80211com *ic = ni->ni_ic; - if (status) /* ACK'd */ + if (status == 0) /* ACK'd */ bar_stop_timer(tap); ic->ic_bar_response(ni, tap, status); /* NB: just let timer expire so we pace requests */ @@ -2016,7 +2222,7 @@ ieee80211_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status) { - if (status != 0) { /* got ACK */ + if (status == 0) { /* got ACK */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u", tap->txa_start, @@ -2106,11 +2312,15 @@ ieee80211_send_bar(struct ieee80211_node *ni, ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)", tid, barctl, seq, tap->txa_attempts); + /* + * ic_raw_xmit will free the node reference + * regardless of queue/TX success or failure. + */ ret = ic->ic_raw_xmit(ni, m, NULL); if (ret != 0) { /* xmit failed, clear state flag */ tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; - goto bad; + return ret; } /* XXX hack against tx complete happening before timer is started */ if (tap->txa_flags & IEEE80211_AGGR_BARPEND) @@ -2159,12 +2369,12 @@ ht_send_action_ba_addba(struct ieee80211_node *ni, uint8_t *frm; IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni, - "send ADDBA %s: dialogtoken %d " + "send ADDBA %s: dialogtoken %d status %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]); + args[0], args[1], args[2], MS(args[2], IEEE80211_BAPS_TID), + args[3], args[4]); IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, @@ -2181,10 +2391,12 @@ ht_send_action_ba_addba(struct ieee80211_node *ni, *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_RESPONSE) + ADDSHORT(frm, args[1]); /* status code */ + ADDSHORT(frm, args[2]); /* baparamset */ + ADDSHORT(frm, args[3]); /* batimeout */ if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) - ADDSHORT(frm, args[3]); /* baseqctl */ + ADDSHORT(frm, args[4]); /* baseqctl */ m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); return ht_action_output(ni, m); } else { @@ -2278,21 +2490,49 @@ ht_send_action_ht_txchwidth(struct ieee80211_node *ni, #undef ADDSHORT /* - * Construct the MCS bit mask for inclusion - * in an HT information element. + * Construct the MCS bit mask for inclusion in an HT capabilities + * information element. */ -static void -ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs) +static void +ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm) { int i; - - for (i = 0; i < rs->rs_nrates; i++) { - int r = rs->rs_rates[i] & IEEE80211_RATE_VAL; - if (r < IEEE80211_HTRATE_MAXSIZE) { /* XXX? */ - /* NB: this assumes a particular implementation */ - setbit(frm, r); + uint8_t txparams; + + KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4), + ("ic_rxstream %d out of range", ic->ic_rxstream)); + KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4), + ("ic_txstream %d out of range", ic->ic_txstream)); + + for (i = 0; i < ic->ic_rxstream * 8; i++) + setbit(frm, i); + if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && + (ic->ic_htcaps & IEEE80211_HTC_RXMCS32)) + setbit(frm, 32); + if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) { + if (ic->ic_rxstream >= 2) { + for (i = 33; i <= 38; i++) + setbit(frm, i); + } + if (ic->ic_rxstream >= 3) { + for (i = 39; i <= 52; i++) + setbit(frm, i); + } + if (ic->ic_txstream >= 4) { + for (i = 53; i <= 76; i++) + setbit(frm, i); } } + + if (ic->ic_rxstream != ic->ic_txstream) { + txparams = 0x1; /* TX MCS set defined */ + txparams |= 0x2; /* TX RX MCS not equal */ + txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */ + if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) + txparams |= 0x16; /* TX unequal modulation sup */ + } else + txparams = 0; + frm[12] = txparams; } /* @@ -2306,8 +2546,9 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) frm[1] = (v) >> 8; \ frm += 2; \ } while (0) + struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; - uint16_t caps; + uint16_t caps, extcaps; int rxmax, density; /* HT capabilities */ @@ -2329,6 +2570,17 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) /* use advertised setting (XXX locally constraint) */ rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); + + /* + * NB: Hardware might support HT40 on some but not all + * channels. We can't determine this earlier because only + * after association the channel is upgraded to HT based + * on the negotiated capabilities. + */ + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL && + findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL) + caps &= ~IEEE80211_HTCAP_CHWIDTH40; } else { /* override 20/40 use based on current channel */ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) @@ -2358,15 +2610,24 @@ ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni) /* supported MCS set */ /* - * XXX it would better to get the rate set from ni_htrates - * so we can restrict it but for sta mode ni_htrates isn't - * setup when we're called to form an AssocReq frame so for - * now we're restricted to the default HT rate set. + * XXX: For sta mode the rate set should be restricted based + * on the AP's capabilities, but ni_htrates isn't setup when + * we're called to form an AssocReq frame so for now we're + * restricted to the device capabilities. */ - ieee80211_set_htrates(frm, &ieee80211_rateset_11n); + ieee80211_set_mcsset(ni->ni_ic, frm); - frm += sizeof(struct ieee80211_ie_htcap) - + frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) - __offsetof(struct ieee80211_ie_htcap, hc_mcsset); + + /* HT extended capabilities */ + extcaps = vap->iv_htextcaps & 0xffff; + + ADDSHORT(frm, extcaps); + + frm += sizeof(struct ieee80211_ie_htcap) - + __offsetof(struct ieee80211_ie_htcap, hc_txbf); + return frm; #undef ADDSHORT } diff --git a/freebsd/sys/net80211/ieee80211_ht.h b/freebsd/sys/net80211/ieee80211_ht.h index 7b0eab7a..249ddd2c 100644 --- a/freebsd/sys/net80211/ieee80211_ht.h +++ b/freebsd/sys/net80211/ieee80211_ht.h @@ -142,7 +142,8 @@ struct ieee80211_rx_ampdu { int rxa_age; /* age of oldest frame in window */ int rxa_nframes; /* frames since ADDBA */ struct mbuf *rxa_m[IEEE80211_AGGR_BAWMAX]; - uint64_t rxa_pad[4]; + void *rxa_private; + uint64_t rxa_pad[3]; }; void ieee80211_ht_attach(struct ieee80211com *); @@ -158,7 +159,7 @@ struct ieee80211_mcs_rates { uint16_t ht40_rate_800ns; uint16_t ht40_rate_400ns; }; -extern const struct ieee80211_mcs_rates ieee80211_htrates[16]; +extern const struct ieee80211_mcs_rates ieee80211_htrates[]; const struct ieee80211_htrateset *ieee80211_get_suphtrates( struct ieee80211com *, const struct ieee80211_channel *); diff --git a/freebsd/sys/net80211/ieee80211_hwmp.c b/freebsd/sys/net80211/ieee80211_hwmp.c index 12a15637..36cdc313 100644 --- a/freebsd/sys/net80211/ieee80211_hwmp.c +++ b/freebsd/sys/net80211/ieee80211_hwmp.c @@ -163,7 +163,7 @@ struct ieee80211_hwmp_state { uint8_t hs_maxhops; /* max hop count */ }; -SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, +static SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0, "IEEE 802.11s HWMP parameters"); static int ieee80211_hwmp_targetonly = 0; SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW, diff --git a/freebsd/sys/net80211/ieee80211_input.c b/freebsd/sys/net80211/ieee80211_input.c index 97b5c756..043d1887 100644 --- a/freebsd/sys/net80211/ieee80211_input.c +++ b/freebsd/sys/net80211/ieee80211_input.c @@ -59,9 +59,54 @@ __FBSDID("$FreeBSD$"); #include <net/ethernet.h> #endif +static void +ieee80211_process_mimo(struct ieee80211_node *ni, struct ieee80211_rx_stats *rx) +{ + int i; + + /* Verify the required MIMO bits are set */ + if ((rx->r_flags & (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) != + (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) + return; + + /* XXX This assumes the MIMO radios have both ctl and ext chains */ + for (i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { + IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ctl[i], rx->c_rssi_ctl[i]); + IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ext[i], rx->c_rssi_ext[i]); + } + + /* XXX This also assumes the MIMO radios have both ctl and ext chains */ + for(i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) { + ni->ni_mimo_noise_ctl[i] = rx->c_nf_ctl[i]; + ni->ni_mimo_noise_ext[i] = rx->c_nf_ext[i]; + } + ni->ni_mimo_chains = rx->c_chain; +} + +int +ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m, + struct ieee80211_rx_stats *rx) +{ + /* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */ + ieee80211_process_mimo(ni, rx); + return ieee80211_input(ni, m, rx->rssi, rx->nf); +} + int ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf) { + struct ieee80211_rx_stats rx; + + rx.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI; + rx.nf = nf; + rx.rssi = rssi; + return ieee80211_input_mimo_all(ic, m, &rx); +} + +int +ieee80211_input_mimo_all(struct ieee80211com *ic, struct mbuf *m, + struct ieee80211_rx_stats *rx) +{ struct ieee80211vap *vap; int type = -1; @@ -98,7 +143,7 @@ ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf) m = NULL; } ni = ieee80211_ref_node(vap->iv_bss); - type = ieee80211_input(ni, mcopy, rssi, nf); + type = ieee80211_input_mimo(ni, mcopy, rx); ieee80211_free_node(ni); } if (m != NULL) /* no vaps, reclaim mbuf */ @@ -679,7 +724,6 @@ ieee80211_parse_action(struct ieee80211_node *ni, struct mbuf *m) IEEE80211_NODE_STAT(ni, rx_action); /* verify frame payloads but defer processing */ - /* XXX maybe push this to method */ switch (ia->ia_category) { case IEEE80211_ACTION_CAT_BA: switch (ia->ia_action) { diff --git a/freebsd/sys/net80211/ieee80211_input.h b/freebsd/sys/net80211/ieee80211_input.h index 5b38dddc..b90f46a1 100644 --- a/freebsd/sys/net80211/ieee80211_input.h +++ b/freebsd/sys/net80211/ieee80211_input.h @@ -142,6 +142,104 @@ ishtinfooui(const uint8_t *frm) return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI); } +#include <sys/endian.h> /* For le16toh() */ + +/* + * Check the current frame sequence number against the current TID + * state and return whether it's in sequence or should be dropped. + * + * Since out of order packet and duplicate packet eliminations should + * be done by the AMPDU RX code, this routine blindly accepts all + * frames from a HT station w/ a TID that is currently doing AMPDU-RX. + * HT stations without WME or where the TID is not doing AMPDU-RX + * are checked like non-HT stations. + * + * The routine only eliminates packets whose sequence/fragment + * match or are less than the last seen sequence/fragment number + * AND are retransmits It doesn't try to eliminate out of order packets. + * + * Since all frames after sequence number 4095 will be less than 4095 + * (as the seqnum wraps), handle that special case so packets aren't + * incorrectly dropped - ie, if the next packet is sequence number 0 + * but a retransmit since the initial packet didn't make it. + */ +static __inline int +ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh) +{ +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_EQ(a,b) ((int)((a)-(b)) == 0) +#define HAS_SEQ(type) ((type & 0x4) == 0) +#define SEQNO(a) ((a) >> IEEE80211_SEQ_SEQ_SHIFT) +#define FRAGNO(a) ((a) & IEEE80211_SEQ_FRAG_MASK) + uint16_t rxseq; + uint8_t type; + uint8_t tid; + struct ieee80211_rx_ampdu *rap; + + rxseq = le16toh(*(uint16_t *)wh->i_seq); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + /* Types with no sequence number are always treated valid */ + if (! HAS_SEQ(type)) + return 1; + + tid = ieee80211_gettid(wh); + + /* + * Only do the HT AMPDU check for WME stations; non-WME HT stations + * shouldn't exist outside of debugging. We should at least + * handle that. + */ + if (tid < WME_NUM_TID) { + rap = &ni->ni_rx_ampdu[tid]; + /* HT nodes currently doing RX AMPDU are always valid */ + if ((ni->ni_flags & IEEE80211_NODE_HT) && + (rap->rxa_flags & IEEE80211_AGGR_RUNNING)) + return 1; + } + + /* + * Otherwise, retries for packets below or equal to the last + * seen sequence number should be dropped. + */ + + /* + * Treat frame seqnum 4095 as special due to boundary + * wrapping conditions. + */ + if (SEQNO(ni->ni_rxseqs[tid]) == 4095) { + /* + * Drop retransmits on seqnum 4095/current fragment for itself. + */ + if (SEQ_EQ(rxseq, ni->ni_rxseqs[tid]) && + (wh->i_fc[1] & IEEE80211_FC1_RETRY)) + return 0; + /* + * Treat any subsequent frame as fine if the last seen frame + * is 4095 and it's not a retransmit for the same sequence + * number. However, this doesn't capture incorrectly ordered + * fragments w/ sequence number 4095. It shouldn't be seen + * in practice, but see the comment above for further info. + */ + return 1; + } + + /* + * At this point we assume that retransmitted seq/frag numbers below + * the current can simply be eliminated. + */ + if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && + SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) + return 0; + + return 1; +#undef SEQ_LEQ +#undef SEQ_EQ +#undef HAS_SEQ +#undef SEQNO +#undef FRAGNO +} + void ieee80211_deliver_data(struct ieee80211vap *, struct ieee80211_node *, struct mbuf *); struct mbuf *ieee80211_defrag(struct ieee80211_node *, diff --git a/freebsd/sys/net80211/ieee80211_ioctl.c b/freebsd/sys/net80211/ieee80211_ioctl.c index af27ef10..78a6b50f 100644 --- a/freebsd/sys/net80211/ieee80211_ioctl.c +++ b/freebsd/sys/net80211/ieee80211_ioctl.c @@ -72,6 +72,8 @@ __FBSDID("$FreeBSD$"); static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; static struct ieee80211_channel *findchannel(struct ieee80211com *, int ieee, int mode); +static int ieee80211_scanreq(struct ieee80211vap *, + struct ieee80211_scan_req *); static __noinline int ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq) @@ -143,7 +145,7 @@ static __noinline int ieee80211_ioctl_getchaninfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211com *ic = vap->iv_ic; - int space; + uint32_t space; space = __offsetof(struct ieee80211req_chaninfo, ic_chans[ic->ic_nchans]); @@ -207,7 +209,7 @@ ieee80211_ioctl_getstastats(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; uint8_t macaddr[IEEE80211_ADDR_LEN]; - const int off = __offsetof(struct ieee80211req_sta_stats, is_stats); + const size_t off = __offsetof(struct ieee80211req_sta_stats, is_stats); int error; if (ireq->i_len < off) @@ -323,7 +325,7 @@ ieee80211_ioctl_getscanresults(struct ieee80211vap *vap, if (req.space > ireq->i_len) req.space = ireq->i_len; if (req.space > 0) { - size_t space; + uint32_t space; void *p; space = req.space; @@ -458,7 +460,7 @@ get_sta_info(void *arg, struct ieee80211_node *ni) static __noinline int getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq, - struct ieee80211_node *ni, int off) + struct ieee80211_node *ni, size_t off) { struct ieee80211com *ic = vap->iv_ic; struct stainforeq req; @@ -503,7 +505,7 @@ static __noinline int ieee80211_ioctl_getstainfo(struct ieee80211vap *vap, struct ieee80211req *ireq) { uint8_t macaddr[IEEE80211_ADDR_LEN]; - const int off = __offsetof(struct ieee80211req_sta_req, info); + const size_t off = __offsetof(struct ieee80211req_sta_req, info); struct ieee80211_node *ni; int error; @@ -1473,14 +1475,15 @@ mlmelookup(void *arg, const struct ieee80211_scan_entry *se) } static __noinline int -setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], - int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN]) +setmlme_assoc_sta(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, + const uint8_t ssid[IEEE80211_NWID_LEN]) { struct scanlookup lookup; - /* XXX ibss/ahdemo */ - if (vap->iv_opmode != IEEE80211_M_STA) - return EINVAL; + KASSERT(vap->iv_opmode == IEEE80211_M_STA, + ("expected opmode STA not %s", + ieee80211_opmode_name[vap->iv_opmode])); /* NB: this is racey if roaming is !manual */ lookup.se = NULL; @@ -1497,6 +1500,37 @@ setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN], } static __noinline int +setmlme_assoc_adhoc(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len, + const uint8_t ssid[IEEE80211_NWID_LEN]) +{ + struct ieee80211_scan_req sr; + + KASSERT(vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_AHDEMO, + ("expected opmode IBSS or AHDEMO not %s", + ieee80211_opmode_name[vap->iv_opmode])); + + if (ssid_len == 0) + return EINVAL; + + /* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */ + memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN); + vap->iv_des_ssid[0].len = ssid_len; + memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len); + vap->iv_des_nssid = 1; + + memset(&sr, 0, sizeof(sr)); + sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE; + sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; + memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len); + sr.sr_ssid[0].len = ssid_len; + sr.sr_nssid = 1; + + return ieee80211_scanreq(vap, &sr); +} + +static __noinline int ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211req_mlme mlme; @@ -1507,9 +1541,13 @@ ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq) error = copyin(ireq->i_data, &mlme, sizeof(mlme)); if (error) return error; - if (mlme.im_op == IEEE80211_MLME_ASSOC) - return setmlme_assoc(vap, mlme.im_macaddr, + if (vap->iv_opmode == IEEE80211_M_STA && + mlme.im_op == IEEE80211_MLME_ASSOC) + return setmlme_assoc_sta(vap, mlme.im_macaddr, vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid); + else if (mlme.im_op == IEEE80211_MLME_ASSOC) + return setmlme_assoc_adhoc(vap, mlme.im_macaddr, + mlme.im_ssid_len, mlme.im_ssid); else return setmlme_common(vap, mlme.im_op, mlme.im_macaddr, mlme.im_reason); @@ -2338,8 +2376,8 @@ ieee80211_ioctl_chanswitch(struct ieee80211vap *vap, struct ieee80211req *ireq) return error; } -static __noinline int -ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) +static int +ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr) { #define IEEE80211_IOC_SCAN_FLAGS \ (IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \ @@ -2348,48 +2386,38 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \ IEEE80211_IOC_SCAN_CHECK) struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_req sr; /* XXX off stack? */ int error, i; - /* NB: parent must be running */ - if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - return ENXIO; - - if (ireq->i_len != sizeof(sr)) - return EINVAL; - error = copyin(ireq->i_data, &sr, sizeof(sr)); - if (error != 0) - return error; /* convert duration */ - if (sr.sr_duration == IEEE80211_IOC_SCAN_FOREVER) - sr.sr_duration = IEEE80211_SCAN_FOREVER; + if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER) + sr->sr_duration = IEEE80211_SCAN_FOREVER; else { - if (sr.sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN || - sr.sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX) + if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN || + sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX) return EINVAL; - sr.sr_duration = msecs_to_ticks(sr.sr_duration); - if (sr.sr_duration < 1) - sr.sr_duration = 1; + sr->sr_duration = msecs_to_ticks(sr->sr_duration); + if (sr->sr_duration < 1) + sr->sr_duration = 1; } /* convert min/max channel dwell */ - if (sr.sr_mindwell != 0) { - sr.sr_mindwell = msecs_to_ticks(sr.sr_mindwell); - if (sr.sr_mindwell < 1) - sr.sr_mindwell = 1; + if (sr->sr_mindwell != 0) { + sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell); + if (sr->sr_mindwell < 1) + sr->sr_mindwell = 1; } - if (sr.sr_maxdwell != 0) { - sr.sr_maxdwell = msecs_to_ticks(sr.sr_maxdwell); - if (sr.sr_maxdwell < 1) - sr.sr_maxdwell = 1; + if (sr->sr_maxdwell != 0) { + sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell); + if (sr->sr_maxdwell < 1) + sr->sr_maxdwell = 1; } /* NB: silently reduce ssid count to what is supported */ - if (sr.sr_nssid > IEEE80211_SCAN_MAX_SSID) - sr.sr_nssid = IEEE80211_SCAN_MAX_SSID; - for (i = 0; i < sr.sr_nssid; i++) - if (sr.sr_ssid[i].len > IEEE80211_NWID_LEN) + if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID) + sr->sr_nssid = IEEE80211_SCAN_MAX_SSID; + for (i = 0; i < sr->sr_nssid; i++) + if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN) return EINVAL; /* cleanse flags just in case, could reject if invalid flags */ - sr.sr_flags &= IEEE80211_IOC_SCAN_FLAGS; + sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS; /* * Add an implicit NOPICK if the vap is not marked UP. This * allows applications to scan without joining a bss (or picking @@ -2397,13 +2425,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) * roaming mode--you just need to mark the parent device UP. */ if ((vap->iv_ifp->if_flags & IFF_UP) == 0) - sr.sr_flags |= IEEE80211_IOC_SCAN_NOPICK; + sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n", - __func__, sr.sr_flags, + __func__, sr->sr_flags, (vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "", - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, sr.sr_nssid); + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid); /* * If we are in INIT state then the driver has never had a chance * to setup hardware state to do a scan; we must use the state @@ -2418,13 +2446,13 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) IEEE80211_LOCK(ic); if (vap->iv_state == IEEE80211_S_INIT) { /* NB: clobbers previous settings */ - vap->iv_scanreq_flags = sr.sr_flags; - vap->iv_scanreq_duration = sr.sr_duration; - vap->iv_scanreq_nssid = sr.sr_nssid; - for (i = 0; i < sr.sr_nssid; i++) { - vap->iv_scanreq_ssid[i].len = sr.sr_ssid[i].len; - memcpy(vap->iv_scanreq_ssid[i].ssid, sr.sr_ssid[i].ssid, - sr.sr_ssid[i].len); + vap->iv_scanreq_flags = sr->sr_flags; + vap->iv_scanreq_duration = sr->sr_duration; + vap->iv_scanreq_nssid = sr->sr_nssid; + for (i = 0; i < sr->sr_nssid; i++) { + vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len; + memcpy(vap->iv_scanreq_ssid[i].ssid, + sr->sr_ssid[i].ssid, sr->sr_ssid[i].len); } vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ; IEEE80211_UNLOCK(ic); @@ -2432,26 +2460,46 @@ ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) } else { vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; IEEE80211_UNLOCK(ic); - /* XXX neeed error return codes */ - if (sr.sr_flags & IEEE80211_IOC_SCAN_CHECK) { - (void) ieee80211_check_scan(vap, sr.sr_flags, - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, - sr.sr_nssid, + if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) { + error = ieee80211_check_scan(vap, sr->sr_flags, + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, + sr->sr_nssid, /* NB: cheat, we assume structures are compatible */ - (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]); + (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]); } else { - (void) ieee80211_start_scan(vap, sr.sr_flags, - sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, - sr.sr_nssid, + error = ieee80211_start_scan(vap, sr->sr_flags, + sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, + sr->sr_nssid, /* NB: cheat, we assume structures are compatible */ - (const struct ieee80211_scan_ssid *) &sr.sr_ssid[0]); + (const struct ieee80211_scan_ssid *) &sr->sr_ssid[0]); } + if (error == 0) + return EINPROGRESS; } - return error; + return 0; #undef IEEE80211_IOC_SCAN_FLAGS } static __noinline int +ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_req sr; /* XXX off stack? */ + int error; + + /* NB: parent must be running */ + if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return ENXIO; + + if (ireq->i_len != sizeof(sr)) + return EINVAL; + error = copyin(ireq->i_data, &sr, sizeof(sr)); + if (error != 0) + return error; + return ieee80211_scanreq(vap, &sr); +} + +static __noinline int ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq) { struct ieee80211_node *ni; @@ -2676,7 +2724,7 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r case IEEE80211_IOC_PROTMODE: if (ireq->i_val > IEEE80211_PROT_RTSCTS) return EINVAL; - ic->ic_protmode = ireq->i_val; + ic->ic_protmode = (enum ieee80211_protmode)ireq->i_val; /* NB: if not operating in 11g this can wait */ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) @@ -2695,7 +2743,7 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r if (!(IEEE80211_ROAMING_DEVICE <= ireq->i_val && ireq->i_val <= IEEE80211_ROAMING_MANUAL)) return EINVAL; - vap->iv_roaming = ireq->i_val; + vap->iv_roaming = (enum ieee80211_roamingmode)ireq->i_val; /* XXXX reset? */ break; case IEEE80211_IOC_PRIVACY: diff --git a/freebsd/sys/net80211/ieee80211_ioctl.h b/freebsd/sys/net80211/ieee80211_ioctl.h index 89d8fe53..cad55760 100644 --- a/freebsd/sys/net80211/ieee80211_ioctl.h +++ b/freebsd/sys/net80211/ieee80211_ioctl.h @@ -578,7 +578,7 @@ struct ieee80211req { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ uint16_t i_type; /* req type */ int16_t i_val; /* Index or simple value */ - int16_t i_len; /* Index or simple value */ + uint16_t i_len; /* Index or simple value */ void *i_data; /* Extra data */ }; #define SIOCS80211 _IOW('i', 234, struct ieee80211req) @@ -790,7 +790,7 @@ struct ieee80211req_scan_result { uint16_t isr_flags; /* channel flags */ int8_t isr_noise; int8_t isr_rssi; - uint8_t isr_intval; /* beacon interval */ + uint16_t isr_intval; /* beacon interval */ uint8_t isr_capinfo; /* capabilities */ uint8_t isr_erp; /* ERP element */ uint8_t isr_bssid[IEEE80211_ADDR_LEN]; diff --git a/freebsd/sys/net80211/ieee80211_mesh.c b/freebsd/sys/net80211/ieee80211_mesh.c index cd2ddb94..303d430c 100644 --- a/freebsd/sys/net80211/ieee80211_mesh.c +++ b/freebsd/sys/net80211/ieee80211_mesh.c @@ -84,6 +84,7 @@ static void mesh_forward(struct ieee80211vap *, struct mbuf *, static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int); static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, int, int); +static void mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int); static void mesh_peer_timeout_setup(struct ieee80211_node *); static void mesh_peer_timeout_backoff(struct ieee80211_node *); static void mesh_peer_timeout_cb(void *); @@ -98,7 +99,7 @@ uint32_t mesh_airtime_calc(struct ieee80211_node *); /* * Timeout values come from the specification and are in milliseconds. */ -SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0, +static SYSCTL_NODE(_net_wlan, OID_AUTO, mesh, CTLFLAG_RD, 0, "IEEE 802.11s parameters"); static int ieee80211_mesh_retrytimeout = -1; SYSCTL_PROC(_net_wlan_mesh, OID_AUTO, retrytimeout, CTLTYPE_INT | CTLFLAG_RW, @@ -522,6 +523,7 @@ mesh_vattach(struct ieee80211vap *vap) vap->iv_input = mesh_input; vap->iv_opdetach = mesh_vdetach; vap->iv_recv_mgmt = mesh_recv_mgmt; + vap->iv_recv_ctl = mesh_recv_ctl; ms = malloc(sizeof(struct ieee80211_mesh_state), M_80211_VAP, M_NOWAIT | M_ZERO); if (ms == NULL) { @@ -1040,7 +1042,6 @@ mesh_isucastforme(struct ieee80211vap *vap, const struct ieee80211_frame *wh, static int mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -1094,9 +1095,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr1, "duplicate", @@ -1470,11 +1469,12 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, if (xrates != NULL) IEEE80211_VERIFY_ELEMENT(xrates, IEEE80211_RATE_MAXSIZE - rates[1], return); - if (meshid != NULL) + if (meshid != NULL) { IEEE80211_VERIFY_ELEMENT(meshid, IEEE80211_MESHID_LEN, return); - /* NB: meshid, not ssid */ - IEEE80211_VERIFY_SSID(vap->iv_bss, meshid, return); + /* NB: meshid, not ssid */ + IEEE80211_VERIFY_SSID(vap->iv_bss, meshid, return); + } /* XXX find a better class or define it's own */ IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2, @@ -1488,46 +1488,42 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, ieee80211_send_proberesp(vap, wh->i_addr2, 0); break; } + case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state != IEEE80211_S_RUN) { - vap->iv_stats.is_rx_mgtdiscard++; - break; - } - /* - * We received an action for an unknown neighbor. - * XXX: wait for it to beacon or create ieee80211_node? - */ + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: if (ni == vap->iv_bss) { - IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH, + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "unknown node"); vap->iv_stats.is_rx_mgtdiscard++; - break; - } - /* - * Discard if not for us. - */ - if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { - IEEE80211_DISCARD(vap, IEEE80211_MSG_MESH, - wh, NULL, "%s", "not for me"); + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); vap->iv_stats.is_rx_mgtdiscard++; - break; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); } - /* XXX parse_action is a bit useless now */ - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); break; - case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: - case IEEE80211_FC0_SUBTYPE_DEAUTH: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "mgt", "subtype 0x%x not handled", subtype); @@ -1536,6 +1532,17 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, } } +static void +mesh_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) +{ + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } +} + /* * Parse meshpeering action ie's for open+confirm frames; the * important bits are returned in the supplied structure. @@ -2285,6 +2292,7 @@ mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie) const struct ieee80211_meshconf_ie *meshconf = (const struct ieee80211_meshconf_ie *) ie; const struct ieee80211_mesh_state *ms = vap->iv_mesh; + uint16_t cap; if (meshconf == NULL) return 1; @@ -2318,8 +2326,10 @@ mesh_verify_meshconf(struct ieee80211vap *vap, const uint8_t *ie) meshconf->conf_pselid); return 1; } + /* NB: conf_cap is only read correctly here */ + cap = LE_READ_2(&meshconf->conf_cap); /* Not accepting peers */ - if (!(meshconf->conf_cap & IEEE80211_MESHCONF_CAP_AP)) { + if (!(cap & IEEE80211_MESHCONF_CAP_AP)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MESH, "not accepting peers: 0x%x\n", meshconf->conf_cap); return 1; @@ -2383,6 +2393,7 @@ uint8_t * ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap) { const struct ieee80211_mesh_state *ms = vap->iv_mesh; + uint16_t caps; KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a MBSS vap")); @@ -2398,11 +2409,12 @@ ieee80211_add_meshconf(uint8_t *frm, struct ieee80211vap *vap) if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) *frm |= IEEE80211_MESHCONF_FORM_MP; frm += 1; + caps = 0; if (ms->ms_flags & IEEE80211_MESHFLAGS_AP) - *frm |= IEEE80211_MESHCONF_CAP_AP; + caps |= IEEE80211_MESHCONF_CAP_AP; if (ms->ms_flags & IEEE80211_MESHFLAGS_FWD) - *frm |= IEEE80211_MESHCONF_CAP_FWRD; - frm += 1; + caps |= IEEE80211_MESHCONF_CAP_FWRD; + ADDSHORT(frm, caps); return frm; } diff --git a/freebsd/sys/net80211/ieee80211_mesh.h b/freebsd/sys/net80211/ieee80211_mesh.h index de9b5c2a..ad1b02af 100644 --- a/freebsd/sys/net80211/ieee80211_mesh.h +++ b/freebsd/sys/net80211/ieee80211_mesh.h @@ -49,7 +49,7 @@ struct ieee80211_meshconf_ie { uint8_t conf_syncid; /* Sync. Protocol ID */ uint8_t conf_authid; /* Auth. Protocol ID */ uint8_t conf_form; /* Formation Information */ - uint8_t conf_cap; + uint16_t conf_cap; } __packed; /* Hybrid Wireless Mesh Protocol */ @@ -72,7 +72,8 @@ struct ieee80211_meshconf_ie { #define IEEE80211_MESHCONF_CAP_FWRD 0x08 /* forwarding enabled */ #define IEEE80211_MESHCONF_CAP_BTR 0x10 /* Beacon Timing Report Enab */ #define IEEE80211_MESHCONF_CAP_TBTTA 0x20 /* TBTT Adj. Enabled */ -#define IEEE80211_MESHCONF_CAP_PSL 0x40 /* Power Save Level */ +#define IEEE80211_MESHCONF_CAP_TBTT 0x40 /* TBTT Adjusting */ +#define IEEE80211_MESHCONF_CAP_PSL 0x80 /* Power Save Level */ /* Mesh Identifier */ struct ieee80211_meshid_ie { diff --git a/freebsd/sys/net80211/ieee80211_node.c b/freebsd/sys/net80211/ieee80211_node.c index e1166707..5bf33549 100644 --- a/freebsd/sys/net80211/ieee80211_node.c +++ b/freebsd/sys/net80211/ieee80211_node.c @@ -287,10 +287,7 @@ ieee80211_node_set_chan(struct ieee80211_node *ni, mode = ieee80211_chan2mode(chan); if (IEEE80211_IS_CHAN_HT(chan)) { /* - * XXX Gotta be careful here; the rate set returned by - * ieee80211_get_suprates is actually any HT rate - * set so blindly copying it will be bad. We must - * install the legacy rate est in ni_rates and the + * We must install the legacy rate est in ni_rates and the * HT rate set in ni_htrates. */ ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); @@ -1090,7 +1087,26 @@ static void node_getmimoinfo(const struct ieee80211_node *ni, struct ieee80211_mimo_info *info) { - /* XXX zero data? */ + int i; + uint32_t avgrssi; + int32_t rssi; + + bzero(info, sizeof(*info)); + + for (i = 0; i < ni->ni_mimo_chains; i++) { + avgrssi = ni->ni_mimo_rssi_ctl[i]; + if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) { + info->rssi[i] = 0; + } else { + rssi = IEEE80211_RSSI_GET(avgrssi); + info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi; + } + info->noise[i] = ni->ni_mimo_noise_ctl[i]; + } + + /* XXX ext radios? */ + + /* XXX EVM? */ } struct ieee80211_node * diff --git a/freebsd/sys/net80211/ieee80211_node.h b/freebsd/sys/net80211/ieee80211_node.h index 01bb2cf1..c1fc0069 100644 --- a/freebsd/sys/net80211/ieee80211_node.h +++ b/freebsd/sys/net80211/ieee80211_node.h @@ -166,6 +166,13 @@ struct ieee80211_node { uint32_t ni_avgrssi; /* recv ssi state */ int8_t ni_noise; /* noise floor */ + /* mimo statistics */ + uint32_t ni_mimo_rssi_ctl[IEEE80211_MAX_CHAINS]; + uint32_t ni_mimo_rssi_ext[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_noise_ctl[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_noise_ext[IEEE80211_MAX_CHAINS]; + uint8_t ni_mimo_chains; + /* header */ uint8_t ni_macaddr[IEEE80211_ADDR_LEN]; uint8_t ni_bssid[IEEE80211_ADDR_LEN]; diff --git a/freebsd/sys/net80211/ieee80211_output.c b/freebsd/sys/net80211/ieee80211_output.c index 81aa7fb6..229c87ea 100644 --- a/freebsd/sys/net80211/ieee80211_output.c +++ b/freebsd/sys/net80211/ieee80211_output.c @@ -59,8 +59,11 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_wds.h> #include <net80211/ieee80211_mesh.h> -#ifdef INET +#if defined(INET) || defined(INET6) #include <netinet/in.h> +#endif + +#ifdef INET #include <netinet/if_ether.h> #include <netinet/in_systm.h> #include <netinet/ip.h> @@ -421,7 +424,8 @@ ieee80211_output(struct ifnet *ifp, struct mbuf *m, "block %s frame in CAC state\n", "raw data"); vap->iv_stats.is_tx_badstate++; senderr(EIO); /* XXX */ - } + } else if (vap->iv_state == IEEE80211_S_SCAN) + senderr(EIO); /* XXX bypass bridge, pfil, carp, etc. */ if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) @@ -514,6 +518,7 @@ ieee80211_send_setup( { #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_tx_ampdu *tap; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); ieee80211_seq seqno; @@ -581,9 +586,15 @@ ieee80211_send_setup( } *(uint16_t *)&wh->i_dur[0] = 0; - seqno = ni->ni_txseqs[tid]++; - *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); - M_SEQNO_SET(m, seqno); + tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)]; + if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) + m->m_flags |= M_AMPDU_MPDU; + else { + seqno = ni->ni_txseqs[tid]++; + *(uint16_t *)&wh->i_seq[0] = + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + M_SEQNO_SET(m, seqno); + } if (IEEE80211_IS_MULTICAST(wh->i_addr1)) m->m_flags |= M_MCAST; @@ -2783,6 +2794,8 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; uint16_t capinfo; + struct ieee80211_frame *wh; + ieee80211_seq seqno; IEEE80211_LOCK(ic); /* @@ -2814,6 +2827,12 @@ ieee80211_beacon_update(struct ieee80211_node *ni, return 1; /* just assume length changed */ } + wh = mtod(m, struct ieee80211_frame *); + seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + *(uint16_t *)&wh->i_seq[0] = + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + M_SEQNO_SET(m, seqno); + /* XXX faster to recalculate entirely or just changes? */ capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); *bo->bo_caps = htole16(capinfo); @@ -2924,13 +2943,13 @@ ieee80211_beacon_update(struct ieee80211_node *ni, bo->bo_tim_trailer += adjust; bo->bo_erp += adjust; bo->bo_htinfo += adjust; -#ifdef IEEE80211_SUPERG_SUPPORT +#ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += adjust; #endif -#ifdef IEEE80211_TDMA_SUPPORT +#ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += adjust; #endif -#ifdef IEEE80211_MESH_SUPPORT +#ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += adjust; #endif bo->bo_appie += adjust; @@ -2978,13 +2997,13 @@ ieee80211_beacon_update(struct ieee80211_node *ni, bo->bo_erp += sizeof(*csa); bo->bo_htinfo += sizeof(*csa); bo->bo_wme += sizeof(*csa); -#ifdef IEEE80211_SUPERG_SUPPORT +#ifdef IEEE80211_SUPPORT_SUPERG bo->bo_ath += sizeof(*csa); #endif -#ifdef IEEE80211_TDMA_SUPPORT +#ifdef IEEE80211_SUPPORT_TDMA bo->bo_tdma += sizeof(*csa); #endif -#ifdef IEEE80211_MESH_SUPPORT +#ifdef IEEE80211_SUPPORT_MESH bo->bo_meshconf += sizeof(*csa); #endif bo->bo_appie += sizeof(*csa); diff --git a/freebsd/sys/net80211/ieee80211_power.c b/freebsd/sys/net80211/ieee80211_power.c index b39e7156..dde58269 100644 --- a/freebsd/sys/net80211/ieee80211_power.c +++ b/freebsd/sys/net80211/ieee80211_power.c @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); static void ieee80211_update_ps(struct ieee80211vap *, int); static int ieee80211_set_tim(struct ieee80211_node *, int); -MALLOC_DEFINE(M_80211_POWER, "80211power", "802.11 power save state"); +static MALLOC_DEFINE(M_80211_POWER, "80211power", "802.11 power save state"); void ieee80211_power_attach(struct ieee80211com *ic) @@ -104,7 +104,7 @@ ieee80211_power_vdetach(struct ieee80211vap *vap) void ieee80211_psq_init(struct ieee80211_psq *psq, const char *name) { - memset(psq, 0, sizeof(psq)); + memset(psq, 0, sizeof(*psq)); psq->psq_maxlen = IEEE80211_PS_MAX_QUEUE; IEEE80211_PSQ_INIT(psq, name); /* OS-dependent setup */ } diff --git a/freebsd/sys/net80211/ieee80211_proto.c b/freebsd/sys/net80211/ieee80211_proto.c index a0a6a0fa..2f9e60b8 100644 --- a/freebsd/sys/net80211/ieee80211_proto.c +++ b/freebsd/sys/net80211/ieee80211_proto.c @@ -66,7 +66,7 @@ const char *ieee80211_mgt_subtype_name[] = { "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", "probe_req", "probe_resp", "reserved#6", "reserved#7", "beacon", "atim", "disassoc", "auth", - "deauth", "action", "reserved#14", "reserved#15" + "deauth", "action", "action_noack", "reserved#15" }; const char *ieee80211_ctl_subtype_name[] = { "reserved#0", "reserved#1", "reserved#2", "reserved#3", @@ -209,6 +209,21 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) const struct ieee80211_rateset *rs = &ic->ic_sup_rates[i]; vap->iv_txparms[i].ucastrate = IEEE80211_FIXED_RATE_NONE; + + /* + * Setting the management rate to MCS 0 assumes that the + * BSS Basic rate set is empty and the BSS Basic MCS set + * is not. + * + * Since we're not checking this, default to the lowest + * defined rate for this mode. + * + * At least one 11n AP (DLINK DIR-825) is reported to drop + * some MCS management traffic (eg BA response frames.) + * + * See also: 9.6.0 of the 802.11n-2009 specification. + */ +#ifdef NOTYET if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS; vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS; @@ -218,6 +233,9 @@ ieee80211_proto_vattach(struct ieee80211vap *vap) vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; } +#endif + vap->iv_txparms[i].mgmtrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; + vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; } vap->iv_roaming = IEEE80211_ROAMING_AUTO; @@ -880,6 +898,15 @@ ieee80211_wme_initparams_locked(struct ieee80211vap *vap) return; /* + * Clear the wme cap_info field so a qoscount from a previous + * vap doesn't confuse later code which only parses the beacon + * field and updates hardware when said field changes. + * Otherwise the hardware is programmed with defaults, not what + * the beacon actually announces. + */ + wme->wme_wmeChanParams.cap_info = 0; + + /* * Select mode; we can be called early in which case we * always use auto mode. We know we'll be called when * entering the RUN state with bsschan setup properly @@ -1476,6 +1503,11 @@ ieee80211_csa_startswitch(struct ieee80211com *ic, ieee80211_notify_csa(ic, c, mode, count); } +/* + * Complete the channel switch by transitioning all CSA VAPs to RUN. + * This is called by both the completion and cancellation functions + * so each VAP is placed back in the RUN state and can thus transmit. + */ static void csa_completeswitch(struct ieee80211com *ic) { @@ -1493,15 +1525,27 @@ csa_completeswitch(struct ieee80211com *ic) * Complete an 802.11h channel switch started by ieee80211_csa_startswitch. * We clear state and move all vap's in CSA state to RUN state * so they can again transmit. + * + * Although this may not be completely correct, update the BSS channel + * for each VAP to the newly configured channel. The setcurchan sets + * the current operating channel for the interface (so the radio does + * switch over) but the VAP BSS isn't updated, leading to incorrectly + * reported information via ioctl. */ void ieee80211_csa_completeswitch(struct ieee80211com *ic) { + struct ieee80211vap *vap; + IEEE80211_LOCK_ASSERT(ic); KASSERT(ic->ic_flags & IEEE80211_F_CSAPENDING, ("csa not pending")); ieee80211_setcurchan(ic, ic->ic_csa_newchan); + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_state == IEEE80211_S_CSA) + vap->iv_bss->ni_chan = ic->ic_curchan; + csa_completeswitch(ic); } diff --git a/freebsd/sys/net80211/ieee80211_proto.h b/freebsd/sys/net80211/ieee80211_proto.h index c2808477..7e882161 100644 --- a/freebsd/sys/net80211/ieee80211_proto.h +++ b/freebsd/sys/net80211/ieee80211_proto.h @@ -61,9 +61,36 @@ void ieee80211_syncflag(struct ieee80211vap *, int flag); void ieee80211_syncflag_ht(struct ieee80211vap *, int flag); void ieee80211_syncflag_ext(struct ieee80211vap *, int flag); +#define IEEE80211_R_NF 0x0000001 /* global NF value valid */ +#define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */ +#define IEEE80211_R_C_CHAIN 0x0000004 /* RX chain count valid */ +#define IEEE80211_R_C_NF 0x0000008 /* per-chain NF value valid */ +#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI value valid */ +#define IEEE80211_R_C_EVM 0x0000020 /* per-chain EVM valid */ +#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */ + +struct ieee80211_rx_stats { + uint32_t r_flags; /* IEEE80211_R_* flags */ + uint8_t c_chain; /* number of RX chains involved */ + int16_t c_nf_ctl[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_nf_ext[IEEE80211_MAX_CHAINS]; /* per-chain NF */ + int16_t c_rssi_ctl[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + int16_t c_rssi_ext[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */ + uint8_t nf; /* global NF */ + uint8_t rssi; /* global RSSI */ + uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS]; + /* per-chain, per-pilot EVM values */ +}; + #define ieee80211_input(ni, m, rssi, nf) \ ((ni)->ni_vap->iv_input(ni, m, rssi, nf)) int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int); + +int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *, + struct ieee80211_rx_stats *); +int ieee80211_input_mimo_all(struct ieee80211com *, struct mbuf *, + struct ieee80211_rx_stats *); + struct ieee80211_bpf_params; int ieee80211_mgmt_output(struct ieee80211_node *, struct mbuf *, int, struct ieee80211_bpf_params *); diff --git a/freebsd/sys/net80211/ieee80211_scan.c b/freebsd/sys/net80211/ieee80211_scan.c index 16eeae7d..19becf8f 100644 --- a/freebsd/sys/net80211/ieee80211_scan.c +++ b/freebsd/sys/net80211/ieee80211_scan.c @@ -418,6 +418,8 @@ start_scan_locked(const struct ieee80211_scanner *scan, vap->iv_stats.is_scan_passive++; if (flags & IEEE80211_SCAN_FLUSH) ss->ss_ops->scan_flush(ss); + if (flags & IEEE80211_SCAN_BGSCAN) + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; /* NB: flush frames rx'd before 1st channel change */ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; @@ -434,12 +436,13 @@ start_scan_locked(const struct ieee80211_scanner *scan, ic->ic_flags |= IEEE80211_F_SCAN; ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); } + return 1; } else { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: %s scan already in progress\n", __func__, ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"); } - return (ic->ic_flags & IEEE80211_F_SCAN); + return 0; } /* diff --git a/freebsd/sys/net80211/ieee80211_scan_sta.c b/freebsd/sys/net80211/ieee80211_scan_sta.c index eb5bcd7c..7cf485c8 100644 --- a/freebsd/sys/net80211/ieee80211_scan_sta.c +++ b/freebsd/sys/net80211/ieee80211_scan_sta.c @@ -240,6 +240,7 @@ sta_add(struct ieee80211_scan_state *ss, const uint8_t *macaddr = wh->i_addr2; struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_channel *c; struct sta_entry *se; struct ieee80211_scan_entry *ise; int hash; @@ -302,7 +303,6 @@ found: * association on the wrong channel. */ if (sp->status & IEEE80211_BPARSE_OFFCHAN) { - struct ieee80211_channel *c; /* * Off-channel, locate the home/bss channel for the sta * using the value broadcast in the DSPARMS ie. We know @@ -319,6 +319,14 @@ found: } } else ise->se_chan = ic->ic_curchan; + if (IEEE80211_IS_CHAN_HT(ise->se_chan) && sp->htcap == NULL) { + /* Demote legacy networks to a non-HT channel. */ + c = ieee80211_find_channel(ic, ise->se_chan->ic_freq, + ise->se_chan->ic_flags & ~IEEE80211_CHAN_HT); + KASSERT(c != NULL, + ("no legacy channel %u", ise->se_chan->ic_ieee)); + ise->se_chan = c; + } ise->se_fhdwell = sp->fhdwell; ise->se_fhindex = sp->fhindex; ise->se_erp = sp->erp; @@ -758,26 +766,38 @@ maxrate(const struct ieee80211_scan_entry *se) { const struct ieee80211_ie_htcap *htcap = (const struct ieee80211_ie_htcap *) se->se_ies.htcap_ie; - int rmax, r, i; + int rmax, r, i, txstream; uint16_t caps; + uint8_t txparams; rmax = 0; if (htcap != NULL) { /* * HT station; inspect supported MCS and then adjust - * rate by channel width. Could also include short GI - * in this if we want to be extra accurate. + * rate by channel width. */ - /* XXX assumes MCS15 is max */ - for (i = 15; i >= 0 && isclr(htcap->hc_mcsset, i); i--) - ; + txparams = htcap->hc_mcsset[12]; + if (txparams & 0x3) { + /* + * TX MCS parameters defined and not equal to RX, + * extract the number of spartial streams and + * map it to the highest MCS rate. + */ + txstream = ((txparams & 0xc) >> 2) + 1; + i = txstream * 8 - 1; + } else + for (i = 31; i >= 0 && isclr(htcap->hc_mcsset, i); i--); if (i >= 0) { caps = LE_READ_2(&htcap->hc_cap); - /* XXX short/long GI */ - if (caps & IEEE80211_HTCAP_CHWIDTH40) + if ((caps & IEEE80211_HTCAP_CHWIDTH40) && + (caps & IEEE80211_HTCAP_SHORTGI40)) rmax = ieee80211_htrates[i].ht40_rate_400ns; - else + else if (caps & IEEE80211_HTCAP_CHWIDTH40) rmax = ieee80211_htrates[i].ht40_rate_800ns; + else if (caps & IEEE80211_HTCAP_SHORTGI20) + rmax = ieee80211_htrates[i].ht20_rate_400ns; + else + rmax = ieee80211_htrates[i].ht20_rate_800ns; } } for (i = 0; i < se->se_rates[1]; i++) { diff --git a/freebsd/sys/net80211/ieee80211_sta.c b/freebsd/sys/net80211/ieee80211_sta.c index f709d51e..c96eb0b5 100644 --- a/freebsd/sys/net80211/ieee80211_sta.c +++ b/freebsd/sys/net80211/ieee80211_sta.c @@ -436,7 +436,7 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) goto invalid; break; case IEEE80211_S_SLEEP: - ieee80211_sta_pwrsave(vap, 0); + ieee80211_sta_pwrsave(vap, 1); break; default: invalid: @@ -514,7 +514,6 @@ doprint(struct ieee80211vap *vap, int subtype) static int sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -593,9 +592,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, bssid, "duplicate", @@ -912,7 +909,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -1546,7 +1542,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, htcap = frm; } else if (ishtinfooui(frm)) { if (htinfo == NULL) - htcap = frm; + htinfo = frm; } } /* XXX Atheros OUI support */ @@ -1720,21 +1716,35 @@ 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, wh, frm, efrm); - } else + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } break; - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_ATIM: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; - return; + break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } @@ -1743,6 +1753,11 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, } static void -sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype) +sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m, int subtype) { + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; + } } diff --git a/freebsd/sys/net80211/ieee80211_var.h b/freebsd/sys/net80211/ieee80211_var.h index d790bfc2..e4b00099 100644 --- a/freebsd/sys/net80211/ieee80211_var.h +++ b/freebsd/sys/net80211/ieee80211_var.h @@ -137,6 +137,7 @@ struct ieee80211com { uint32_t ic_flags_ven; /* vendor state flags */ uint32_t ic_caps; /* capabilities */ uint32_t ic_htcaps; /* HT capabilities */ + uint32_t ic_htextcaps; /* HT extended capabilities */ uint32_t ic_cryptocaps; /* crypto capabilities */ uint8_t ic_modecaps[2]; /* set of mode capabilities */ uint8_t ic_promisc; /* vap's needing promisc mode */ @@ -212,6 +213,8 @@ struct ieee80211com { enum ieee80211_protmode ic_htprotmode; /* HT protection mode */ int ic_lastnonerp; /* last time non-ERP sta noted*/ int ic_lastnonht; /* last time non-HT sta noted */ + uint8_t ic_rxstream; /* # RX streams */ + uint8_t ic_txstream; /* # TX streams */ /* optional state for Atheros SuperG protocol extensions */ struct ieee80211_superg *ic_superg; @@ -225,10 +228,10 @@ struct ieee80211com { /* virtual ap create/delete */ struct ieee80211vap* (*ic_vap_create)(struct ieee80211com *, - const char name[IFNAMSIZ], int unit, - int opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t macaddr[IEEE80211_ADDR_LEN]); + const char [IFNAMSIZ], int, + enum ieee80211_opmode, int, + const uint8_t [IEEE80211_ADDR_LEN], + const uint8_t [IEEE80211_ADDR_LEN]); void (*ic_vap_delete)(struct ieee80211vap *); /* operating mode attachment */ ieee80211vap_attach ic_vattach[IEEE80211_OPMODE_MAX]; @@ -304,6 +307,8 @@ struct ieee80211com { int status, int baparamset, int batimeout); void (*ic_addba_stop)(struct ieee80211_node *, struct ieee80211_tx_ampdu *); + void (*ic_addba_response_timeout)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *); /* BAR response received */ void (*ic_bar_response)(struct ieee80211_node *, struct ieee80211_tx_ampdu *, int status); @@ -313,7 +318,7 @@ struct ieee80211com { int batimeout, int baseqctl); void (*ic_ampdu_rx_stop)(struct ieee80211_node *, struct ieee80211_rx_ampdu *); - uint64_t ic_spare[8]; + uint64_t ic_spare[7]; }; struct ieee80211_aclator; @@ -340,6 +345,7 @@ struct ieee80211vap { uint32_t iv_flags_ven; /* vendor state flags */ uint32_t iv_caps; /* capabilities */ uint32_t iv_htcaps; /* HT capabilities */ + uint32_t iv_htextcaps; /* HT extended capabilities */ enum ieee80211_opmode iv_opmode; /* operation mode */ enum ieee80211_state iv_state; /* state machine state */ enum ieee80211_state iv_nstate; /* pending state */ @@ -574,7 +580,7 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_FHT_BITS \ "\20\1NONHT_PR" \ - "\23GF\24HT\25AMDPU_TX\26AMPDU_TX" \ + "\23GF\24HT\25AMPDU_TX\26AMPDU_TX" \ "\27AMSDU_TX\30AMSDU_RX\31USEHT40\32PUREN\33SHORTGI20\34SHORTGI40" \ "\35HTCOMPAT\36RIFS\37STBC_TX\40STBC_RX" @@ -633,6 +639,10 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_HTC_HT 0x00040000 /* CAPABILITY: HT operation */ #define IEEE80211_HTC_SMPS 0x00080000 /* CAPABILITY: MIMO power save*/ #define IEEE80211_HTC_RIFS 0x00100000 /* CAPABILITY: RIFS support */ +#define IEEE80211_HTC_RXUNEQUAL 0x00200000 /* CAPABILITY: RX unequal MCS */ +#define IEEE80211_HTC_RXMCS32 0x00400000 /* CAPABILITY: MCS32 support */ +#define IEEE80211_HTC_TXUNEQUAL 0x00800000 /* CAPABILITY: TX unequal MCS */ +#define IEEE80211_HTC_TXMCS32 0x01000000 /* CAPABILITY: MCS32 suport */ #define IEEE80211_C_HTCAP_BITS \ "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \ @@ -642,7 +652,8 @@ void ieee80211_ifattach(struct ieee80211com *, const uint8_t macaddr[IEEE80211_ADDR_LEN]); void ieee80211_ifdetach(struct ieee80211com *); int ieee80211_vap_setup(struct ieee80211com *, struct ieee80211vap *, - const char name[IFNAMSIZ], int unit, int opmode, int flags, + const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t macaddr[IEEE80211_ADDR_LEN]); int ieee80211_vap_attach(struct ieee80211vap *, diff --git a/freebsd/sys/net80211/ieee80211_wds.c b/freebsd/sys/net80211/ieee80211_wds.c index 55c2833b..0c5ea68b 100644 --- a/freebsd/sys/net80211/ieee80211_wds.c +++ b/freebsd/sys/net80211/ieee80211_wds.c @@ -408,7 +408,6 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) { -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define HAS_SEQ(type) ((type & 0x4) == 0) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; @@ -456,6 +455,9 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) */ wh = mtod(m, struct ieee80211_frame *); + if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) + ni->ni_inact = ni->ni_inact_reload; + if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, @@ -494,9 +496,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; rxseq = le16toh(*(uint16_t *)wh->i_seq); - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && - (wh->i_fc[1] & IEEE80211_FC1_RETRY) && - SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { + if (! ieee80211_check_rxseq(ni, wh)) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr1, "duplicate", @@ -538,8 +538,6 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) vap->iv_stats.is_rx_wrongdir++;/*XXX*/ goto out; } - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) - ni->ni_inact = ni->ni_inact_reload; /* * Handle A-MPDU re-ordering. If the frame is to be * processed directly then ieee80211_ampdu_reorder @@ -742,7 +740,6 @@ out: m_freem(m); } return type; -#undef SEQ_LEQ } static void @@ -758,31 +755,47 @@ wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, frm = (u_int8_t *)&wh[1]; efrm = mtod(m0, u_int8_t *) + m0->m_len; switch (subtype) { - case IEEE80211_FC0_SUBTYPE_DEAUTH: - case IEEE80211_FC0_SUBTYPE_PROBE_RESP: - case IEEE80211_FC0_SUBTYPE_BEACON: - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_ACTION: + case IEEE80211_FC0_SUBTYPE_ACTION_NOACK: + if (ni == vap->iv_bss) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "unknown node"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr1)) { + /* NB: not interested in multicast frames. */ + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not for us"); + vap->iv_stats.is_rx_mgtdiscard++; + } else if (vap->iv_state != IEEE80211_S_RUN) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "wrong state %s", + ieee80211_state_name[vap->iv_state]); + vap->iv_stats.is_rx_mgtdiscard++; + } else { + if (ieee80211_parse_action(ni, m0) == 0) + (void)ic->ic_recv_action(ni, wh, frm, efrm); + } + break; + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: - case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + case IEEE80211_FC0_SUBTYPE_ATIM: case IEEE80211_FC0_SUBTYPE_DISASSOC: + case IEEE80211_FC0_SUBTYPE_AUTH: + case IEEE80211_FC0_SUBTYPE_DEAUTH: + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, + wh, NULL, "%s", "not handled"); vap->iv_stats.is_rx_mgtdiscard++; break; - case IEEE80211_FC0_SUBTYPE_ACTION: - if (vap->iv_state != IEEE80211_S_RUN || - IEEE80211_IS_MULTICAST(wh->i_addr1)) { - vap->iv_stats.is_rx_mgtdiscard++; - break; - } - ni->ni_inact = ni->ni_inact_reload; - if (ieee80211_parse_action(ni, m0) == 0) - ic->ic_recv_action(ni, wh, frm, efrm); - break; + default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, - wh, "mgt", "subtype 0x%x not handled", subtype); + wh, "mgt", "subtype 0x%x not handled", subtype); vap->iv_stats.is_rx_badsubtype++; break; } |