]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: cfg80211: separately store HT, VHT and HE capabilities for NAN
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 18 Mar 2026 12:39:18 +0000 (14:39 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 25 Mar 2026 19:56:54 +0000 (20:56 +0100)
In NAN, unlike in other modes, there is only one set of (HT, VHT, HE)
capabilities that is used for all channels (and bands) used in the NAN
data path.

This set of capabilities will have to be a special one, for example - have
the minimum of (HT-for-5 GHz, HT-for-2.4 GHz), careful handling of the
bits that have a different meaning for each band, etc.

While we could use the exiting sband/iftype capabilities, and require
identical capabilities for all bands (makes no sense since this means
that we will have VHT capabilities in the 2.4 GHz slot),
or require that only one of the sbands will be set,
or have logic to extract the minimum and handle the conflicting bits -
it seems simpler to add a dedicated set of capabilities which is special
for NAN, and is band agnostic, to be populated by the driver.

That way we also let the driver decide how it wants to handle the
conflicting bits.

Add this special set of these capabilities to wiphy:nan_capabilities, to be
populated by the driver.
Send it to user space.

Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260219114327.4b6f3e4a81b4.I45422adc0df3ad4101d857a92e83f0de5cf241e1@changeid
Link: https://patch.msgid.link/20260318123926.206536-5-miriam.rachel.korenblit@intel.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/core.c
net/wireless/nl80211.c

index 1797ece502955d41a21b2590963f6effb0c457d8..60cd0fbe9a46ba01bc5c5bb2fb24d733f387d413 100644 (file)
@@ -5913,6 +5913,12 @@ enum wiphy_nan_flags {
  * @max_channel_switch_time: maximum channel switch time in milliseconds.
  * @dev_capabilities: NAN device capabilities as defined in Wi-Fi Aware (TM)
  *     specification Table 79 (Capabilities field).
+ * @phy: Band-agnostic capabilities for NAN data interfaces. Since NAN
+ *     operates on multiple channels simultaneously, these capabilities apply
+ *     across all bands. Valid only if NL80211_IFTYPE_NAN_DATA is supported.
+ * @phy.ht: HT capabilities (mandatory for NAN data)
+ * @phy.vht: VHT capabilities (optional)
+ * @phy.he: HE capabilities (optional)
  */
 struct wiphy_nan_capa {
        u32 flags;
@@ -5920,6 +5926,11 @@ struct wiphy_nan_capa {
        u8 n_antennas;
        u16 max_channel_switch_time;
        u8 dev_capabilities;
+       struct {
+               struct ieee80211_sta_ht_cap ht;
+               struct ieee80211_sta_vht_cap vht;
+               struct ieee80211_sta_he_cap he;
+       } phy;
 };
 
 #define CFG80211_HW_TIMESTAMP_ALL_PEERS        0xffff
index 3984c176f9e763417e14a3838ae61e7dd0c59eeb..c94e957a3467cf4c1c15efe8bb6341b0c52e9fb2 100644 (file)
@@ -4462,6 +4462,46 @@ enum nl80211_band_attr {
 
 #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
 
+/**
+ * enum nl80211_nan_phy_cap_attr - NAN PHY capabilities attributes
+ * @__NL80211_NAN_PHY_CAP_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET: 16-byte attribute containing HT MCS set
+ * @NL80211_NAN_PHY_CAP_ATTR_HT_CAPA: HT capabilities (u16)
+ * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR: HT A-MPDU factor (u8)
+ * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY: HT A-MPDU density (u8)
+ * @NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET: 8-byte attribute containing VHT MCS set
+ * @NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA: VHT capabilities (u32)
+ * @NL80211_NAN_PHY_CAP_ATTR_HE_MAC: HE MAC capabilities
+ * @NL80211_NAN_PHY_CAP_ATTR_HE_PHY: HE PHY capabilities
+ * @NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET: HE supported NSS/MCS combinations
+ * @NL80211_NAN_PHY_CAP_ATTR_HE_PPE: HE PPE thresholds
+ * @NL80211_NAN_PHY_CAP_ATTR_MAX: highest NAN PHY cap attribute number
+ * @__NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_nan_phy_cap_attr {
+       __NL80211_NAN_PHY_CAP_ATTR_INVALID,
+
+       /* HT capabilities */
+       NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET,
+       NL80211_NAN_PHY_CAP_ATTR_HT_CAPA,
+       NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR,
+       NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY,
+
+       /* VHT capabilities */
+       NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET,
+       NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA,
+
+       /* HE capabilities */
+       NL80211_NAN_PHY_CAP_ATTR_HE_MAC,
+       NL80211_NAN_PHY_CAP_ATTR_HE_PHY,
+       NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET,
+       NL80211_NAN_PHY_CAP_ATTR_HE_PPE,
+
+       /* keep last */
+       __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST,
+       NL80211_NAN_PHY_CAP_ATTR_MAX = __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST - 1
+};
+
 /**
  * enum nl80211_wmm_rule - regulatory wmm rule
  *
@@ -8635,6 +8675,8 @@ enum nl80211_s1g_short_beacon_attrs {
  * @NL80211_NAN_CAPA_CAPABILITIES: u8 attribute containing the
  *     capabilities of the device as defined in Wi-Fi Aware (TM)
  *     specification Table 79 (Capabilities field).
+ * @NL80211_NAN_CAPA_PHY: nested attribute containing band-agnostic
+ *     capabilities for NAN data path. See &enum nl80211_nan_phy_cap_attr.
  * @__NL80211_NAN_CAPABILITIES_LAST: Internal
  * @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute.
  */
@@ -8647,6 +8689,7 @@ enum nl80211_nan_capabilities {
        NL80211_NAN_CAPA_NUM_ANTENNAS,
        NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME,
        NL80211_NAN_CAPA_CAPABILITIES,
+       NL80211_NAN_CAPA_PHY,
        /* keep last */
        __NL80211_NAN_CAPABILITIES_LAST,
        NL80211_NAN_CAPABILITIES_MAX = __NL80211_NAN_CAPABILITIES_LAST - 1,
index 200b97f912eb21aefe9d2626311000bbb370a410..6783e0672dcb711a42fc47d483653ff01bb62ef5 100644 (file)
@@ -835,6 +835,10 @@ int wiphy_register(struct wiphy *wiphy)
                     !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ)))))
                return -EINVAL;
 
