mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-14 06:12:01 +01:00
Create a new task to handle 802.11n channel width changes.
Currently, a channel width change updates the 802.11n HT info data in net80211 but it doesn't trigger any device changes. So the device driver may decide that HT40 frames can be transmitted but the last device channel set only had HT20 set. Now, a task is scheduled so a hardware reset or change isn't done during any active ongoing RX. It also means that it's serialised with the other task operations (eg channel change.) This isn't the final incantation of this work, see below. For now, any unmodified drivers will simply receive a channel change log entry. A subsequent patch to ath(4) will introduce some basic channel change handling (by resetting the NIC.) Other NICs may need to update their rate control information. TODO: * There's still a small window at the present moment where the channel width has been updated but the task hasn't been fired. The final version of this should likely pass in a channel width field to the driver and let the driver atomically do whatever it needs to before changing the channel. PR: kern/166286
This commit is contained in:
parent
e3a078dfed
commit
b94299c437
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=233452
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 *,
|
||||
|
@ -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.
|
||||
|
@ -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 *,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
/*
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user