> Date: Thu, 13 Jan 2022 17:45:03 +0100
> From: Stefan Sperling <[email protected]>
>
> At present active scans (which send probe requests, as opposed to
> just listening for beacons) are disabled on iwm 9k and iwx. This
> was done because firmware misbehaved after association.
>
> zxystd from the OpenIntelWireless project has debugged the issue
> and has sent me a patch against OpenBSD which fixes this problem.
> The patch is below, with some small tweaks by me which have already
> been reviewed by zxystd.
>
> It seems that firmware misbehaves if the driver sets the DTIM period
> to zero. This value is read from TIM information elements (IE) in beacons.
> Passive scans worked because we picked up the DTIM period from a beacon,
> while probe responses received during active scans lack the TIM IE, which
> resulted in a zero DTIM period being configured in firmware. We then never
> updated TIM information when a beacon was recieved, letting firmware run
> with a zero DTIM period until it eventually stopped working.
>
> I have tested this patch on iwm 8265 and iwx ax200.
> And jmc@ has been testing this on ax200 for some time.
> More tests are welcome, on any supported device.
This seems to be an improvement on iwm 9260. At least connecting to
the WiFi at my parents' worked better than during christmas.
However, running this diff I had a problem after resuming my laptop
twice. After resume the interface didn't work and I found the
following in dmesg:
iwm0: could not initialize hardware
I tried to reset the interface by bringing it down and up again, which
crashed the machine. It must have been in ddb since typing "bo re"
made it reset. Unfortunately I don't have further information since I
was in X.
> diff refs/heads/remove-find-node-for-beacon refs/heads/iwm-iwx-active-scan
> blob - 607a45b71f7ea71773809136cadf122c72375558
> blob + 937f2cc28f6c85502031e4c9efa0a02c75fd1a6d
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -340,6 +340,7 @@ void iwm_updateprot(struct ieee80211com *);
> void iwm_updateslot(struct ieee80211com *);
> void iwm_updateedca(struct ieee80211com *);
> void iwm_updatechan(struct ieee80211com *);
> +void iwm_updatedtim(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 *);
> @@ -3374,6 +3375,8 @@ iwm_mac_ctxt_task(void *arg)
> err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1);
> if (err)
> printf("%s: failed to update MAC\n", DEVNAME(sc));
> +
> + iwm_unprotect_session(sc, in);
>
> refcnt_rele_wake(&sc->task_refs);
> splx(s);
> @@ -3454,6 +3457,16 @@ iwm_updatechan(struct ieee80211com *ic)
> iwm_add_task(sc, systq, &sc->phy_ctxt_task);
> }
>
> +void
> +iwm_updatedtim(struct ieee80211com *ic)
> +{
> + struct iwm_softc *sc = ic->ic_softc;
> +
> + if (ic->ic_state == IEEE80211_S_RUN &&
> + !task_pending(&sc->newstate_task))
> + iwm_add_task(sc, systq, &sc->mac_ctxt_task);
> +}
> +
> int
> iwm_sta_tx_agg(struct iwm_softc *sc, struct ieee80211_node *ni, uint8_t tid,
> uint16_t ssn, uint16_t winsize, int start)
> @@ -7275,12 +7288,7 @@ iwm_lmac_scan_fill_channels(struct iwm_softc *sc,
> chan->iter_count = htole16(1);
> chan->iter_interval = 0;
> chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
> - /*
> - * Firmware may become unresponsive when asked to send
> - * a directed probe request on a passive channel.
> - */
> - if (n_ssids != 0 && !bgscan &&
> - (c->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
> + if (n_ssids != 0 && !bgscan)
> chan->flags |= htole32(1 << 1); /* select SSID 0 */
> chan++;
> nchan++;
> @@ -7307,12 +7315,7 @@ iwm_umac_scan_fill_channels(struct iwm_softc *sc,
> chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0);
> chan->iter_count = 1;
> chan->iter_interval = htole16(0);
> - /*
> - * Firmware may become unresponsive when asked to send
> - * a directed probe request on a passive channel.
> - */
> - if (n_ssids != 0 && !bgscan &&
> - (c->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
> + if (n_ssids != 0 && !bgscan)
> chan->flags = htole32(1 << 0); /* select SSID 0 */
> chan++;
> nchan++;
> @@ -7782,13 +7785,7 @@ iwm_umac_scan(struct iwm_softc *sc, int bgscan)
> IWM_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER;
> }
>
> - /*
> - * Check if we're doing an active directed scan.
> - * 9k devices may randomly lock up (no interrupts) after association
> - * following active scans. Use passive scan only for now on 9k.
> - */
> - if (sc->sc_device_family != IWM_DEVICE_FAMILY_9000 &&
> - ic->ic_des_esslen != 0) {
> + if (ic->ic_des_esslen != 0) {
> if (isset(sc->sc_ucode_api,
> IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) {
> tail->direct_scan[0].id = IEEE80211_ELEMID_SSID;
> @@ -11620,6 +11617,7 @@ iwm_attach(struct device *parent, struct device *self,
> ic->ic_updateprot = iwm_updateprot;
> ic->ic_updateslot = iwm_updateslot;
> ic->ic_updateedca = iwm_updateedca;
> + ic->ic_updatedtim = iwm_updatedtim;
> ic->ic_ampdu_rx_start = iwm_ampdu_rx_start;
> ic->ic_ampdu_rx_stop = iwm_ampdu_rx_stop;
> ic->ic_ampdu_tx_start = iwm_ampdu_tx_start;
> blob - 4c85ad108a8188a811c2144657bf53c744746d5d
> blob + 7681719b425e7a636094aa8578ba4192fd68bb68
> --- sys/dev/pci/if_iwx.c
> +++ sys/dev/pci/if_iwx.c
> @@ -311,6 +311,7 @@ void iwx_updatechan(struct ieee80211com *);
> void iwx_updateprot(struct ieee80211com *);
> void iwx_updateslot(struct ieee80211com *);
> void iwx_updateedca(struct ieee80211com *);
> +void iwx_updatedtim(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 *);
> @@ -3214,6 +3215,16 @@ iwx_updateedca(struct ieee80211com *ic)
> }
>
> void
> +iwx_updatedtim(struct ieee80211com *ic)
> +{
> + struct iwx_softc *sc = ic->ic_softc;
> +
> + if (ic->ic_state == IEEE80211_S_RUN &&
> + !task_pending(&sc->newstate_task))
> + iwx_add_task(sc, systq, &sc->mac_ctxt_task);
> +}
> +
> +void
> iwx_sta_tx_agg_start(struct iwx_softc *sc, struct ieee80211_node *ni,
> uint8_t tid)
> {
> @@ -5965,15 +5976,8 @@ iwx_umac_scan_fill_channels(struct iwx_softc *sc,
> chan->v1.iter_count = 1;
> chan->v1.iter_interval = htole16(0);
> }
> - /*
> - * Firmware may become unresponsive when asked to send
> - * a directed probe request on a passive channel.
> - */
> -#if 0 /* Some people see "device timeout" after active scans. */
> - if (n_ssids != 0 && !bgscan &&
> - (c->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
> + if (n_ssids != 0 && !bgscan)
> chan->flags = htole32(1 << 0); /* select SSID 0 */
> -#endif
> chan++;
> nchan++;
> }
> @@ -6220,9 +6224,7 @@ iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *sc,
> int
> iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan)
> {
> -#if 0 /* Some people see "device timeout" after active scans. */
> struct ieee80211com *ic = &sc->sc_ic;
> -#endif
> struct iwx_host_cmd hcmd = {
> .id = iwx_cmd_id(IWX_SCAN_REQ_UMAC, IWX_LONG_GROUP, 0),
> .len = { 0, },
> @@ -6258,7 +6260,6 @@ iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan)
> return err;
> }
>
> -#if 0 /* Some people see "device timeout" after active scans. */
> if (ic->ic_des_esslen != 0) {
> scan_p->probe_params.direct_scan[0].id = IEEE80211_ELEMID_SSID;
> scan_p->probe_params.direct_scan[0].len = ic->ic_des_esslen;
> @@ -6267,7 +6268,6 @@ iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan)
> bitmap_ssid |= (1 << 0);
> n_ssid = 1;
> }
> -#endif
>
> iwx_scan_umac_fill_ch_p_v6(sc, &scan_p->channel_params, bitmap_ssid,
> n_ssid, bgscan);
> @@ -9557,6 +9557,7 @@ iwx_attach(struct device *parent, struct device *self,
> ic->ic_updateprot = iwx_updateprot;
> ic->ic_updateslot = iwx_updateslot;
> ic->ic_updateedca = iwx_updateedca;
> + ic->ic_updatedtim = iwx_updatedtim;
> ic->ic_ampdu_rx_start = iwx_ampdu_rx_start;
> ic->ic_ampdu_rx_stop = iwx_ampdu_rx_stop;
> ic->ic_ampdu_tx_start = iwx_ampdu_tx_start;
> blob - b049ada63ce5ecd29b413f0eec0aeae28cf64a76
> blob + ff8938b0759db03147f818b6f1d3c81f98e92db7
> --- sys/net80211/ieee80211_input.c
> +++ sys/net80211/ieee80211_input.c
> @@ -1605,10 +1605,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
> struct ieee80211_node *ni;
> const struct ieee80211_frame *wh;
> const u_int8_t *frm, *efrm;
> - const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie;
> + const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie, *tim;
> const u_int8_t *rsnie, *wpaie, *htcaps, *htop;
> u_int16_t capinfo, bintval;
> - u_int8_t chan, bchan, erp, dtim_count, dtim_period;
> + u_int8_t chan, bchan, erp;
> int is_new;
>
> /*
> @@ -1646,12 +1646,11 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
> bintval = LE_READ_2(frm); frm += 2;
> capinfo = LE_READ_2(frm); frm += 2;
>
> - ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = NULL;
> + ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = tim = NULL;
> htcaps = htop = NULL;
> bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
> chan = bchan;
> erp = 0;
> - dtim_count = dtim_period = 0;
> while (frm + 2 <= efrm) {
> if (frm + 2 + frm[1] > efrm) {
> ic->ic_stats.is_rx_elem_toosmall++;
> @@ -1694,10 +1693,11 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
> htop = frm;
> break;
> case IEEE80211_ELEMID_TIM:
> - if (frm[1] > 3) {
> - dtim_count = frm[2];
> - dtim_period = frm[3];
> + if (frm[1] < 4) {
> + ic->ic_stats.is_rx_elem_toosmall++;
> + break;
> }
> + tim = frm;
> break;
> case IEEE80211_ELEMID_VENDOR:
> if (frm[1] < 4) {
> @@ -1780,8 +1780,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
> if (htop && !ieee80211_setup_htop(ni, htop + 2, htop[1], 1))
> htop = NULL; /* invalid HTOP */
>
> - ni->ni_dtimcount = dtim_count;
> - ni->ni_dtimperiod = dtim_period;
> + if (tim) {
> + ni->ni_dtimcount = tim[2];
> + ni->ni_dtimperiod = tim[3];
> + }
>
> /*
> * When operating in station mode, check for state updates
> @@ -1860,6 +1862,14 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
> (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
> }
>
> + if (tim && ic->ic_bss->ni_dtimperiod != ni->ni_dtimperiod) {
> + ic->ic_bss->ni_dtimperiod = ni->ni_dtimperiod;
> + ic->ic_bss->ni_dtimcount = ni->ni_dtimcount;
> +
> + if (ic->ic_updatedtim != NULL)
> + ic->ic_updatedtim(ic);
> + }
> +
> /*
> * Reset management timer. If it is non-zero in RUN state, the
> * driver sent a probe request after a missed beacon event.
> blob - d211947e3d0bd0033e22e37eb411c8930bbbee39
> blob + 8d5c254af3f3b8245b3d7a2d57b10238eb2413fa
> --- sys/net80211/ieee80211_var.h
> +++ sys/net80211/ieee80211_var.h
> @@ -249,6 +249,7 @@ struct ieee80211com {
> struct ieee80211_node *, u_int8_t);
> void (*ic_updateprot)(struct ieee80211com *);
> void (*ic_updatechan)(struct ieee80211com *);
> + void (*ic_updatedtim)(struct ieee80211com *);
> int (*ic_bgscan_start)(struct ieee80211com *);
> void (*ic_bgscan_done)(struct ieee80211com *,
> struct ieee80211_node_switch_bss_arg *,
>
>