From ee72d26d0865d1152cecfa2a930624fef52643cb Mon Sep 17 00:00:00 2001 From: stsp Date: Thu, 8 Jul 2021 17:14:08 +0000 Subject: [PATCH] Support MCC update response used by newer iwm(4) firmware, and verify the size of the response we receive for MCC_UPDATE commands (even though we aren't doing anything with this response yet). With the correct expected response length this time. The driver needs to expect the maximum response size, not sizeof() the response struct. The actual response size depends on the number of channels stored in the "world" regulatory profile of the device. ok sthen@ --- sys/dev/pci/if_iwm.c | 80 +++++++++++++++++++++++++++++++++-------- sys/dev/pci/if_iwmreg.h | 38 +++++++++++++++++--- sys/dev/pci/if_iwmvar.h | 3 +- 3 files changed, 100 insertions(+), 21 deletions(-) diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index ead79967700..e760d1a2068 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwm.c,v 1.342 2021/07/08 00:12:49 stsp Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.343 2021/07/08 17:14:08 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh @@ -456,6 +456,7 @@ int iwm_fill_probe_req(struct iwm_softc *, struct iwm_scan_probe_req *); int iwm_lmac_scan(struct iwm_softc *, int); int iwm_config_umac_scan(struct iwm_softc *); int iwm_umac_scan(struct iwm_softc *, int); +void iwm_mcc_update(struct iwm_softc *, struct iwm_mcc_chub_notif *); uint8_t iwm_ridx2rate(struct ieee80211_rateset *, int); int iwm_rval2ridx(int); void iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *); @@ -698,7 +699,6 @@ iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) sc->sc_capa_n_scan_channels = IWM_DEFAULT_SCAN_CHANNELS; memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa)); sc->n_cmd_versions = 0; - memset(sc->sc_fw_mcc, 0, sizeof(sc->sc_fw_mcc)); uhdr = (void *)fw->fw_rawdata; if (*(uint32_t *)fw->fw_rawdata != 0 @@ -7601,6 +7601,24 @@ iwm_umac_scan(struct iwm_softc *sc, int bgscan) return err; } +void +iwm_mcc_update(struct iwm_softc *sc, struct iwm_mcc_chub_notif *notif) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = IC2IFP(ic); + char alpha2[3]; + + snprintf(alpha2, sizeof(alpha2), "%c%c", + (le16toh(notif->mcc) & 0xff00) >> 8, le16toh(notif->mcc) & 0xff); + + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: firmware has detected regulatory domain '%s' " + "(0x%x)\n", DEVNAME(sc), alpha2, le16toh(notif->mcc)); + } + + /* TODO: Schedule a task to send MCC_UPDATE_CMD? */ +} + uint8_t iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx) { @@ -9091,11 +9109,14 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) struct iwm_host_cmd hcmd = { .id = IWM_MCC_UPDATE_CMD, .flags = IWM_CMD_WANT_RESP, + .resp_pkt_len = IWM_CMD_RESP_MAX, .data = { &mcc_cmd }, }; + struct iwm_rx_packet *pkt; + size_t resp_len; int err; - int resp_v2 = isset(sc->sc_enabled_capa, - IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2); + int resp_v3 = isset(sc->sc_enabled_capa, + IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V3); if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000 && !sc->sc_nvm.lar_enabled) { @@ -9110,23 +9131,54 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) else mcc_cmd.source_id = IWM_MCC_SOURCE_OLD_FW; - if (resp_v2) { + if (resp_v3) { /* same size as resp_v2 */ hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd); - hcmd.resp_pkt_len = sizeof(struct iwm_rx_packet) + - sizeof(struct iwm_mcc_update_resp); } else { hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd_v1); - hcmd.resp_pkt_len = sizeof(struct iwm_rx_packet) + - sizeof(struct iwm_mcc_update_resp_v1); } err = iwm_send_cmd(sc, &hcmd); if (err) return err; - iwm_free_resp(sc, &hcmd); + pkt = hcmd.resp_pkt; + if (!pkt || (pkt->hdr.flags & IWM_CMD_FAILED_MSK)) { + err = EIO; + goto out; + } - return 0; + if (resp_v3) { + struct iwm_mcc_update_resp_v3 *resp; + resp_len = iwm_rx_packet_payload_len(pkt); + if (resp_len < sizeof(*resp)) { + err = EIO; + goto out; + } + + resp = (void *)pkt->data; + if (resp_len != sizeof(*resp) + + resp->n_channels * sizeof(resp->channels[0])) { + err = EIO; + goto out; + } + } else { + struct iwm_mcc_update_resp_v1 *resp_v1; + resp_len = iwm_rx_packet_payload_len(pkt); + if (resp_len < sizeof(*resp_v1)) { + err = EIO; + goto out; + } + + resp_v1 = (void *)pkt->data; + if (resp_len != sizeof(*resp_v1) + + resp_v1->n_channels * sizeof(resp_v1->channels[0])) { + err = EIO; + goto out; + } + } +out: + iwm_free_resp(sc, &hcmd); + return err; } int @@ -10334,10 +10386,8 @@ iwm_rx_pkt(struct iwm_softc *sc, struct iwm_rx_data *data, struct mbuf_list *ml) case IWM_MCC_CHUB_UPDATE_CMD: { struct iwm_mcc_chub_notif *notif; SYNC_RESP_STRUCT(notif, pkt); - - sc->sc_fw_mcc[0] = (notif->mcc & 0xff00) >> 8; - sc->sc_fw_mcc[1] = notif->mcc & 0xff; - sc->sc_fw_mcc[2] = '\0'; + iwm_mcc_update(sc, notif); + break; } case IWM_DTS_MEASUREMENT_NOTIFICATION: diff --git a/sys/dev/pci/if_iwmreg.h b/sys/dev/pci/if_iwmreg.h index 2a5eb3d6d29..e3e93193f52 100644 --- a/sys/dev/pci/if_iwmreg.h +++ b/sys/dev/pci/if_iwmreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmreg.h,v 1.62 2021/07/08 00:12:49 stsp Exp $ */ +/* $OpenBSD: if_iwmreg.h,v 1.63 2021/07/08 17:14:08 stsp Exp $ */ /****************************************************************************** * @@ -927,7 +927,7 @@ enum msix_ivar_for_cause { #define IWM_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT 68 #define IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION 71 #define IWM_UCODE_TLV_CAPA_BEACON_STORING 72 -#define IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2 73 +#define IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V3 73 #define IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW 74 #define IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT 75 #define IWM_UCODE_TLV_CAPA_CTDP_SUPPORT 76 @@ -6566,7 +6566,7 @@ struct iwm_mcc_update_resp_v1 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** - * iwm_mcc_update_resp - response to MCC_UPDATE_CMD. + * iwm_mcc_update_resp_v2 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -6581,7 +6581,7 @@ struct iwm_mcc_update_resp_v1 { * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ -struct iwm_mcc_update_resp { +struct iwm_mcc_update_resp_v2 { uint32_t status; uint16_t mcc; uint8_t cap; @@ -6592,6 +6592,36 @@ struct iwm_mcc_update_resp { uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ +#define IWM_GEO_NO_INFO 0 +#define IWM_GEO_WMM_ETSI_5GHZ_INFO (1 << 0) + +/** + * iwm_mcc_update_resp_v3 - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: see &enum iwm_mcc_update_status + * @mcc: the new applied MCC + * @cap: capabilities for all channels which matches the MCC + * @source_id: the MCC source, see IWM_MCC_SOURCE_* + * @time: time elapsed from the MCC test start (in 30 seconds TU) + * @geo_info: geographic specific profile information + * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 + * channels, depending on platform) + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwm_mcc_update_resp_v3 { + uint32_t status; + uint16_t mcc; + uint8_t cap; + uint8_t source_id; + uint16_t time; + uint16_t geo_info; + uint32_t n_channels; + uint32_t channels[0]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ + /** * struct iwm_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) diff --git a/sys/dev/pci/if_iwmvar.h b/sys/dev/pci/if_iwmvar.h index 7d921776bd7..bcda8e90146 100644 --- a/sys/dev/pci/if_iwmvar.h +++ b/sys/dev/pci/if_iwmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmvar.h,v 1.68 2021/07/08 00:12:49 stsp Exp $ */ +/* $OpenBSD: if_iwmvar.h,v 1.69 2021/07/08 17:14:08 stsp Exp $ */ /* * Copyright (c) 2014 genua mbh @@ -548,7 +548,6 @@ struct iwm_softc { #define IWM_MAX_FW_CMD_VERSIONS 64 struct iwm_fw_cmd_version cmd_versions[IWM_MAX_FW_CMD_VERSIONS]; int n_cmd_versions; - char sc_fw_mcc[3]; int sc_intmask; int sc_flags; -- 2.20.1