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):