Fix and re-enable active scans on iwm(4) and iwx(4).
authorstsp <stsp@openbsd.org>
Fri, 21 Jan 2022 15:51:02 +0000 (15:51 +0000)
committerstsp <stsp@openbsd.org>
Fri, 21 Jan 2022 15:51:02 +0000 (15:51 +0000)
Ensure that we supply the access point's DTIM period to firmware after
an active scan, as soon as the next beacon arrives. This prevents the
problems which prompted us to keep active scans disabled in our drivers.

Problem debugged and patch by zxystd from the OpenIntelWireless project.
I made some tweaks regarding TIM parsing, which were reviewed by zxystd.

Johannes Berg from Intel has confirmed to me via IRC that firmware
will misbehave if running with a zero DTIM period.

Tested:
8265: jca, stsp
9260: kettenis (possible fallout observed here; will keep an eye on it)
9650: stsp
ax200: zxystd, kevlo, stsp
ax201: stsp

ok kevlo@ kettenis@

sys/dev/pci/if_iwm.c
sys/dev/pci/if_iwx.c
sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_var.h

index 607a45b..5e0af5f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwm.c,v 1.389 2022/01/09 05:42:50 jsg Exp $        */
+/*     $OpenBSD: if_iwm.c,v 1.390 2022/01/21 15:51:02 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -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, void *aux)
        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;
index 4c85ad1..57bdcce 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwx.c,v 1.133 2022/01/09 05:42:52 jsg Exp $        */
+/*     $OpenBSD: if_iwx.c,v 1.134 2022/01/21 15:51:02 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -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 *);
@@ -3213,6 +3214,16 @@ iwx_updateedca(struct ieee80211com *ic)
                iwx_add_task(sc, systq, &sc->mac_ctxt_task);
 }
 
+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, void *aux)
        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;
index d764aa0..fcc8478 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_input.c,v 1.242 2022/01/12 08:29:27 stsp Exp $      */
+/*     $OpenBSD: ieee80211_input.c,v 1.243 2022/01/21 15:51:03 stsp Exp $      */
 
 /*-
  * Copyright (c) 2001 Atsushi Onoe
@@ -1605,10 +1605,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
        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, struct mbuf *m,
        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, struct mbuf *m,
                        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, struct mbuf *m,
        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, struct mbuf *m,
                            (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.
index d211947..161853a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_var.h,v 1.109 2021/12/05 11:33:45 stsp Exp $        */
+/*     $OpenBSD: ieee80211_var.h,v 1.110 2022/01/21 15:51:03 stsp Exp $        */
 /*     $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
 
 /*-
@@ -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 *,