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;