diff options
author | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-03-03 01:06:27 +0000 |
---|---|---|
committer | Andriy Voskoboinyk <avos@FreeBSD.org> | 2017-03-03 01:06:27 +0000 |
commit | dfabbaa0e030669f8ccddb4d52e85e96e8fcf39c (patch) | |
tree | 65068da874772f9a391680aaaf06aa2ce6fcfc40 /sys/net80211/ieee80211_ioctl.c | |
parent | 0132c9cd4ac9a4cf86ff858e22cab39fc446ba93 (diff) | |
download | src-dfabbaa0e030669f8ccddb4d52e85e96e8fcf39c.tar.gz src-dfabbaa0e030669f8ccddb4d52e85e96e8fcf39c.zip |
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
Notes
Notes:
svn path=/head/; revision=314575
Diffstat (limited to 'sys/net80211/ieee80211_ioctl.c')
-rw-r--r-- | sys/net80211/ieee80211_ioctl.c | 18 |
1 files changed, 13 insertions, 5 deletions
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++; } |