From fdabd982e796b1878f4349ff34bc061c59dca5fd Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sun, 21 Sep 2008 23:44:15 +0000 Subject: [PATCH] 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. --- sys/net80211/ieee80211_hostap.c | 3 +- sys/net80211/ieee80211_ht.c | 140 ++++++++++++++++++++++---------- sys/net80211/ieee80211_ht.h | 5 +- sys/net80211/ieee80211_sta.c | 11 +-- 4 files changed, 110 insertions(+), 49 deletions(-) diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index c876dab84fb2..7f28f4fe945c 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -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); /* diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 649441d99f2c..827336b404d9 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -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); - /* - * 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. - */ - /* 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; - } +} + +/* + * 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). + */ +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. */ diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h index dfad584f5041..62d2f2e457d4 100644 --- a/sys/net80211/ieee80211_ht.h +++ b/sys/net80211/ieee80211_ht.h @@ -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 *, diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c index d98c6dda9706..3010965ff815 100644 --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -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);