If authentication to the AP times out iwx(4) currently triggers a
fatal firmware error while resetting the device.

As part of configuring the device for operation, we create a "binding"
between a MAC config and a PHY config in firmware.
And before we start to associate, firmware is given a "time event"
which "protects the seession" (meaning it prevents firmware from
moving off-channel while we are trying to talk to our new AP).

If we fail to associate we try to reset the device configuration.
But if we attempt to remove the "binding" while the time event
is still active, the firmware will crash (trace shown below).

This patch below fills in missing bits of time-event management.
Code was lifted from iwm(4) and adapted to iwx(4) data structures.

We now stop the time-event as soon as we realize that authentication has
failed. While here, remove iwx_send_time_event_cmd() which is unused.

ok?

iwx0: SCAN -> AUTH
iwx0: sending auth to xx:xx:xx:xx:xx:xx on channel 64 mode 11a
iwx0: authentication timed out for xx:xx:xx:xx:xx:xx
iwx_send_cmd: sending command 0x118
iwx_cmd_done: command 0x18 done
iwx_send_cmd: sending command 0x11e
iwx_cmd_done: command 0x1e done
iwx_send_cmd: sending command 0x118
iwx_cmd_done: command 0x18 done
iwx_send_cmd: sending command 0x119
iwx_cmd_done: command 0x19 done
iwx_send_cmd: sending command 0x12b
iwx0: dumping device error log
iwx0: Start Error Log Dump:
iwx0: Status: 0x19, count: 6
iwx0: 0x00000071 | NMI_INTERRUPT_UMAC_FATAL    
iwx0: 0080A210 | trm_hw_status0
iwx0: 00000000 | trm_hw_status1
iwx0: 004FB322 | branchlink2
iwx0: 004F1B86 | interruptlink1
iwx0: 004F1B86 | interruptlink2
iwx0: 00013622 | data1
iwx0: 00001000 | data2
iwx0: 00000000 | data3
iwx0: 00000000 | beacon time
iwx0: B289E195 | tsf low
iwx0: 0000007D | tsf hi
iwx0: 00000000 | time gp1
iwx0: 008AB03C | time gp2
iwx0: 00000001 | uCode revision type
iwx0: 00000044 | uCode version major
iwx0: 01D30B0C | uCode version minor
iwx0: 00000340 | hw version
iwx0: 18889000 | board version
iwx0: 80F9FC3B | hcmd
iwx0: 24020000 | isr0
iwx0: 01000000 | isr1
iwx0: 08F00002 | isr2
iwx0: 00C3000C | isr3
iwx0: 00000000 | isr4
iwx0: 0100001C | last cmd Id
iwx0: 00013622 | wait_event
iwx0: 00000080 | l2p_control
iwx0: 00010034 | l2p_duration
iwx0: 0000003F | l2p_mhvalid
iwx0: 00000080 | l2p_addr_match
iwx0: 00000009 | lmpm_pmg_sel
iwx0: 00000000 | timestamp
iwx0: 000080A4 | flow_handler
iwx0: Start UMAC Error Log Dump:
iwx0: Status: 0x19, count: 7
iwx0: 0x2000320F | ADVANCED_SYSASSERT
iwx0: 0x00000000 | umac branchlink1
iwx0: 0x80455D20 | umac branchlink2
iwx0: 0x010771CE | umac interruptlink1
iwx0: 0x00000000 | umac interruptlink2
iwx0: 0x00000000 | umac data1
iwx0: 0xDEADBEEF | umac data2
iwx0: 0xDEADBEEF | umac data3
iwx0: 0x00000044 | umac major
iwx0: 0x01D30B0C | umac minor
iwx0: 0x008AB036 | frame pointer
iwx0: 0xC0885E68 | stack pointer
iwx0: 0x001C012B | last host cmd
iwx0: 0x00000000 | isr status reg
driver status:
  tx ring  0: qid=0  cur=29  cur_hw=29  queued=1  
  tx ring  1: qid=1  cur=1   cur_hw=1   queued=0  
  tx ring  2: qid=2  cur=0   cur_hw=0   queued=0  
  tx ring  3: qid=3  cur=0   cur_hw=0   queued=0  
  tx ring  4: qid=4  cur=0   cur_hw=0   queued=0  
  tx ring  5: qid=5  cur=0   cur_hw=0   queued=0  
  tx ring  6: qid=6  cur=0   cur_hw=0   queued=0  
  tx ring  7: qid=7  cur=0   cur_hw=0   queued=0  
  tx ring  8: qid=8  cur=0   cur_hw=0   queued=0  
  tx ring  9: qid=9  cur=0   cur_hw=0   queued=0  
  rx ring: cur=136
  802.11 state AUTH
iwx0: fatal firmware error

diff /usr/src
commit - 36eaeeee8d761cea6a70e9e97003c06b13843e25
path + /usr/src
blob - f4dc3de32d8cc36a18e016b789f7374f34b4b4fd
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -311,6 +311,7 @@ void        iwx_init_channel_map(struct iwx_softc *, 
uint16_t
 void   iwx_post_alive(struct iwx_softc *);
 int    iwx_schedule_session_protection(struct iwx_softc *, struct iwx_node *,
            uint32_t);
+void   iwx_unprotect_session(struct iwx_softc *, struct iwx_node *);
 void   iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
 void   iwx_setup_ht_rates(struct iwx_softc *);
 void   iwx_setup_vht_rates(struct iwx_softc *);
@@ -2910,56 +2911,7 @@ iwx_post_alive(struct iwx_softc *sc)
        iwx_ict_reset(sc);
 }
 
