From c7653db7514985419da0e64d1f438232864a8e63 Mon Sep 17 00:00:00 2001 From: stsp Date: Wed, 7 Jul 2021 09:47:40 +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). --- sys/dev/pci/if_iwm.c | 77 ++++++++++++++++++++++++++++++++++------- sys/dev/pci/if_iwmreg.h | 38 +++++++++++++++++--- sys/dev/pci/if_iwmvar.h | 3 +- 3 files changed, 100 insertions(+), 18 deletions(-) diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index d6c80191872..8304f27dac3 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.340 2021/07/07 09:13:50 stsp Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.341 2021/07/07 09:47:40 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) { @@ -9093,9 +9111,11 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) .flags = IWM_CMD_WANT_RESP, .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,10 +9130,10 @@ 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); + sizeof(struct iwm_mcc_update_resp_v3); } else { hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd_v1); hcmd.resp_pkt_len = sizeof(struct iwm_rx_packet) + @@ -9124,9 +9144,44 @@ iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) 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 +10389,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 99553e9f782..79873d7902a 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.60 2021/07/07 09:13:50 stsp Exp $ */ +/* $OpenBSD: if_iwmreg.h,v 1.61 2021/07/07 09:47:40 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 89fd69dfa44..352d37a3fb4 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.66 2021/07/07 09:13:50 stsp Exp $ */ +/* $OpenBSD: if_iwmvar.h,v 1.67 2021/07/07 09:47:40 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