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.

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 *,

Reply via email to