]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: cfg80211: add role-based peer limits to FTM capabilities
authorPeddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
Mon, 20 Apr 2026 09:08:51 +0000 (14:38 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 5 May 2026 11:43:18 +0000 (13:43 +0200)
Peer measurement capabilities currently advertise a single maximum
peer count regardless of device role. Some devices support different
peer limits when operating as initiator versus responder.

Add max_peers fields inside the ftm.ista and ftm.rsta sub-structs of
cfg80211_pmsr_capabilities to allow drivers to advertise per-role peer
limits. These limits are generic and not restricted to any specific
ranging type.

Expose these over nl80211 using new NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE
and NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE attributes inside the
ISTA_CAPS and RSTA_CAPS nested attributes respectively.

When a role limit is advertised, validate the number of peers in the
request separately for each role using the existing rsta flag in the
FTM request, and reject the request if the limit is exceeded.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
Link: https://patch.msgid.link/20260420090856.2152905-9-peddolla.reddy@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c
net/wireless/pmsr.c

index ad32353e87e054119853b20b0c08ae03cb279eec..5669948e0f3d5c048a542c0035b7472d78701ba9 100644 (file)
@@ -6003,6 +6003,8 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type);
  *     TB ranging.
  * @ftm.ista.support_edca: supports operating as ISTA in PMSR FTM request for
  *     EDCA based ranging.
+ * @ftm.ista.max_peers: maximum number of peers supported in the ISTA role.
+ *     If zero, no role-specific peer limit applies.
  * @ftm.rsta: responder role capabilities
  * @ftm.rsta.support_ntb: supports operating as RSTA in PMSR FTM request for
  *     NTB ranging.
@@ -6010,6 +6012,8 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type);
  *     TB ranging.
  * @ftm.rsta.support_edca: supports operating as RSTA in PMSR FTM request for
  *     EDCA based ranging.
+ * @ftm.rsta.max_peers: maximum number of peers supported in the RSTA role.
+ *     If zero, no role-specific peer limit applies.
  * @ftm.max_no_of_tx_antennas: maximum number of transmit antennas supported for
  *     EDCA based ranging (0 means unknown)
  * @ftm.max_no_of_rx_antennas: maximum number of receive antennas supported for
@@ -6064,11 +6068,13 @@ struct cfg80211_pmsr_capabilities {
                        u8 support_ntb:1,
                           support_tb:1,
                           support_edca:1;
+                       u32 max_peers;
                } ista;
                struct {
                        u8 support_ntb:1,
                           support_tb:1,
                           support_edca:1;
+                       u32 max_peers;
                } rsta;
                u8 max_no_of_tx_antennas;
                u8 max_no_of_rx_antennas;
index 08e8e4de650cd6c261fcc339ace4857914a3d0f2..e31ff2a745b216b5e489e5511f5ba2a399cfa372 100644 (file)
@@ -8065,6 +8065,18 @@ enum nl80211_peer_measurement_peer_attrs {
  *     meaningless, just a list of peers to measure with, with the
  *     sub-attributes taken from
  *     &enum nl80211_peer_measurement_peer_attrs.
+ * @NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE: u32 attribute indicating the
+ *     maximum number of peers supported when the device operates in the
+ *     ISTA (Initiator STA) role. If absent, no role-specific peer limit
+ *     applies. The sum of %NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE and
+ *     %NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE is enforced when the device
+ *     supports concurrent ISTA/RSTA operation.
+ * @NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE: u32 attribute indicating the
+ *     maximum number of peers supported when the device operates in the
+ *     RSTA (Responder STA) role. If absent, no role-specific peer limit
+ *     applies. The sum of %NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE and
+ *     %NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE is enforced when the device
+ *     supports concurrent ISTA/RSTA operation.
  *
  * @NUM_NL80211_PMSR_ATTR: internal
  * @NL80211_PMSR_ATTR_MAX: highest attribute number
@@ -8077,6 +8089,8 @@ enum nl80211_peer_measurement_attrs {
        NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR,
        NL80211_PMSR_ATTR_TYPE_CAPA,
        NL80211_PMSR_ATTR_PEERS,
+       NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE,
+       NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE,
 
        /* keep last */
        NUM_NL80211_PMSR_ATTR,
index 61ecf8fceb6af4c004708a2d2f51881903a1612e..0ffaa2cd780872db88149390073db4e1134b0589 100644 (file)
@@ -2532,6 +2532,10 @@ nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
                if (cap->ftm.ista.support_edca &&
                    nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_EDCA))
                        return -ENOBUFS;
+               if (cap->ftm.ista.max_peers &&
+                   nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE,
+                               cap->ftm.ista.max_peers))
+                       return -ENOBUFS;
                nla_nest_end(msg, ista_caps);
        }
 
