Christian Ehrhardt reported an issue where changes in the ERP protection
settings in beacons caused noticeable packet loss on iwm(4).
I've found that there are a few parameters in beacons which can change at
run-time but don't get updated in hardware, simply because the drivers do
not implement the corresponding hooks which are provided by net80211.
The patch below ensures that the following parameters will be kept
up-to-date at run-time by iwn, iwm, and iwx:
- HT protection settings (this was already implemented)
- ERP (11g) protection setting
- short slottime setting
- short preamble setting
- EDCA (QoS) parameters
I am renaming ic_update_htprot() to ic_updateprot() since it now includes ERP.
The node parameter of this function is always ic->ic_bss so I've dropped it.
Tested on iwn 6250, iwm 8265, and iwx ax200. No regressions found.
A few additional test reports would be nice. For most people this patch
should simply not change anything. ERP protection changes should only
occur when 802.11b devices start or stop using the access point's channel.
diff refs/heads/master refs/heads/updateprot
blob - 1d7c376ff8cdf661401c89e6f13e4b2a819d70c2
blob + c243e2932471c805ea6f6b846d103bb054becc36
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -328,8 +328,10 @@ void iwm_init_channel_map(struct iwm_softc *, const
ui
const uint8_t *nvm_channels, int nchan);
int iwm_mimo_enabled(struct iwm_softc *);
void iwm_setup_ht_rates(struct iwm_softc *);
-void iwm_htprot_task(void *);
-void iwm_update_htprot(struct ieee80211com *, struct ieee80211_node *);
+void iwm_mac_ctxt_task(void *);
+void iwm_updateprot(struct ieee80211com *);
+void iwm_updateslot(struct ieee80211com *);
+void iwm_updateedca(struct ieee80211com *);
void iwm_init_reorder_buffer(struct iwm_reorder_buffer *, uint16_t,
uint16_t);
void iwm_clear_reorder_buffer(struct iwm_softc *, struct iwm_rxba_data *);
@@ -3170,7 +3172,7 @@ iwm_sta_rx_agg(struct iwm_softc *sc, struct ieee80211_
}
void
-iwm_htprot_task(void *arg)
+iwm_mac_ctxt_task(void *arg)
{
struct iwm_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
@@ -3183,30 +3185,42 @@ iwm_htprot_task(void *arg)
return;
}
- /* This call updates HT protection based on in->in_ni.ni_htop1. */
err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1);
if (err)
- printf("%s: could not change HT protection: error %d\n",
- DEVNAME(sc), err);
+ printf("%s: failed to update MAC\n", DEVNAME(sc));
refcnt_rele_wake(&sc->task_refs);
splx(s);
}
-/*
- * This function is called by upper layer when HT protection settings in
- * beacons have changed.
- */
void
-iwm_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni)
+iwm_updateprot(struct ieee80211com *ic)
{
struct iwm_softc *sc = ic->ic_softc;
- /* assumes that ni == ic->ic_bss */
- iwm_add_task(sc, systq, &sc->htprot_task);
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwm_add_task(sc, systq, &sc->mac_ctxt_task);
}
void
+iwm_updateslot(struct ieee80211com *ic)
+{
+ struct iwm_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwm_add_task(sc, systq, &sc->mac_ctxt_task);
+}
+
+void
+iwm_updateedca(struct ieee80211com *ic)
+{
+ struct iwm_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwm_add_task(sc, systq, &sc->mac_ctxt_task);
+}
+
+void
iwm_ba_task(void *arg)
{
struct iwm_softc *sc = arg;
@@ -8026,7 +8040,7 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
if (ic->ic_state == IEEE80211_S_RUN) {
timeout_del(&sc->sc_calib_to);
iwm_del_task(sc, systq, &sc->ba_task);
- iwm_del_task(sc, systq, &sc->htprot_task);
+ iwm_del_task(sc, systq, &sc->mac_ctxt_task);
for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
struct iwm_rxba_data *rxba = &sc->sc_rxba_data[i];
iwm_clear_reorder_buffer(sc, rxba);
@@ -8808,7 +8822,7 @@ iwm_stop(struct ifnet *ifp)
task_del(systq, &sc->init_task);
iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task);
iwm_del_task(sc, systq, &sc->ba_task);
- iwm_del_task(sc, systq, &sc->htprot_task);
+ iwm_del_task(sc, systq, &sc->mac_ctxt_task);
KASSERT(sc->task_refs.refs >= 1);
refcnt_finalize(&sc->task_refs, "iwmstop");
@@ -10250,7 +10264,7 @@ iwm_attach(struct device *parent, struct device *self,
task_set(&sc->init_task, iwm_init_task, sc);
task_set(&sc->newstate_task, iwm_newstate_task, sc);
task_set(&sc->ba_task, iwm_ba_task, sc);
- task_set(&sc->htprot_task, iwm_htprot_task, sc);
+ task_set(&sc->mac_ctxt_task, iwm_mac_ctxt_task, sc);
ic->ic_node_alloc = iwm_node_alloc;
ic->ic_bgscan_start = iwm_bgscan;
@@ -10260,7 +10274,9 @@ iwm_attach(struct device *parent, struct device *self,
/* Override 802.11 state transition machine. */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwm_newstate;
- ic->ic_update_htprot = iwm_update_htprot;
+ ic->ic_updateprot = iwm_updateprot;
+ ic->ic_updateslot = iwm_updateslot;
+ ic->ic_updateedca = iwm_updateedca;
ic->ic_ampdu_rx_start = iwm_ampdu_rx_start;
ic->ic_ampdu_rx_stop = iwm_ampdu_rx_stop;
#ifdef notyet
blob - f40424718a56c18243a374c944711cce4977f742
blob + 4796b37585a766e811871d3830e971c58fdcb28c
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -478,8 +478,8 @@ struct iwm_softc {
uint16_t ba_winsize[IWM_MAX_TID_COUNT];
int ba_timeout_val[IWM_MAX_TID_COUNT];
- /* Task for HT protection updates. */
- struct task htprot_task;
+ /* Task for ERP/HT prot/slot-time/EDCA updates. */
+ struct task mac_ctxt_task;
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
blob - 241fff3d280e22b7c9c27eb8c63f71ac781ea5bb
blob + 59cbaecac948b4b589d483bacc454ae93dd20e32
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -247,8 +247,9 @@ int iwn_set_key(struct ieee80211com *, struct
ieee802
struct ieee80211_key *);
void iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
-void iwn_update_htprot(struct ieee80211com *,
- struct ieee80211_node *);
+void iwn_updateprot(struct ieee80211com *);
+void iwn_updateslot(struct ieee80211com *);
+void iwn_update_rxon(struct iwn_softc *);
int iwn_ampdu_rx_start(struct ieee80211com *,
struct ieee80211_node *, uint8_t);
void iwn_ampdu_rx_stop(struct ieee80211com *,
@@ -540,7 +541,8 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_updateedca = iwn_updateedca;
ic->ic_set_key = iwn_set_key;
ic->ic_delete_key = iwn_delete_key;
- ic->ic_update_htprot = iwn_update_htprot;
+ ic->ic_updateprot = iwn_updateprot;
+ ic->ic_updateslot = iwn_updateslot;
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
ic->ic_ampdu_tx_start = iwn_ampdu_tx_start;
@@ -5652,25 +5654,58 @@ iwn_delete_key(struct ieee80211com *ic, struct ieee802
(void)ops->add_node(sc, &node, 1);
}
-/*
- * This function is called by upper layer when HT protection settings in
- * beacons have changed.
- */
void
-iwn_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni)
+iwn_updateprot(struct ieee80211com *ic)
{
struct iwn_softc *sc = ic->ic_softc;
- struct iwn_ops *ops = &sc->ops;
enum ieee80211_htprot htprot;
- struct iwn_rxon_assoc rxon_assoc;
- int s, error;
+ if (ic->ic_state != IEEE80211_S_RUN)
+ return;
+
+ /* Update ERP protection setting. */
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT);
+ else
+ sc->rxon.flags &= ~htole32(IWN_RXON_TGG_PROT);
+
/* Update HT protection mode setting. */
- htprot = (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >>
+ htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >>
IEEE80211_HTOP1_PROT_SHIFT;
sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3));
sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot));
+ iwn_update_rxon(sc);
+}
+
+void
+iwn_updateslot(struct ieee80211com *ic)
+{
+ struct iwn_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state != IEEE80211_S_RUN)
+ return;
+
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ sc->rxon.flags |= htole32(IWN_RXON_SHSLOT);
+ else
+ sc->rxon.flags &= ~htole32(IWN_RXON_SHSLOT);
+
+ if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
+ sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE);
+ else
+ sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE);
+
+ iwn_update_rxon(sc);
+}
+void
+iwn_update_rxon(struct iwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwn_ops *ops = &sc->ops;
+ struct iwn_rxon_assoc rxon_assoc;
+ int s, error;
+
/* Update RXON config. */
memset(&rxon_assoc, 0, sizeof(rxon_assoc));
rxon_assoc.flags = sc->rxon.flags;
blob - 724ab6796ced1c50ebcdacdcf7fd089232869b37
blob + ce6a5c4d5b5b2c737e37ff7beb7afc2cb1ea95a4
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -300,8 +300,10 @@ void iwx_unprotect_session(struct iwx_softc *,
struct
void iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
void iwx_setup_ht_rates(struct iwx_softc *);
int iwx_mimo_enabled(struct iwx_softc *);
-void iwx_htprot_task(void *);
-void iwx_update_htprot(struct ieee80211com *, struct ieee80211_node *);
+void iwx_mac_ctxt_task(void *);
+void iwx_updateprot(struct ieee80211com *);
+void iwx_updateslot(struct ieee80211com *);
+void iwx_updateedca(struct ieee80211com *);
void iwx_init_reorder_buffer(struct iwx_reorder_buffer *, uint16_t,
uint16_t);
void iwx_clear_reorder_buffer(struct iwx_softc *, struct iwx_rxba_data *);
@@ -2940,7 +2942,7 @@ iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_
}
void
-iwx_htprot_task(void *arg)
+iwx_mac_ctxt_task(void *arg)
{
struct iwx_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
@@ -2953,30 +2955,42 @@ iwx_htprot_task(void *arg)
return;
}
- /* This call updates HT protection based on in->in_ni.ni_htop1. */
err = iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_MODIFY, 1);
if (err)
- printf("%s: could not change HT protection: error %d\n",
- DEVNAME(sc), err);
+ printf("%s: failed to update MAC\n", DEVNAME(sc));
refcnt_rele_wake(&sc->task_refs);
splx(s);
}
-/*
- * This function is called by upper layer when HT protection settings in
- * beacons have changed.
- */
void
-iwx_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni)
+iwx_updateprot(struct ieee80211com *ic)
{
struct iwx_softc *sc = ic->ic_softc;
- /* assumes that ni == ic->ic_bss */
- iwx_add_task(sc, systq, &sc->htprot_task);
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwx_add_task(sc, systq, &sc->mac_ctxt_task);
}
void
+iwx_updateslot(struct ieee80211com *ic)
+{
+ struct iwx_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwx_add_task(sc, systq, &sc->mac_ctxt_task);
+}
+
+void
+iwx_updateedca(struct ieee80211com *ic)
+{
+ struct iwx_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state == IEEE80211_S_RUN)
+ iwx_add_task(sc, systq, &sc->mac_ctxt_task);
+}
+
+void
iwx_ba_task(void *arg)
{
struct iwx_softc *sc = arg;
@@ -6854,7 +6868,7 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_s
if (ic->ic_state == IEEE80211_S_RUN) {
iwx_del_task(sc, systq, &sc->ba_task);
- iwx_del_task(sc, systq, &sc->htprot_task);
+ iwx_del_task(sc, systq, &sc->mac_ctxt_task);
for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i];
iwx_clear_reorder_buffer(sc, rxba);
@@ -7426,7 +7440,7 @@ iwx_stop(struct ifnet *ifp)
task_del(systq, &sc->init_task);
iwx_del_task(sc, sc->sc_nswq, &sc->newstate_task);
iwx_del_task(sc, systq, &sc->ba_task);
- iwx_del_task(sc, systq, &sc->htprot_task);
+ iwx_del_task(sc, systq, &sc->mac_ctxt_task);
KASSERT(sc->task_refs.refs >= 1);
refcnt_finalize(&sc->task_refs, "iwxstop");
@@ -8823,7 +8837,7 @@ iwx_attach(struct device *parent, struct device *self,
task_set(&sc->init_task, iwx_init_task, sc);
task_set(&sc->newstate_task, iwx_newstate_task, sc);
task_set(&sc->ba_task, iwx_ba_task, sc);
- task_set(&sc->htprot_task, iwx_htprot_task, sc);
+ task_set(&sc->mac_ctxt_task, iwx_mac_ctxt_task, sc);
ic->ic_node_alloc = iwx_node_alloc;
ic->ic_bgscan_start = iwx_bgscan;
@@ -8833,7 +8847,9 @@ iwx_attach(struct device *parent, struct device *self,
/* Override 802.11 state transition machine. */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwx_newstate;
- ic->ic_update_htprot = iwx_update_htprot;
+ ic->ic_updateprot = iwx_updateprot;
+ ic->ic_updateslot = iwx_updateslot;
+ ic->ic_updateedca = iwx_updateedca;
ic->ic_ampdu_rx_start = iwx_ampdu_rx_start;
ic->ic_ampdu_rx_stop = iwx_ampdu_rx_stop;
#ifdef notyet
blob - 732a1a4f4ef0e73315532900483339bf7d7dab8a
blob + 58e5df4de6f347198d78a49820221e6c997180cd
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -458,8 +458,8 @@ struct iwx_softc {
uint16_t ba_winsize[IWX_MAX_TID_COUNT];
int ba_timeout_val[IWX_MAX_TID_COUNT];
- /* Task for HT protection updates. */
- struct task htprot_task;
+ /* Task for ERP/HT prot/slot-time/EDCA updates. */
+ struct task mac_ctxt_task;
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
blob - 4a9c33e9694ffc6fadbff252628344c1af63d741
blob + 4f3f21ab75170060c89b4d6cef0187583d3a3b27
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1744,6 +1744,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
if (ic->ic_opmode == IEEE80211_M_STA &&
ic->ic_state == IEEE80211_S_RUN &&
ni->ni_state == IEEE80211_STA_BSS) {
+ int updateprot = 0;
/*
* Check if protection mode has changed since last beacon.
*/
@@ -1759,6 +1760,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
else
ic->ic_flags &= ~IEEE80211_F_USEPROT;
ic->ic_bss->ni_erp = erp;
+ updateprot = 1;
}
if (htop && (ic->ic_bss->ni_flags & IEEE80211_NODE_HT)) {
enum ieee80211_htprot htprot_last, htprot;
@@ -1773,10 +1775,11 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
htprot_last, htprot));
ic->ic_stats.is_ht_prot_change++;
ic->ic_bss->ni_htop1 = ni->ni_htop1;
- if (ic->ic_update_htprot)
- ic->ic_update_htprot(ic, ic->ic_bss);
+ updateprot = 1;
}
}
+ if (updateprot && ic->ic_updateprot != NULL)
+ ic->ic_updateprot(ic);
/*
* Check if AP short slot time setting has changed
blob - 6365c1e2dfe725076a3fd0784a90e1e323fb856a
blob + a559e3bec5a136e2aeafac2097fce528e16b19d8
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -962,8 +962,8 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct
ni->ni_htop1 = IEEE80211_HTPROT_NONE;
/* Disallow Greenfield mode. None of our drivers support it. */
ni->ni_htop1 |= IEEE80211_HTOP1_NONGF_STA;
- if (ic->ic_update_htprot)
- ic->ic_update_htprot(ic, ni);
+ if (ic->ic_updateprot)
+ ic->ic_updateprot(ic);
/* Configure QoS EDCA parameters. */
for (aci = 0; aci < EDCA_NUM_AC; aci++) {
@@ -2214,8 +2214,8 @@ ieee80211_clean_nodes(struct ieee80211com *ic, int cac
htop1 |= htprot;
ic->ic_bss->ni_htop1 = htop1;
ic->ic_protmode = protmode;
- if (ic->ic_update_htprot)
- ic->ic_update_htprot(ic, ic->ic_bss);
+ if (ic->ic_updateprot)
+ ic->ic_updateprot(ic);
}
}
@@ -2489,8 +2489,8 @@ ieee80211_node_join_ht(struct ieee80211com *ic, struct
htop1 &= ~IEEE80211_HTOP1_PROT_MASK;
htop1 |= IEEE80211_HTPROT_NONHT_MIXED;
ic->ic_bss->ni_htop1 = htop1;
- if (ic->ic_update_htprot)
- ic->ic_update_htprot(ic, ic->ic_bss);
+ if (ic->ic_updateprot)
+ ic->ic_updateprot(ic);
}
}
blob - ba711629a0ba77afaf8420e005c8968f912c3cc6
blob + dff53cee227e10e14f37977117aeec021090d40a
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -244,8 +244,7 @@ struct ieee80211com {
struct ieee80211_node *, u_int8_t);
void (*ic_ampdu_rx_stop)(struct ieee80211com *,
struct ieee80211_node *, u_int8_t);
- void (*ic_update_htprot)(struct ieee80211com *,
- struct ieee80211_node *);
+ void (*ic_updateprot)(struct ieee80211com *);
int (*ic_bgscan_start)(struct ieee80211com *);
struct timeout ic_bgscan_timeout;
uint32_t ic_bgscan_fail;