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
This commit is contained in:
parent
0132c9cd4a
commit
dfabbaa0e0
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 *,
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user