wifi: cfg80211: add role-based peer limits to FTM capabilities

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>
This commit is contained in:
Peddolla Harshavardhan Reddy 2026-04-20 14:38:51 +05:30 committed by Johannes Berg
parent 4e901e99ed
commit ea996c2c03
4 changed files with 70 additions and 4 deletions

View 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;

View 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,

View 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);
}

View 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;