diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net80211/ieee80211.c | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ht.c | 15 | ||||
-rw-r--r-- | sys/net80211/ieee80211_ht.h | 2 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 1 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 14 | ||||
-rw-r--r-- | sys/net80211/ieee80211_sta.c | 13 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 5 |
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]; }; |