@@ -2560,6 +2564,10 @@ nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
                if (cap->ftm.rsta.support_edca &&
                    nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_EDCA))
                        return -ENOBUFS;
+               if (cap->ftm.rsta.max_peers &&
+                   nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE,
+                               cap->ftm.rsta.max_peers))
+                       return -ENOBUFS;
                nla_nest_end(msg, rsta_caps);
        }
 
index caffa2421c20cd1035e04038041a7b8226ee8017..432d34be7945ea2f2715efbd00bbf2e3ac7da7e0 100644 (file)
@@ -361,12 +361,15 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS];
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       int count, rem, err, idx, peer_count;
        struct wireless_dev *wdev = info->user_ptr[1];
+       const struct cfg80211_pmsr_capabilities *capa;
        struct cfg80211_pmsr_request *req;
        struct nlattr *peers, *peer;
-       int count, rem, err, idx;
 
-       if (!rdev->wiphy.pmsr_capa)
+       capa = rdev->wiphy.pmsr_capa;
+
+       if (!capa)
                return -EOPNOTSUPP;
 
        if (!reqattr)
@@ -381,7 +384,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
        nla_for_each_nested(peer, peers, rem) {
                count++;
 
-               if (count > rdev->wiphy.pmsr_capa->max_peers) {
+               if (count > capa->max_peers) {
                        NL_SET_ERR_MSG_ATTR(info->extack, peer,
                                            "Too many peers used");
                        return -EINVAL;
@@ -397,7 +400,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
                req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]);
 
        if (info->attrs[NL80211_ATTR_MAC]) {
-               if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) {
+               if (!capa->randomize_mac_addr) {
                        NL_SET_ERR_MSG_ATTR(info->extack,
                                            info->attrs[NL80211_ATTR_MAC],
                                            "device cannot randomize MAC address");
@@ -422,6 +425,41 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
                        goto out_err;
                idx++;
        }
+
+       /* Validate per-role peer limits if advertised */
+       if (capa->ftm.ista.max_peers) {
+               peer_count = 0;
+
+               for (idx = 0; idx < req->n_peers; idx++) {
+                       if (!req->peers[idx].ftm.rsta) {
+                               peer_count++;
+
+                               if (peer_count > capa->ftm.ista.max_peers) {
+                                       NL_SET_ERR_MSG(info->extack,
+                                                      "Too many ISTA peers for device limit");
+                                       err = -EINVAL;
+                                       goto out_err;
+                               }
+                       }
+               }
+       }
+
+       if (capa->ftm.rsta.max_peers) {
+               peer_count = 0;
+
+               for (idx = 0; idx < req->n_peers; idx++) {
+                       if (req->peers[idx].ftm.rsta) {
+                               peer_count++;
+
+                               if (peer_count > capa->ftm.rsta.max_peers) {
+                                       NL_SET_ERR_MSG(info->extack,
+                                                      "Too many RSTA peers for device limit");
+                                       err = -EINVAL;
+                                       goto out_err;
+                               }
+                       }
+               }
+       }
        req->cookie = cfg80211_assign_cookie(rdev);
        req->nl_portid = info->snd_portid;