summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h11
-rw-r--r--include/uapi/linux/nl80211.h43
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/nl80211.c65
4 files changed, 123 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1797ece50295..60cd0fbe9a46 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -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
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 3984c176f9e7..c94e957a3467 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4463,6 +4463,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
*
* @__NL80211_WMMR_INVALID: attribute number 0 is reserved
@@ -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,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 200b97f912eb..6783e0672dcb 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -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;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7cea8fef6ae5..a9a829613b7b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -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;