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;

Reply via email to