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++;
|
vap->iv_stats.is_ht_assoc_norate++;
|
||||||
return;
|
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)
|
} else if (ni->ni_flags & IEEE80211_NODE_HT)
|
||||||
ieee80211_ht_node_cleanup(ni);
|
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.
|
* work for temporary and/or legacy sta's.
|
||||||
*/
|
*/
|
||||||
void
|
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;
|
struct ieee80211_tx_ampdu *tap;
|
||||||
int ac;
|
int ac;
|
||||||
|
@ -796,7 +796,6 @@ ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
|
||||||
*/
|
*/
|
||||||
ieee80211_ht_node_cleanup(ni);
|
ieee80211_ht_node_cleanup(ni);
|
||||||
}
|
}
|
||||||
ieee80211_parse_htcap(ni, htcap);
|
|
||||||
for (ac = 0; ac < WME_NUM_AC; ac++) {
|
for (ac = 0; ac < WME_NUM_AC; ac++) {
|
||||||
tap = &ni->ni_tx_ampdu[ac];
|
tap = &ni->ni_tx_ampdu[ac];
|
||||||
tap->txa_ac = ac;
|
tap->txa_ac = ac;
|
||||||
|
@ -1146,8 +1145,6 @@ ieee80211_ht_timeout(struct ieee80211com *ic)
|
||||||
void
|
void
|
||||||
ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
|
ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
|
||||||
{
|
{
|
||||||
struct ieee80211vap *vap = ni->ni_vap;
|
|
||||||
|
|
||||||
if (ie[0] == IEEE80211_ELEMID_VENDOR) {
|
if (ie[0] == IEEE80211_ELEMID_VENDOR) {
|
||||||
/*
|
/*
|
||||||
* Station used Vendor OUI ie to associate;
|
* 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 +
|
ni->ni_htcap = LE_READ_2(ie +
|
||||||
__offsetof(struct ieee80211_ie_htcap, hc_cap));
|
__offsetof(struct ieee80211_ie_htcap, hc_cap));
|
||||||
ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void
|
||||||
* Process an 802.11n HT info ie and update the node state.
|
htinfo_parse(struct ieee80211_node *ni,
|
||||||
* Note that we handle use this information to identify the
|
const struct ieee80211_ie_htinfo *htinfo)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
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;
|
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_htctlchan = htinfo->hi_ctrlchannel;
|
||||||
ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
|
ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
|
||||||
w = LE_READ_2(&htinfo->hi_byte2);
|
w = LE_READ_2(&htinfo->hi_byte2);
|
||||||
ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
|
ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
|
||||||
w = LE_READ_2(&htinfo->hi_byte45);
|
w = LE_READ_2(&htinfo->hi_byte45);
|
||||||
ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
|
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
|
* Handle 11n channel switch. Use the received HT ie's to
|
||||||
* identify the right channel to use. If we cannot locate it
|
* identify the right channel to use. If we cannot locate it
|
||||||
* in the channel table then fallback to legacy operation.
|
* 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 */
|
static void
|
||||||
htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
|
htinfo_update_chw(struct ieee80211_node *ni, int htflags)
|
||||||
IEEE80211_CHAN_HT20 : 0;
|
{
|
||||||
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
|
struct ieee80211com *ic = ni->ni_ic;
|
||||||
(vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
|
struct ieee80211_channel *c;
|
||||||
if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
|
int chanflags;
|
||||||
htflags = IEEE80211_CHAN_HT40U;
|
|
||||||
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
|
|
||||||
htflags = IEEE80211_CHAN_HT40D;
|
|
||||||
}
|
|
||||||
chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
|
chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
|
||||||
if (chanflags != ni->ni_chan->ic_flags) {
|
if (chanflags != ni->ni_chan->ic_flags) {
|
||||||
|
/* XXX not right for ht40- */
|
||||||
c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
|
c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
|
||||||
if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
|
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.
|
* to HT20 operation. This should not happen.
|
||||||
*/
|
*/
|
||||||
c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
|
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,
|
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
|
||||||
"no HT40 channel (freq %u), falling back to HT20",
|
"no HT40 channel (freq %u), falling back to HT20",
|
||||||
ni->ni_chan->ic_freq);
|
ni->ni_chan->ic_freq);
|
||||||
|
#endif
|
||||||
/* XXX stat */
|
/* XXX stat */
|
||||||
}
|
}
|
||||||
if (c != NULL && c != ni->ni_chan) {
|
if (c != NULL && c != ni->ni_chan) {
|
||||||
IEEE80211_NOTE(vap,
|
IEEE80211_NOTE(ni->ni_vap,
|
||||||
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
|
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
|
||||||
"switch station to HT%d channel %u/0x%x",
|
"switch station to HT%d channel %u/0x%x",
|
||||||
IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
|
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;
|
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.
|
* 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 *);
|
struct mbuf *ieee80211_decap_amsdu(struct ieee80211_node *, struct mbuf *);
|
||||||
int ieee80211_ampdu_reorder(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_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_cleanup(struct ieee80211_node *);
|
||||||
void ieee80211_ht_node_age(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_ht_timeout(struct ieee80211com *);
|
||||||
void ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
|
void ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
|
||||||
void ieee80211_parse_htinfo(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 *,
|
void ieee80211_recv_action(struct ieee80211_node *,
|
||||||
const uint8_t *, const uint8_t *);
|
const uint8_t *, const uint8_t *);
|
||||||
int ieee80211_ampdu_request(struct ieee80211_node *,
|
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);
|
ieee80211_wme_updateparams(vap);
|
||||||
if (scan.ath != NULL)
|
if (scan.ath != NULL)
|
||||||
ieee80211_parse_athparams(ni, scan.ath, wh);
|
ieee80211_parse_athparams(ni, scan.ath, wh);
|
||||||
if (scan.htcap != NULL && scan.htinfo != NULL) {
|
if (scan.htcap != NULL && scan.htinfo != NULL &&
|
||||||
ieee80211_parse_htcap(ni, scan.htcap);
|
(vap->iv_flags_ext & IEEE80211_FEXT_HT)) {
|
||||||
ieee80211_parse_htinfo(ni, scan.htinfo);
|
ieee80211_ht_updateparams(ni,
|
||||||
|
scan.htcap, scan.htinfo);
|
||||||
/* XXX state changes? */
|
/* XXX state changes? */
|
||||||
}
|
}
|
||||||
if (scan.tim != NULL) {
|
if (scan.tim != NULL) {
|
||||||
|
@ -1503,8 +1504,8 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
|
||||||
*/
|
*/
|
||||||
if (htcap != NULL && htinfo != NULL &&
|
if (htcap != NULL && htinfo != NULL &&
|
||||||
(vap->iv_flags_ext & IEEE80211_FEXT_HT)) {
|
(vap->iv_flags_ext & IEEE80211_FEXT_HT)) {
|
||||||
ieee80211_ht_node_init(ni, htcap);
|
ieee80211_ht_node_init(ni);
|
||||||
ieee80211_parse_htinfo(ni, htinfo);
|
ieee80211_ht_updateparams(ni, htcap, htinfo);
|
||||||
ieee80211_setup_htrates(ni, htcap,
|
ieee80211_setup_htrates(ni, htcap,
|
||||||
IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
|
IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
|
||||||
ieee80211_setup_basic_htrates(ni, htinfo);
|
ieee80211_setup_basic_htrates(ni, htinfo);
|
||||||
|
|
Loading…
Reference in New Issue