From dfabbaa0e030669f8ccddb4d52e85e96e8fcf39c Mon Sep 17 00:00:00 2001 From: Andriy Voskoboinyk Date: Fri, 3 Mar 2017 01:06:27 +0000 Subject: [PATCH] net80211: fix ieee80211_htrateset setup, return EINVAL for an unsupported ucast/mcast/mgmt HT rate. - Init global ieee80211_htrateset only once; neither ic_htcaps nor ic_txstream is changed when device is attached; - Move global ieee80211_htrateset structure to ieee80211com; there was a possible data race when more than 1 wireless device is used simultaneously; - Discard unsupported rates in ieee80211_ioctl_settxparams(); otherwise, an unsupported value may break connectivity (actually, 'ifconfig wlan0 ucastrate 8' for RTL8188EU results in immediate disconnect + infinite 'device timeout's after it). Tested with: - Intel 6205, STA mode. - RTL8821AU, STA mode. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D9871 --- sys/net80211/ieee80211.c | 10 ++++++++++ sys/net80211/ieee80211_ht.c | 15 ++++++--------- sys/net80211/ieee80211_ht.h | 3 +-- sys/net80211/ieee80211_ioctl.c | 18 +++++++++++++----- sys/net80211/ieee80211_var.h | 3 +++ 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 77b5513f3902..05939f100fc1 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -242,6 +242,8 @@ ieee80211_chan_init(struct ieee80211com *ic) if (ic->ic_txstream == 0) ic->ic_txstream = 2; + ieee80211_init_suphtrates(ic); + /* * Set auto mode to reset active channel state and any desired channel. */ @@ -1905,6 +1907,14 @@ ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel * return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; } +/* XXX inline or eliminate? */ +const struct ieee80211_htrateset * +ieee80211_get_suphtrates(struct ieee80211com *ic, + const struct ieee80211_channel *c) +{ + return &ic->ic_sup_htrates; +} + void ieee80211_announce(struct ieee80211com *ic) { diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 4ee6b2489f40..1c4d954896ee 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -421,19 +421,17 @@ ieee80211_ht_announce(struct ieee80211com *ic) 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) +void +ieee80211_init_suphtrates(struct ieee80211com *ic) { #define ADDRATE(x) do { \ - htrateset.rs_rates[htrateset.rs_nrates] = x; \ - htrateset.rs_nrates++; \ + htrateset->rs_rates[htrateset->rs_nrates] = x; \ + htrateset->rs_nrates++; \ } while (0) + struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates; int i; - memset(&htrateset, 0, sizeof(struct ieee80211_htrateset)); + 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) && @@ -453,7 +451,6 @@ ieee80211_get_suphtrates(struct ieee80211com *ic, ADDRATE(i); } } - return &htrateset; #undef ADDRATE } diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h index b34d4edf3895..5b818a28b71a 100644 --- a/sys/net80211/ieee80211_ht.h +++ b/sys/net80211/ieee80211_ht.h @@ -177,8 +177,7 @@ struct ieee80211_mcs_rates { uint16_t ht40_rate_400ns; }; extern const struct ieee80211_mcs_rates ieee80211_htrates[]; -const struct ieee80211_htrateset *ieee80211_get_suphtrates( - struct ieee80211com *, const struct ieee80211_channel *); +void ieee80211_init_suphtrates(struct ieee80211com *); struct ieee80211_node; int ieee80211_setup_htrates(struct ieee80211_node *, diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 613eb84a05ef..9939ca34bb89 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -2226,13 +2226,19 @@ checkrate(const struct ieee80211_rateset *rs, int rate) } static int -checkmcs(int mcs) +checkmcs(const struct ieee80211_htrateset *rs, int mcs) { + int rate_val = IEEE80211_RV(mcs); + int i; + if (mcs == IEEE80211_FIXED_RATE_NONE) return 1; if ((mcs & IEEE80211_RATE_MCS) == 0) /* MCS always have 0x80 set */ return 0; - return (mcs & 0x7f) <= 31; /* XXX could search ht rate set */ + for (i = 0; i < rs->rs_nrates; i++) + if (IEEE80211_RV(rs->rs_rates[i]) == rate_val) + return 1; + return 0; } static int @@ -2242,6 +2248,7 @@ ieee80211_ioctl_settxparams(struct ieee80211vap *vap, struct ieee80211com *ic = vap->iv_ic; struct ieee80211_txparams_req parms; /* XXX stack use? */ struct ieee80211_txparam *src, *dst; + const struct ieee80211_htrateset *rs_ht; const struct ieee80211_rateset *rs; int error, mode, changed, is11n, nmodes; @@ -2260,23 +2267,24 @@ ieee80211_ioctl_settxparams(struct ieee80211vap *vap, src = &parms.params[mode]; dst = &vap->iv_txparms[mode]; rs = &ic->ic_sup_rates[mode]; /* NB: 11n maps to legacy */ + rs_ht = &ic->ic_sup_htrates; is11n = (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG); if (src->ucastrate != dst->ucastrate) { if (!checkrate(rs, src->ucastrate) && - (!is11n || !checkmcs(src->ucastrate))) + (!is11n || !checkmcs(rs_ht, src->ucastrate))) return EINVAL; changed++; } if (src->mcastrate != dst->mcastrate) { if (!checkrate(rs, src->mcastrate) && - (!is11n || !checkmcs(src->mcastrate))) + (!is11n || !checkmcs(rs_ht, src->mcastrate))) return EINVAL; changed++; } if (src->mgmtrate != dst->mgmtrate) { if (!checkrate(rs, src->mgmtrate) && - (!is11n || !checkmcs(src->mgmtrate))) + (!is11n || !checkmcs(rs_ht, src->mgmtrate))) return EINVAL; changed++; } diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 7c972944a76b..175d95fc6444 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -175,6 +175,7 @@ struct ieee80211com { uint16_t ic_holdover; /* PM hold over duration */ uint16_t ic_txpowlimit; /* global tx power limit */ struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; + struct ieee80211_htrateset ic_sup_htrates; /* * Channel state: @@ -692,6 +693,8 @@ int ieee80211_vap_attach(struct ieee80211vap *, void ieee80211_vap_detach(struct ieee80211vap *); const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *); +const struct ieee80211_htrateset *ieee80211_get_suphtrates( + struct ieee80211com *, const struct ieee80211_channel *); void ieee80211_announce(struct ieee80211com *); void ieee80211_announce_channels(struct ieee80211com *); void ieee80211_drain(struct ieee80211com *);