aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2008-09-21 23:44:15 +0000
committerSam Leffler <sam@FreeBSD.org>2008-09-21 23:44:15 +0000
commitfdabd982e796b1878f4349ff34bc061c59dca5fd (patch)
tree68592baf2027c37efcdcd6532dbf42b70cde44eb
parentbd985970b6b4f8cc4b7a17fef22c2f0651f9aaac (diff)
downloadsrc-fdabd982e796b1878f4349ff34bc061c59dca5fd.tar.gz
src-fdabd982e796b1878f4349ff34bc061c59dca5fd.zip
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.
Notes
Notes: svn path=/head/; revision=183254
-rw-r--r--sys/net80211/ieee80211_hostap.c3
-rw-r--r--sys/net80211/ieee80211_ht.c140
-rw-r--r--sys/net80211/ieee80211_ht.h5
-rw-r--r--sys/net80211/ieee80211_sta.c11
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,
@@ -1239,6 +1237,64 @@ ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
}
/*
+ * 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.
*/
int
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);