Revamp ht ie handling:
o change ieee80211_parse_htcap and ieee80211_parse_htinfo to save only internal state obtained from the ie's; no dynamic state such as ni_chw is altered o add ieee80211_ht_updateparams to parse ht cap+info ie's and update dynamic node state o change ieee80211_ht_node_init to not take an htcap ie that is parsed; instead have the caller make a separate call as one caller wants to parse the ie while another wants to parse both cap+info ie's and update state so can better do this with ieee80211_ht_updateparams These changes fix sta mode state handling where the node's channel width was shifted to ht20/ht40 prematurely.
This commit is contained in:
parent
bd985970b6
commit
fdabd982e7
@ -2038,7 +2038,8 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
|
||||
vap->iv_stats.is_ht_assoc_norate++;
|
||||
return;
|
||||
}
|
||||
ieee80211_ht_node_init(ni, htcap);
|
||||
ieee80211_ht_node_init(ni);
|
||||
ieee80211_ht_updatehtcap(ni, htcap);
|
||||
} else if (ni->ni_flags & IEEE80211_NODE_HT)
|
||||
ieee80211_ht_node_cleanup(ni);
|
||||
/*
|
||||
|
@ -783,7 +783,7 @@ ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
|
||||
* work for temporary and/or legacy sta's.
|
||||
*/
|
||||
void
|
||||
ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
|
||||
ieee80211_ht_node_init(struct ieee80211_node *ni)
|
||||
{
|
||||
struct ieee80211_tx_ampdu *tap;
|
||||
int ac;
|
||||
@ -796,7 +796,6 @@ ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
|
||||
*/
|
||||
ieee80211_ht_node_cleanup(ni);
|
||||
}
|
||||
ieee80211_parse_htcap(ni, htcap);
|
||||
for (ac = 0; ac < WME_NUM_AC; ac++) {
|
||||
tap = &ni->ni_tx_ampdu[ac];
|
||||
tap->txa_ac = ac;
|
||||
@ -1146,8 +1145,6 @@ ieee80211_ht_timeout(struct ieee80211com *ic)
|
||||
void
|
||||
ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
|
||||
if (ie[0] == IEEE80211_ELEMID_VENDOR) {
|
||||
/*
|
||||
* Station used Vendor OUI ie to associate;
|
||||
@ -1162,55 +1159,54 @@ ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
ni->ni_htcap = LE_READ_2(ie +
|
||||
__offsetof(struct ieee80211_ie_htcap, hc_cap));
|
||||
ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
|
||||
/* XXX needed or will ieee80211_parse_htinfo always be called? */
|
||||
ni->ni_chw = (ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_USEHT40) ? 40 : 20;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an 802.11n HT info ie and update the node state.
|
||||
* Note that we handle use this information to identify the
|
||||
* correct channel (HT20, HT40+, HT40-, legacy). The caller
|
||||
* is responsible for insuring any required channel change is
|
||||
* done (e.g. in sta mode when parsing the contents of a
|
||||
* beacon frame).
|
||||
*/
|
||||
void
|
||||
ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
static void
|
||||
htinfo_parse(struct ieee80211_node *ni,
|
||||
const struct ieee80211_ie_htinfo *htinfo)
|
||||
{
|
||||
struct ieee80211com *ic = ni->ni_ic;
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
const struct ieee80211_ie_htinfo *htinfo;
|
||||
struct ieee80211_channel *c;
|
||||
uint16_t w;
|
||||
int htflags, chanflags;
|
||||
|
||||
if (ie[0] == IEEE80211_ELEMID_VENDOR)
|
||||
ie += 4;
|
||||
htinfo = (const struct ieee80211_ie_htinfo *) ie;
|
||||
ni->ni_htctlchan = htinfo->hi_ctrlchannel;
|
||||
ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
|
||||
w = LE_READ_2(&htinfo->hi_byte2);
|
||||
ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
|
||||
w = LE_READ_2(&htinfo->hi_byte45);
|
||||
ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
|
||||
/*
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an 802.11n HT info ie and save useful information
|
||||
* to the node state. Note this does not effect any state
|
||||
* changes such as for channel width change.
|
||||
*/
|
||||
void
|
||||
ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
{
|
||||
if (ie[0] == IEEE80211_ELEMID_VENDOR)
|
||||
ie += 4;
|
||||
htinfo_parse(ni, (const struct ieee80211_ie_htinfo *) ie);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle 11n channel switch. Use the received HT ie's to
|
||||
* identify the right channel to use. If we cannot locate it
|
||||
* in the channel table then fallback to legacy operation.
|
||||
* Note that we use this information to identify the node's
|
||||
* channel only; the caller is responsible for insuring any
|
||||
* required channel change is done (e.g. in sta mode when
|
||||
* parsing the contents of a beacon frame).
|
||||
*/
|
||||
/* NB: honor operating mode constraint */
|
||||
htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
|
||||
IEEE80211_CHAN_HT20 : 0;
|
||||
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
|
||||
if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
|
||||
htflags = IEEE80211_CHAN_HT40U;
|
||||
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
|
||||
htflags = IEEE80211_CHAN_HT40D;
|
||||
}
|
||||
static void
|
||||
htinfo_update_chw(struct ieee80211_node *ni, int htflags)
|
||||
{
|
||||
struct ieee80211com *ic = ni->ni_ic;
|
||||
struct ieee80211_channel *c;
|
||||
int chanflags;
|
||||
|
||||
chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
|
||||
if (chanflags != ni->ni_chan->ic_flags) {
|
||||
/* XXX not right for ht40- */
|
||||
c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
|
||||
if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
|
||||
/*
|
||||
@ -1218,14 +1214,16 @@ ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
* to HT20 operation. This should not happen.
|
||||
*/
|
||||
c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
|
||||
IEEE80211_NOTE(vap,
|
||||
#if 0
|
||||
IEEE80211_NOTE(ni->ni_vap,
|
||||
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
|
||||
"no HT40 channel (freq %u), falling back to HT20",
|
||||
ni->ni_chan->ic_freq);
|
||||
#endif
|
||||
/* XXX stat */
|
||||
}
|
||||
if (c != NULL && c != ni->ni_chan) {
|
||||
IEEE80211_NOTE(vap,
|
||||
IEEE80211_NOTE(ni->ni_vap,
|
||||
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
|
||||
"switch station to HT%d channel %u/0x%x",
|
||||
IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
|
||||
@ -1238,6 +1236,64 @@ ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
|
||||
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and update HT-related state extracted from
|
||||
* the HT cap and info ie's.
|
||||
*/
|
||||
void
|
||||
ieee80211_ht_updateparams(struct ieee80211_node *ni,
|
||||
const uint8_t *htcapie, const uint8_t *htinfoie)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
const struct ieee80211_ie_htinfo *htinfo;
|
||||
int htflags;
|
||||
|
||||
ieee80211_parse_htcap(ni, htcapie);
|
||||
|
||||
if (htinfoie[0] == IEEE80211_ELEMID_VENDOR)
|
||||
htinfoie += 4;
|
||||
htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
|
||||
htinfo_parse(ni, htinfo);
|
||||
|
||||
htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
|
||||
IEEE80211_CHAN_HT20 : 0;
|
||||
/* NB: honor operating mode constraint */
|
||||
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
|
||||
if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
|
||||
htflags = IEEE80211_CHAN_HT40U;
|
||||
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
|
||||
htflags = IEEE80211_CHAN_HT40D;
|
||||
}
|
||||
htinfo_update_chw(ni, htflags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and update HT-related state extracted from the HT cap ie
|
||||
* for a station joining an HT BSS.
|
||||
*/
|
||||
void
|
||||
ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
|
||||
{
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
int htflags;
|
||||
|
||||
ieee80211_parse_htcap(ni, htcapie);
|
||||
|
||||
/* NB: honor operating mode constraint */
|
||||
/* XXX 40 MHZ intolerant */
|
||||
htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
|
||||
IEEE80211_CHAN_HT20 : 0;
|
||||
if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
|
||||
if (IEEE80211_IS_CHAN_HT40U(vap->iv_bss->ni_chan))
|
||||
htflags = IEEE80211_CHAN_HT40U;
|
||||
else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
|
||||
htflags = IEEE80211_CHAN_HT40D;
|
||||
}
|
||||
htinfo_update_chw(ni, htflags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install received HT rate set by parsing the HT cap ie.
|
||||
*/
|
||||
|
@ -165,7 +165,7 @@ void ieee80211_setup_basic_htrates(struct ieee80211_node *,
|
||||
struct mbuf *ieee80211_decap_amsdu(struct ieee80211_node *, struct mbuf *);
|
||||
int ieee80211_ampdu_reorder(struct ieee80211_node *, struct mbuf *);
|
||||
void ieee80211_recv_bar(struct ieee80211_node *, struct mbuf *);
|
||||
void ieee80211_ht_node_init(struct ieee80211_node *, const uint8_t *);
|
||||
void ieee80211_ht_node_init(struct ieee80211_node *);
|
||||
void ieee80211_ht_node_cleanup(struct ieee80211_node *);
|
||||
void ieee80211_ht_node_age(struct ieee80211_node *);
|
||||
|
||||
@ -178,6 +178,9 @@ void ieee80211_htprot_update(struct ieee80211com *, int protmode);
|
||||
void ieee80211_ht_timeout(struct ieee80211com *);
|
||||
void ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
|
||||
void ieee80211_parse_htinfo(struct ieee80211_node *, const uint8_t *);
|
||||
void ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
|
||||
const uint8_t *);
|
||||
void ieee80211_ht_updatehtcap(struct ieee80211_node *, const uint8_t *);
|
||||
void ieee80211_recv_action(struct ieee80211_node *,
|
||||
const uint8_t *, const uint8_t *);
|
||||
int ieee80211_ampdu_request(struct ieee80211_node *,
|
||||
|
@ -1268,9 +1268,10 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
|
||||
ieee80211_wme_updateparams(vap);
|
||||
if (scan.ath != NULL)
|
||||
ieee80211_parse_athparams(ni, scan.ath, wh);
|
||||
if (scan.htcap != NULL && scan.htinfo != NULL) {
|
||||
ieee80211_parse_htcap(ni, scan.htcap);
|
||||
ieee80211_parse_htinfo(ni, scan.htinfo);
|
||||
if (scan.htcap != NULL && scan.htinfo != NULL &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_HT)) {
|
||||
ieee80211_ht_updateparams(ni,
|
||||
scan.htcap, scan.htinfo);
|
||||
/* XXX state changes? */
|
||||
}
|
||||
if (scan.tim != NULL) {
|
||||
@ -1503,8 +1504,8 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
|
||||
*/
|
||||
if (htcap != NULL && htinfo != NULL &&
|
||||
(vap->iv_flags_ext & IEEE80211_FEXT_HT)) {
|
||||
ieee80211_ht_node_init(ni, htcap);
|
||||
ieee80211_parse_htinfo(ni, htinfo);
|
||||
ieee80211_ht_node_init(ni);
|
||||
ieee80211_ht_updateparams(ni, htcap, htinfo);
|
||||
ieee80211_setup_htrates(ni, htcap,
|
||||
IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
|
||||
ieee80211_setup_basic_htrates(ni, htinfo);
|
||||
|
Loading…
Reference in New Issue
Block a user