summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net80211
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-06 16:20:21 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-11-11 10:08:08 +0100
commit66659ff1ad6831b0ea7425fa6ecd8a8687523658 (patch)
tree48e22b475fa8854128e0861a33fed6f78c8094b5 /freebsd/sys/net80211
parentDefine __GLOBL1() and __GLOBL() (diff)
downloadrtems-libbsd-66659ff1ad6831b0ea7425fa6ecd8a8687523658.tar.bz2
Update to FreeBSD 9.2
Diffstat (limited to 'freebsd/sys/net80211')
-rw-r--r--freebsd/sys/net80211/_ieee80211.h15
-rw-r--r--freebsd/sys/net80211/ieee80211.c101
-rw-r--r--freebsd/sys/net80211/ieee80211.h1
-rw-r--r--freebsd/sys/net80211/ieee80211_acl.c7
-rw-r--r--freebsd/sys/net80211/ieee80211_adhoc.c124
-rw-r--r--freebsd/sys/net80211/ieee80211_ageq.c2
-rw-r--r--freebsd/sys/net80211/ieee80211_crypto.h4
-rw-r--r--freebsd/sys/net80211/ieee80211_crypto_ccmp.c3
-rw-r--r--freebsd/sys/net80211/ieee80211_crypto_tkip.c3
-rw-r--r--freebsd/sys/net80211/ieee80211_dfs.c4
-rw-r--r--freebsd/sys/net80211/ieee80211_freebsd.c2
-rw-r--r--freebsd/sys/net80211/ieee80211_hostap.c36
-rw-r--r--freebsd/sys/net80211/ieee80211_ht.c417
-rw-r--r--freebsd/sys/net80211/ieee80211_ht.h5
-rw-r--r--freebsd/sys/net80211/ieee80211_hwmp.c2
-rw-r--r--freebsd/sys/net80211/ieee80211_input.c48
-rw-r--r--freebsd/sys/net80211/ieee80211_input.h98
-rw-r--r--freebsd/sys/net80211/ieee80211_ioctl.c182
-rw-r--r--freebsd/sys/net80211/ieee80211_ioctl.h4
-rw-r--r--freebsd/sys/net80211/ieee80211_mesh.c86
-rw-r--r--freebsd/sys/net80211/ieee80211_mesh.h5
-rw-r--r--freebsd/sys/net80211/ieee80211_node.c26
-rw-r--r--freebsd/sys/net80211/ieee80211_node.h7
-rw-r--r--freebsd/sys/net80211/ieee80211_output.c41
-rw-r--r--freebsd/sys/net80211/ieee80211_power.c4
-rw-r--r--freebsd/sys/net80211/ieee80211_proto.c46
-rw-r--r--freebsd/sys/net80211/ieee80211_proto.h27
-rw-r--r--freebsd/sys/net80211/ieee80211_scan.c5
-rw-r--r--freebsd/sys/net80211/ieee80211_scan_sta.c40
-rw-r--r--freebsd/sys/net80211/ieee80211_sta.c45
-rw-r--r--freebsd/sys/net80211/ieee80211_var.h25
-rw-r--r--freebsd/sys/net80211/ieee80211_wds.c61
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;
}