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>
* 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.
* 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
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;
* 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
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,
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);
}
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);
}
{
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)
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;
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");
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;