summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net80211/ieee80211.c8
-rw-r--r--sys/net80211/ieee80211_ht.c15
-rw-r--r--sys/net80211/ieee80211_ht.h2
-rw-r--r--sys/net80211/ieee80211_node.c8
-rw-r--r--sys/net80211/ieee80211_node.h1
-rw-r--r--sys/net80211/ieee80211_proto.c14
-rw-r--r--sys/net80211/ieee80211_sta.c13
-rw-r--r--sys/net80211/ieee80211_var.h5
8 files changed, 59 insertions, 7 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index d866bbf..78c876e 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -256,6 +256,13 @@ null_input(struct ifnet *ifp, struct mbuf *m)
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 @@ ieee80211_ifattach(struct ieee80211com *ic,
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;
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 23a765f..d403220 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -1428,12 +1428,13 @@ ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
* 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 @@ htinfo_update_chw(struct ieee80211_node *ni, int htflags)
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 @@ htcap_update_shortgi(struct ieee80211_node *ni)
* 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 @@ ieee80211_ht_updateparams(struct ieee80211_node *ni,
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 @@ ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
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);
}
/*
diff --git a/sys/net80211/ieee80211_ht.h b/sys/net80211/ieee80211_ht.h
index 249ddd2..070fbb2 100644
--- a/sys/net80211/ieee80211_ht.h
+++ b/sys/net80211/ieee80211_ht.h
@@ -184,7 +184,7 @@ 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 *,
+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 *,
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index 71f97f0..861fa85 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -685,6 +685,14 @@ ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
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.
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index f438025..3d9cc1c 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -324,6 +324,7 @@ void ieee80211_sync_curchan(struct ieee80211com *);
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 *,
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index caa813a..232dbba 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -105,6 +105,7 @@ static void parent_updown(void *, int);
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 @@ ieee80211_proto_attach(struct ieee80211com *ic)
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 @@ update_channel(void *arg, int npending)
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_waitfor_parent(struct ieee80211com *ic)
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);
}
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 0f1af98..139fa37 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1285,6 +1285,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
uint8_t *frm, *efrm;
uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
uint8_t rate;
+ int ht_state_change = 0;
wh = mtod(m0, struct ieee80211_frame *);
frm = (uint8_t *)&wh[1];
@@ -1372,9 +1373,10 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
#endif
if (scan.htcap != NULL && scan.htinfo != NULL &&
(vap->iv_flags_ht & IEEE80211_FHT_HT)) {
- ieee80211_ht_updateparams(ni,
- scan.htcap, scan.htinfo);
/* XXX state changes? */
+ if (ieee80211_ht_updateparams(ni,
+ scan.htcap, scan.htinfo))
+ ht_state_change = 1;
}
if (scan.quiet)
ic->ic_set_quiet(ni, scan.quiet);
@@ -1441,6 +1443,13 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
#endif
ieee80211_bg_scan(vap, 0);
}
+
+ /*
+ * If we've had a channel width change (eg HT20<->HT40)
+ * then schedule a delayed driver notification.
+ */
+ if (ht_state_change)
+ ieee80211_update_chw(ic);
return;
}
/*
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index feb9fb8..77e67aa 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -130,6 +130,7 @@ struct ieee80211com {
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 @@ struct ieee80211com {
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];
};
OpenPOWER on IntegriCloud