summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2021-07-07 09:47:41 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2021-07-07 09:47:41 +0000
commit1d179d8e4ed83aa02ab4ccf556455979fc4d3dac (patch)
tree5c8a40bcdbb4d68332e7b331fbfb4ee80cb7aa2f /sys
parent3c83f76b0382ec030634dd460f46b446e5b20a7b (diff)
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).
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwm.c77
-rw-r--r--sys/dev/pci/if_iwmreg.h38
-rw-r--r--sys/dev/pci/if_iwmvar.h3
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 <info@genua.de>
@@ -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 <info@genua.de>
@@ -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;