--- /dev/null
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 28 Aug 2023 09:54:39 +0200
+Subject: [PATCH] wifi: cfg80211: annotate iftype_data pointer with sparse
+
+There were are a number of cases in mac80211 and iwlwifi (at
+least) that used the sband->iftype_data pointer directly,
+instead of using the accessors to find the right array entry
+to use.
+
+Make sparse warn when such a thing is done.
+
+To not have a lot of casts, add two helper functions/macros
+
+ - ieee80211_set_sband_iftype_data()
+ - for_each_sband_iftype_data()
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -5893,8 +5893,9 @@ static void ath11k_mac_setup_he_cap(stru
+ ar->mac.iftype[NL80211_BAND_2GHZ],
+ NL80211_BAND_2GHZ);
+ band = &ar->mac.sbands[NL80211_BAND_2GHZ];
+- band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ];
+- band->n_iftype_data = count;
++ _ieee80211_set_sband_iftype_data(band,
++ ar->mac.iftype[NL80211_BAND_2GHZ],
++ count);
+ }
+
+ if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
+@@ -5902,8 +5903,9 @@ static void ath11k_mac_setup_he_cap(stru
+ ar->mac.iftype[NL80211_BAND_5GHZ],
+ NL80211_BAND_5GHZ);
+ band = &ar->mac.sbands[NL80211_BAND_5GHZ];
+- band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
+- band->n_iftype_data = count;
++ _ieee80211_set_sband_iftype_data(band,
++ ar->mac.iftype[NL80211_BAND_5GHZ],
++ count);
+ }
+
+ if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP &&
+@@ -5912,8 +5914,9 @@ static void ath11k_mac_setup_he_cap(stru
+ ar->mac.iftype[NL80211_BAND_6GHZ],
+ NL80211_BAND_6GHZ);
+ band = &ar->mac.sbands[NL80211_BAND_6GHZ];
+- band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ];
+- band->n_iftype_data = count;
++ _ieee80211_set_sband_iftype_data(band,
++ ar->mac.iftype[NL80211_BAND_6GHZ],
++ count);
+ }
+ }
+
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+@@ -1075,8 +1075,8 @@ static void iwl_init_he_hw_capab(struct
+
+ memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa));
+
+- sband->iftype_data = iftype_data;
+- sband->n_iftype_data = ARRAY_SIZE(iwl_he_eht_capa);
++ _ieee80211_set_sband_iftype_data(sband, iftype_data,
++ ARRAY_SIZE(iwl_he_eht_capa));
+
+ for (i = 0; i < sband->n_iftype_data; i++)
+ iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i],
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+@@ -1119,8 +1119,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
+
+ band = &phy->mt76->sband_2g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_5ghz) {
+@@ -1128,8 +1127,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
+
+ band = &phy->mt76->sband_5g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_6ghz) {
+@@ -1137,8 +1135,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data);
+
+ band = &phy->mt76->sband_6g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+ }
+
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+@@ -196,8 +196,7 @@ void mt7921_set_stream_he_caps(struct mt
+ n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data);
+
+ band = &phy->mt76->sband_2g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_5ghz) {
+@@ -205,16 +204,14 @@ void mt7921_set_stream_he_caps(struct mt
+ n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data);
+
+ band = &phy->mt76->sband_5g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+
+ if (phy->mt76->cap.has_6ghz) {
+ data = phy->iftype[NL80211_BAND_6GHZ];
+ n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data);
+
+ band = &phy->mt76->sband_6g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+ }
+ }
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+@@ -823,8 +823,7 @@ __mt7996_set_stream_he_eht_caps(struct m
+ n++;
+ }
+
+- sband->iftype_data = data;
+- sband->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(sband, data, n);
+ }
+
+ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
+--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
++++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
+@@ -1335,7 +1335,7 @@ static int qtnf_cmd_band_fill_iftype(con
+ return -EINVAL;
+ }
+
+- kfree(band->iftype_data);
++ kfree((__force void *)band->iftype_data);
+ band->iftype_data = NULL;
+ band->n_iftype_data = tlv->n_iftype_data;
+ if (band->n_iftype_data == 0)
+@@ -1347,7 +1347,8 @@ static int qtnf_cmd_band_fill_iftype(con
+ band->n_iftype_data = 0;
+ return -ENOMEM;
+ }
+- band->iftype_data = iftype_data;
++
++ _ieee80211_set_sband_iftype_data(band, iftype_data, tlv->n_iftype_data);
+
+ for (i = 0; i < band->n_iftype_data; i++)
+ qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]);
+--- a/drivers/net/wireless/quantenna/qtnfmac/core.c
++++ b/drivers/net/wireless/quantenna/qtnfmac/core.c
+@@ -549,7 +549,7 @@ static void qtnf_core_mac_detach(struct
+ if (!wiphy->bands[band])
+ continue;
+
+- kfree(wiphy->bands[band]->iftype_data);
++ kfree((__force void *)wiphy->bands[band]->iftype_data);
+ wiphy->bands[band]->n_iftype_data = 0;
+
+ kfree(wiphy->bands[band]->channels);
+--- a/drivers/net/wireless/realtek/rtw89/core.c
++++ b/drivers/net/wireless/realtek/rtw89/core.c
+@@ -3328,8 +3328,7 @@ static void rtw89_init_he_cap(struct rtw
+ idx++;
+ }
+
+- sband->iftype_data = iftype_data;
+- sband->n_iftype_data = idx;
++ _ieee80211_set_sband_iftype_data(sband, iftype_data, idx);
+ }
+
+ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
+@@ -3374,11 +3373,11 @@ err:
+ hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+ hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+ if (sband_2ghz)
+- kfree(sband_2ghz->iftype_data);
++ kfree((__force void *)sband_2ghz->iftype_data);
+ if (sband_5ghz)
+- kfree(sband_5ghz->iftype_data);
++ kfree((__force void *)sband_5ghz->iftype_data);
+ if (sband_6ghz)
+- kfree(sband_6ghz->iftype_data);
++ kfree((__force void *)sband_6ghz->iftype_data);
+ kfree(sband_2ghz);
+ kfree(sband_5ghz);
+ kfree(sband_6ghz);
+@@ -3390,11 +3389,11 @@ static void rtw89_core_clr_supported_ban
+ struct ieee80211_hw *hw = rtwdev->hw;
+
+ if (hw->wiphy->bands[NL80211_BAND_2GHZ])
+- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
+ if (hw->wiphy->bands[NL80211_BAND_5GHZ])
+- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
+ if (hw->wiphy->bands[NL80211_BAND_6GHZ])
+- kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
++ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
+ kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
+ kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
+ kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]);
+--- a/drivers/net/wireless/realtek/rtw89/regd.c
++++ b/drivers/net/wireless/realtek/rtw89/regd.c
+@@ -376,7 +376,7 @@ bottom:
+ return;
+
+ wiphy->bands[NL80211_BAND_6GHZ] = NULL;
+- kfree(sband->iftype_data);
++ kfree((__force void *)sband->iftype_data);
+ kfree(sband);
+ }
+
+--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
+@@ -4900,25 +4900,19 @@ static const struct ieee80211_sband_ifty
+
+ static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)
+ {
+- u16 n_iftype_data;
+-
+- if (sband->band == NL80211_BAND_2GHZ) {
+- n_iftype_data = ARRAY_SIZE(sband_capa_2ghz);
+- sband->iftype_data =
+- (struct ieee80211_sband_iftype_data *)sband_capa_2ghz;
+- } else if (sband->band == NL80211_BAND_5GHZ) {
+- n_iftype_data = ARRAY_SIZE(sband_capa_5ghz);
+- sband->iftype_data =
+- (struct ieee80211_sband_iftype_data *)sband_capa_5ghz;
+- } else if (sband->band == NL80211_BAND_6GHZ) {
+- n_iftype_data = ARRAY_SIZE(sband_capa_6ghz);
+- sband->iftype_data =
+- (struct ieee80211_sband_iftype_data *)sband_capa_6ghz;
+- } else {
+- return;
++ switch (sband->band) {
++ case NL80211_BAND_2GHZ:
++ ieee80211_set_sband_iftype_data(sband, sband_capa_2ghz);
++ break;
++ case NL80211_BAND_5GHZ:
++ ieee80211_set_sband_iftype_data(sband, sband_capa_5ghz);
++ break;
++ case NL80211_BAND_6GHZ:
++ ieee80211_set_sband_iftype_data(sband, sband_capa_6ghz);
++ break;
++ default:
++ break;
+ }
+-
+- sband->n_iftype_data = n_iftype_data;
+ }
+
+ #ifdef CPTCFG_MAC80211_MESH
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -415,6 +415,19 @@ struct ieee80211_sta_eht_cap {
+ u8 eht_ppe_thres[IEEE80211_EHT_PPE_THRES_MAX_LEN];
+ };
+
++/* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */
++#ifdef __CHECKER__
++/*
++ * This is used to mark the sband->iftype_data pointer which is supposed
++ * to be an array with special access semantics (per iftype), but a lot
++ * of code got it wrong in the past, so with this marking sparse will be
++ * noisy when the pointer is used directly.
++ */
++# define __iftd __attribute__((noderef, address_space(__iftype_data)))
++#else
++# define __iftd
++#endif /* __CHECKER__ */
++
+ /**
+ * struct ieee80211_sband_iftype_data - sband data per interface type
+ *
+@@ -548,10 +561,48 @@ struct ieee80211_supported_band {
+ struct ieee80211_sta_s1g_cap s1g_cap;
+ struct ieee80211_edmg edmg_cap;
+ u16 n_iftype_data;
+- const struct ieee80211_sband_iftype_data *iftype_data;
++ const struct ieee80211_sband_iftype_data __iftd *iftype_data;
+ };
+
+ /**
++ * _ieee80211_set_sband_iftype_data - set sband iftype data array
++ * @sband: the sband to initialize
++ * @iftd: the iftype data array pointer
++ * @n_iftd: the length of the iftype data array
++ *
++ * Set the sband iftype data array; use this where the length cannot
++ * be derived from the ARRAY_SIZE() of the argument, but prefer
++ * ieee80211_set_sband_iftype_data() where it can be used.
++ */
++static inline void
++_ieee80211_set_sband_iftype_data(struct ieee80211_supported_band *sband,
++ const struct ieee80211_sband_iftype_data *iftd,
++ u16 n_iftd)
++{
++ sband->iftype_data = (const void __iftd __force *)iftd;
++ sband->n_iftype_data = n_iftd;
++}
++
++/**
++ * ieee80211_set_sband_iftype_data - set sband iftype data array
++ * @sband: the sband to initialize
++ * @iftd: the iftype data array
++ */
++#define ieee80211_set_sband_iftype_data(sband, iftd) \
++ _ieee80211_set_sband_iftype_data(sband, iftd, ARRAY_SIZE(iftd))
++
++/**
++ * for_each_sband_iftype_data - iterate sband iftype data entries
++ * @sband: the sband whose iftype_data array to iterate
++ * @i: iterator counter
++ * @iftd: iftype data pointer to set
++ */
++#define for_each_sband_iftype_data(sband, i, iftd) \
++ for (i = 0, iftd = (const void __force *)&(sband)->iftype_data[i]; \
++ i < (sband)->n_iftype_data; \
++ i++, iftd = (const void __force *)&(sband)->iftype_data[i])
++
++/**
+ * ieee80211_get_sband_iftype_data - return sband data for a given iftype
+ * @sband: the sband to search for the STA on
+ * @iftype: enum nl80211_iftype
+@@ -562,6 +613,7 @@ static inline const struct ieee80211_sba
+ ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband,
+ u8 iftype)
+ {
++ const struct ieee80211_sband_iftype_data *data;
+ int i;
+
+ if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
+@@ -570,10 +622,7 @@ ieee80211_get_sband_iftype_data(const st
+ if (iftype == NL80211_IFTYPE_AP_VLAN)
+ iftype = NL80211_IFTYPE_AP;
+
+- for (i = 0; i < sband->n_iftype_data; i++) {
+- const struct ieee80211_sband_iftype_data *data =
+- &sband->iftype_data[i];
+-
++ for_each_sband_iftype_data(sband, i, data) {
+ if (data->types_mask & BIT(iftype))
+ return data;
+ }
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -1055,6 +1055,7 @@ int ieee80211_register_hw(struct ieee802
+ supp_he = false;
+ supp_eht = false;
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ const struct ieee80211_sband_iftype_data *iftd;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[band];
+@@ -1101,11 +1102,7 @@ int ieee80211_register_hw(struct ieee802
+ supp_ht = supp_ht || sband->ht_cap.ht_supported;
+ supp_vht = supp_vht || sband->vht_cap.vht_supported;
+
+- for (i = 0; i < sband->n_iftype_data; i++) {
+- const struct ieee80211_sband_iftype_data *iftd;
+-
+- iftd = &sband->iftype_data[i];
+-
++ for_each_sband_iftype_data(sband, i, iftd) {
+ supp_he = supp_he || iftd->he_cap.has_he;
+ supp_eht = supp_eht || iftd->eht_cap.has_eht;
+ }
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -6,7 +6,7 @@
+ *
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+- * Copyright 2018-2022 Intel Corporation
++ * Copyright 2018-2023 Intel Corporation
+ */
+
+ #include <linux/export.h>
+@@ -1162,8 +1162,7 @@ bool cfg80211_chandef_usable(struct wiph
+ if (!sband)
+ return false;
+
+- for (i = 0; i < sband->n_iftype_data; i++) {
+- iftd = &sband->iftype_data[i];
++ for_each_sband_iftype_data(sband, i, iftd) {
+ if (!iftd->eht_cap.has_eht)
+ continue;
+
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -5,7 +5,7 @@
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2015-2017 Intel Deutschland GmbH
+- * Copyright (C) 2018-2022 Intel Corporation
++ * Copyright (C) 2018-2023 Intel Corporation
+ */
+
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -817,6 +817,7 @@ int wiphy_register(struct wiphy *wiphy)
+
+ /* sanity check supported bands/channels */
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ const struct ieee80211_sband_iftype_data *iftd;
+ u16 types = 0;
+ bool have_he = false;
+
+@@ -873,14 +874,11 @@ int wiphy_register(struct wiphy *wiphy)
+ return -EINVAL;
+ }
+
+- for (i = 0; i < sband->n_iftype_data; i++) {
+- const struct ieee80211_sband_iftype_data *iftd;
++ for_each_sband_iftype_data(sband, i, iftd) {
+ bool has_ap, has_non_ap;
+ u32 ap_bits = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+
+- iftd = &sband->iftype_data[i];
+-
+ if (WARN_ON(!iftd->types_mask))
+ return -EINVAL;
+ if (WARN_ON(types & iftd->types_mask))
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1906,20 +1906,20 @@ static int nl80211_send_band_rateinfo(st
+ struct nlattr *nl_iftype_data =
+ nla_nest_start_noflag(msg,
+ NL80211_BAND_ATTR_IFTYPE_DATA);
++ const struct ieee80211_sband_iftype_data *iftd;
+ int err;
+
+ if (!nl_iftype_data)
+ return -ENOBUFS;
+
+- for (i = 0; i < sband->n_iftype_data; i++) {
++ for_each_sband_iftype_data(sband, i, iftd) {
+ struct nlattr *iftdata;
+
+ iftdata = nla_nest_start_noflag(msg, i + 1);
+ if (!iftdata)
+ return -ENOBUFS;
+
+- err = nl80211_send_iftype_data(msg, sband,
+- &sband->iftype_data[i]);
++ err = nl80211_send_iftype_data(msg, sband, iftd);
+ if (err)
+ return err;
+