Date: Tue, 20 Mar 2012 20:24:37 -0700 From: Adrian Chadd <adrian@freebsd.org> To: freebsd-wireless@freebsd.org, Bernhard Schmidt <bschmidt@freebsd.org> Subject: [net80211] PR kern/166286: force a channel change upon a HT info change Message-ID: <CAJ-Vmonr7y4f23L_gNfcOjiQHVs5xK-NQC72VH%2B6b%2B-9zorRSw@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Hi,
This patch forces a channel change - sta_recv_mgmt() doesn't set the
channel width early enough to catch it after the ASSOC -> RUN state
change. So there's a transition to HT20 upon association, but it
doesn't transition to HT40 via ic_chan_set(). Thus the hardware is in
HT20 mode, but HT40 frames are sent to the hardware .They obviously
fail.
This shows up when associating to an open HT40 AP. Since bgscan is
disabled, there's no subsequent scan to force an ath_chan_set() with
the updated flags. I'm not sure why (yet) it hasn't shown up in other
scenarios.
Bernhard - would you mind commenting on this? You were the last of us
knee-deep in ieee80211_ht.c and the net80211 management path.
Thanks!
Adrian
[-- Attachment #2 --]
Index: sys/net80211/ieee80211_ht.c
===================================================================
--- sys/net80211/ieee80211_ht.c (revision 233254)
+++ sys/net80211/ieee80211_ht.c (working copy)
@@ -1428,12 +1428,13 @@
* required channel change is done (e.g. in sta mode when
* parsing the contents of a beacon frame).
*/
-static void
+static int
htinfo_update_chw(struct ieee80211_node *ni, int htflags)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *c;
int chanflags;
+ int ret = 0;
chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
if (chanflags != ni->ni_chan->ic_flags) {
@@ -1460,11 +1461,13 @@
IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
c->ic_freq, c->ic_flags);
ni->ni_chan = c;
+ ret = 1;
}
/* NB: caller responsible for forcing any channel change */
}
/* update node's tx channel width */
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
+ return (ret);
}
/*
@@ -1515,13 +1518,14 @@
* Parse and update HT-related state extracted from
* the HT cap and info ie's.
*/
-void
+int
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;
+ int ret = 0;
ieee80211_parse_htcap(ni, htcapie);
if (vap->iv_htcaps & IEEE80211_HTCAP_SMPS)
@@ -1543,13 +1547,16 @@
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
htflags = IEEE80211_CHAN_HT40D;
}
- htinfo_update_chw(ni, htflags);
+ if (htinfo_update_chw(ni, htflags))
+ ret = 1;
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
(vap->iv_flags_ht & IEEE80211_FHT_RIFS))
ni->ni_flags |= IEEE80211_NODE_RIFS;
else
ni->ni_flags &= ~IEEE80211_NODE_RIFS;
+
+ return (ret);
}
/*
@@ -1578,7 +1585,7 @@
else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
htflags = IEEE80211_CHAN_HT40D;
}
- htinfo_update_chw(ni, htflags);
+ (void) htinfo_update_chw(ni, htflags);
}
/*
Index: sys/net80211/ieee80211_ht.h
===================================================================
--- sys/net80211/ieee80211_ht.h (revision 233254)
+++ sys/net80211/ieee80211_ht.h (working copy)
@@ -184,7 +184,7 @@
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 *,
+int ieee80211_ht_updateparams(struct ieee80211_node *, const uint8_t *,
const uint8_t *);
void ieee80211_ht_updatehtcap(struct ieee80211_node *, const uint8_t *);
int ieee80211_ampdu_request(struct ieee80211_node *,
Index: sys/net80211/ieee80211_sta.c
===================================================================
--- sys/net80211/ieee80211_sta.c (revision 233254)
+++ sys/net80211/ieee80211_sta.c (working copy)
@@ -1285,6 +1285,7 @@
uint8_t *frm, *efrm;
uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
uint8_t rate;
+ int chan_change = 0;
wh = mtod(m0, struct ieee80211_frame *);
frm = (uint8_t *)&wh[1];
@@ -1372,8 +1373,9 @@
#endif
if (scan.htcap != NULL && scan.htinfo != NULL &&
(vap->iv_flags_ht & IEEE80211_FHT_HT)) {
- ieee80211_ht_updateparams(ni,
- scan.htcap, scan.htinfo);
+ if (ieee80211_ht_updateparams(ni,
+ scan.htcap, scan.htinfo))
+ chan_change = 1;
/* XXX state changes? */
}
if (scan.quiet)
@@ -1441,6 +1443,13 @@
#endif
ieee80211_bg_scan(vap, 0);
}
+
+ /*
+ * If we've had a state change (eg HT20<->HT40)
+ * then reset the operating channel.
+ */
+ if (chan_change)
+ ieee80211_setcurchan(ic, ic->ic_curchan);
return;
}
/*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmonr7y4f23L_gNfcOjiQHVs5xK-NQC72VH%2B6b%2B-9zorRSw>