+       if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN_DATA)) &&
+                   !wiphy->nan_capa.phy.ht.ht_supported))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)))
                return -EINVAL;
 
index 7cea8fef6ae52ab83974e77bb65e8b026900600b..a9a829613b7b7876e9562639f3bea10409102aa1 100644 (file)
@@ -2721,6 +2721,68 @@ fail:
        return -ENOBUFS;
 }
 
+static int nl80211_put_nan_phy_cap(struct wiphy *wiphy, struct sk_buff *msg)
+{
+       struct nlattr *nl_phy_cap;
+       const struct ieee80211_sta_ht_cap *ht_cap;
+       const struct ieee80211_sta_vht_cap *vht_cap;
+       const struct ieee80211_sta_he_cap *he_cap;
+
+       if (!cfg80211_iftype_allowed(wiphy, NL80211_IFTYPE_NAN_DATA, false, 0))
+               return 0;
+
+       ht_cap = &wiphy->nan_capa.phy.ht;
+       vht_cap = &wiphy->nan_capa.phy.vht;
+       he_cap = &wiphy->nan_capa.phy.he;
+
+       /* HT is mandatory */
+       if (WARN_ON(!ht_cap->ht_supported))
+               return 0;
+
+       nl_phy_cap = nla_nest_start_noflag(msg, NL80211_NAN_CAPA_PHY);
+       if (!nl_phy_cap)
+               return -ENOBUFS;
+
+       if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET,
+                   sizeof(ht_cap->mcs), &ht_cap->mcs) ||
+           nla_put_u16(msg, NL80211_NAN_PHY_CAP_ATTR_HT_CAPA, ht_cap->cap) ||
+           nla_put_u8(msg, NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR,
+                      ht_cap->ampdu_factor) ||
+           nla_put_u8(msg, NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY,
+                      ht_cap->ampdu_density))
+               goto fail;
+
+       if (vht_cap->vht_supported) {
+               if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET,
+                           sizeof(vht_cap->vht_mcs), &vht_cap->vht_mcs) ||
+                   nla_put_u32(msg, NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA,
+                               vht_cap->cap))
+                       goto fail;
+       }
+
+       if (he_cap->has_he) {
+               if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_MAC,
+                           sizeof(he_cap->he_cap_elem.mac_cap_info),
+                           he_cap->he_cap_elem.mac_cap_info) ||
+                   nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_PHY,
+                           sizeof(he_cap->he_cap_elem.phy_cap_info),
+                           he_cap->he_cap_elem.phy_cap_info) ||
+                   nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET,
+                           sizeof(he_cap->he_mcs_nss_supp),
+                           &he_cap->he_mcs_nss_supp) ||
+                   nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_PPE,
+                           sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
+                       goto fail;
+       }
+
+       nla_nest_end(msg, nl_phy_cap);
+       return 0;
+
+fail:
+       nla_nest_cancel(msg, nl_phy_cap);
+       return -ENOBUFS;
+}
+
 static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg)
 {
        struct nlattr *nan_caps;
@@ -2747,6 +2809,9 @@ static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg)
                       wiphy->nan_capa.dev_capabilities))
                goto fail;
 
+       if (nl80211_put_nan_phy_cap(wiphy, msg))
+               goto fail;
+
        nla_nest_end(msg, nan_caps);
 
        return 0;