-/*
- * For the high priority TE use a time event type that has similar priority to
- * the FW's action scan priority.
- */
-#define IWX_ROC_TE_TYPE_NORMAL IWX_TE_P2P_DEVICE_DISCOVERABLE
-#define IWX_ROC_TE_TYPE_MGMT_TX IWX_TE_P2P_CLIENT_ASSOC
-
 int
-iwx_send_time_event_cmd(struct iwx_softc *sc,
-    const struct iwx_time_event_cmd *cmd)
-{
-       struct iwx_rx_packet *pkt;
-       struct iwx_time_event_resp *resp;
-       struct iwx_host_cmd hcmd = {
-               .id = IWX_TIME_EVENT_CMD,
-               .flags = IWX_CMD_WANT_RESP,
-               .resp_pkt_len = sizeof(*pkt) + sizeof(*resp),
-       };
-       uint32_t resp_len;
-       int err;
-
-       hcmd.data[0] = cmd;
-       hcmd.len[0] = sizeof(*cmd);
-       err = iwx_send_cmd(sc, &hcmd);
-       if (err)
-               return err;
-
-       pkt = hcmd.resp_pkt;
-       if (!pkt || (pkt->hdr.flags & IWX_CMD_FAILED_MSK)) {
-               err = EIO;
-               goto out;
-       }
-
-       resp_len = iwx_rx_packet_payload_len(pkt);
-       if (resp_len != sizeof(*resp)) {
-               err = EIO;
-               goto out;
-       }
-
-       resp = (void *)pkt->data;
-       if (le32toh(resp->status) == 0)
-               sc->sc_time_event_uid = le32toh(resp->unique_id);
-       else
-               err = EIO;
-out:
-       iwx_free_resp(sc, &hcmd);
-       return err;
-}
-
-int
 iwx_schedule_session_protection(struct iwx_softc *sc, struct iwx_node *in,
     uint32_t duration)
 {
@@ -2971,11 +2923,36 @@ iwx_schedule_session_protection(struct iwx_softc *sc, 
                .duration_tu = htole32(duration * IEEE80211_DUR_TU),
        };
        uint32_t cmd_id;
+       int err;
 
        cmd_id = iwx_cmd_id(IWX_SESSION_PROTECTION_CMD, IWX_MAC_CONF_GROUP, 0);
-       return iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd);
+       err = iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd);
+       if (!err)
+               sc->sc_flags |= IWX_FLAG_TE_ACTIVE;
+       return err;
 }
 
+void
+iwx_unprotect_session(struct iwx_softc *sc, struct iwx_node *in)
+{
+       struct iwx_session_prot_cmd cmd = {
+               .id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id,
+                   in->in_color)),
+               .action = htole32(IWX_FW_CTXT_ACTION_REMOVE),
+               .conf_id = htole32(IWX_SESSION_PROTECT_CONF_ASSOC),
+               .duration_tu = 0,
+       };
+       uint32_t cmd_id;
+
+       /* Do nothing if the time event has already ended. */
+       if ((sc->sc_flags & IWX_FLAG_TE_ACTIVE) == 0)
+               return;
+
+       cmd_id = iwx_cmd_id(IWX_SESSION_PROTECTION_CMD, IWX_MAC_CONF_GROUP, 0);
+       if (iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd) == 0)
+               sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE;
+}
+
 /*
  * NVM read access and content parsing.  We do not support
  * external NVM or writing NVM.
@@ -3434,6 +3411,8 @@ iwx_mac_ctxt_task(void *arg)
        if (err)
                printf("%s: failed to update MAC\n", DEVNAME(sc));
 
+       iwx_unprotect_session(sc, in);
+
        refcnt_rele_wake(&sc->task_refs);
        splx(s);
 }
@@ -7832,6 +7811,8 @@ iwx_deauth(struct iwx_softc *sc)
 
        splassert(IPL_NET);
 
+       iwx_unprotect_session(sc, in);
+
        if (sc->sc_flags & IWX_FLAG_STA_ACTIVE) {
                err = iwx_rm_sta(sc, in);
                if (err)
@@ -9662,8 +9643,21 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
                }
 
                case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
-                   IWX_SESSION_PROTECTION_NOTIF):
+                   IWX_SESSION_PROTECTION_NOTIF): {
+                       struct iwx_session_prot_notif *notif;
+                       uint32_t status, start, conf_id;
+
+                       SYNC_RESP_STRUCT(notif, pkt);
+
+                       status = le32toh(notif->status);
+                       start = le32toh(notif->start);
+                       conf_id = le32toh(notif->conf_id);
+                       /* Check for end of successful PROTECT_CONF_ASSOC. */
+                       if (status == 1 && start == 0 &&
+                           conf_id == IWX_SESSION_PROTECT_CONF_ASSOC)
+                               sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE;
                        break;
+               }
 
                case IWX_WIDE_ID(IWX_SYSTEM_GROUP,
                    IWX_FSEQ_VER_MISMATCH_NOTIFICATION):

Reply via email to