Date: Wed, 21 Mar 2012 18:29:49 -0700 From: Adrian Chadd <adrian@freebsd.org> To: freebsd-wireless@freebsd.org Subject: Re: [net80211] PR kern/166286: force a channel change upon a HT info change Message-ID: <CAJ-Vmon_Tz=02Otc3yKsNN8giZ40hnqZJB2TCZ=b=GGjugLZ7Q@mail.gmail.com> In-Reply-To: <CAJ-VmonVNrB%2BvhCGLAXXaq2W9DS14ym735gSR=Y%2BM1z5vz-C=A@mail.gmail.com> References: <CAJ-Vmonr7y4f23L_gNfcOjiQHVs5xK-NQC72VH%2B6b%2B-9zorRSw@mail.gmail.com> <CAJ-VmonnJwazDRHLtVH5TeWeKMZv2aAAZOvO7vDDRhRciLmixw@mail.gmail.com> <CAJ-VmonVNrB%2BvhCGLAXXaq2W9DS14ym735gSR=Y%2BM1z5vz-C=A@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
.. and the patch.
Adrian
[-- Attachment #2 --]
Index: sys/dev/ath/if_ath.c
===================================================================
--- sys/dev/ath/if_ath.c (revision 233089)
+++ sys/dev/ath/if_ath.c (working copy)
@@ -199,6 +199,7 @@
static void ath_scan_start(struct ieee80211com *);
static void ath_scan_end(struct ieee80211com *);
static void ath_set_channel(struct ieee80211com *);
+static void ath_update_chw(struct ieee80211com *);
static void ath_calibrate(void *);
static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
@@ -794,6 +795,7 @@
ic->ic_scan_start = ath_scan_start;
ic->ic_scan_end = ath_scan_end;
ic->ic_set_channel = ath_set_channel;
+ ic->ic_update_chw = ath_update_chw;
/* 802.11n specific - but just override anyway */
sc->sc_addba_request = ic->ic_addba_request;
@@ -5717,7 +5719,32 @@
sc->sc_curaid);
}
+/*
+ * For now, just do a channel change.
+ *
+ * Later, we'll go through the hard slog of suspending tx/rx, changing rate
+ * control state and resetting the hardware without dropping frames out
+ * of the queue.
+ *
+ * The unfortunate trouble here is making absolutely sure that the
+ * channel width change has propagated enough so the hardware
+ * absolutely isn't handed bogus frames for it's current operating
+ * mode. (Eg, 40MHz frames in 20MHz mode.) Since TX and RX can and
+ * does occur in parallel, we need to make certain we've blocked
+ * any further ongoing TX (and RX, that can cause raw TX)
+ * before we do this.
+ */
static void
+ath_update_chw(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: called\n", __func__);
+ ath_set_channel(ic);
+}
+
+static void
ath_set_channel(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
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 schedule a delayed driver notification.
+ */
+ if (chan_change)
+ ieee80211_update_chw(ic);
return;
}
/*
Index: sys/net80211/ieee80211_proto.c
===================================================================
--- sys/net80211/ieee80211_proto.c (revision 233254)
+++ sys/net80211/ieee80211_proto.c (working copy)
@@ -105,6 +105,7 @@
static void update_mcast(void *, int);
static void update_promisc(void *, int);
static void update_channel(void *, int);
+static void update_chw(void *, int);
static void ieee80211_newstate_cb(void *, int);
static int ieee80211_new_state_locked(struct ieee80211vap *,
enum ieee80211_state, int);
@@ -144,6 +145,7 @@
TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic);
TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic);
TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic);
+ TASK_INIT(&ic->ic_chw_task, 0, update_chw, ic);
ic->ic_wme.wme_hipri_switch_hysteresis =
AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
@@ -1147,6 +1149,17 @@
ieee80211_radiotap_chan_change(ic);
}
+static void
+update_chw(void *arg, int npending)
+{
+ struct ieee80211com *ic = arg;
+
+ /*
+ * XXX should we defer the channel width _config_ update until now?
+ */
+ ic->ic_update_chw(ic);
+}
+
/*
* Block until the parent is in a known state. This is
* used after any operations that dispatch a task (e.g.
@@ -1161,6 +1174,7 @@
ieee80211_draintask(ic, &ic->ic_promisc_task);
ieee80211_draintask(ic, &ic->ic_chan_task);
ieee80211_draintask(ic, &ic->ic_bmiss_task);
+ ieee80211_draintask(ic, &ic->ic_chw_task);
taskqueue_unblock(ic->ic_tq);
}
Index: sys/net80211/ieee80211_node.c
===================================================================
--- sys/net80211/ieee80211_node.c (revision 233254)
+++ sys/net80211/ieee80211_node.c (working copy)
@@ -685,6 +685,14 @@
ieee80211_runtask(ic, &ic->ic_chan_task);
}
+void
+ieee80211_update_chw(struct ieee80211com *ic)
+{
+
+ ieee80211_setupcurchan(ic, ic->ic_curchan);
+ ieee80211_runtask(ic, &ic->ic_chw_task);
+}
+
/*
* Join the specified IBSS/BSS network. The node is assumed to
* be passed in with a held reference.
Index: sys/net80211/ieee80211_node.h
===================================================================
--- sys/net80211/ieee80211_node.h (revision 233254)
+++ sys/net80211/ieee80211_node.h (working copy)
@@ -324,6 +324,7 @@
void ieee80211_setupcurchan(struct ieee80211com *,
struct ieee80211_channel *);
void ieee80211_setcurchan(struct ieee80211com *, struct ieee80211_channel *);
+void ieee80211_update_chw(struct ieee80211com *);
int ieee80211_ibss_merge(struct ieee80211_node *);
struct ieee80211_scan_entry;
int ieee80211_sta_join(struct ieee80211vap *, struct ieee80211_channel *,
Index: sys/net80211/ieee80211_var.h
===================================================================
--- sys/net80211/ieee80211_var.h (revision 233254)
+++ sys/net80211/ieee80211_var.h (working copy)
@@ -130,6 +130,7 @@
struct task ic_mcast_task; /* deferred mcast update */
struct task ic_chan_task; /* deferred channel change */
struct task ic_bmiss_task; /* deferred beacon miss hndlr */
+ struct task ic_chw_task; /* deferred HT CHW update */
uint32_t ic_flags; /* state flags */
uint32_t ic_flags_ext; /* extended state flags */
@@ -322,6 +323,10 @@
int batimeout, int baseqctl);
void (*ic_ampdu_rx_stop)(struct ieee80211_node *,
struct ieee80211_rx_ampdu *);
+
+ /* The channel width has changed (20<->2040) */
+ void (*ic_update_chw)(struct ieee80211com *);
+
uint64_t ic_spare[7];
};
Index: sys/net80211/ieee80211.c
===================================================================
--- sys/net80211/ieee80211.c (revision 233254)
+++ sys/net80211/ieee80211.c (working copy)
@@ -256,6 +256,13 @@
m_freem(m);
}
+static void
+null_update_chw(struct ieee80211com *ic)
+{
+
+ if_printf(ic->ic_ifp, "%s: need callback\n", __func__);
+}
+
/*
* Attach/setup the common net80211 state. Called by
* the driver on attach to prior to creating any vap's.
@@ -287,6 +294,7 @@
ic->ic_update_mcast = null_update_mcast;
ic->ic_update_promisc = null_update_promisc;
+ ic->ic_update_chw = null_update_chw;
ic->ic_hash_key = arc4random();
ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmon_Tz=02Otc3yKsNN8giZ40hnqZJB2TCZ=b=GGjugLZ7Q>
