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 --- include/net/cfg80211.h | 6 +++++ include/uapi/linux/nl80211.h | 14 +++++++++++ net/wireless/nl80211.c | 8 +++++++ net/wireless/pmsr.c | 46 ++++++++++++++++++++++++++++++++---- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4f1f66a137ae..8c82f33bfc40 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6000,6 +6000,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. @@ -6007,6 +6009,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 @@ -6061,11 +6065,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; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index cb55e8b69097..a42bae666d02 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -8054,6 +8054,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 @@ -8066,6 +8078,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, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3fb540c6adcf..4f6612311de3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2531,6 +2531,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); } @@ -2559,6 +2563,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); } diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c index caffa2421c20..432d34be7945 100644 --- a/net/wireless/pmsr.c +++ b/net/wireless/pmsr.c @@ -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; -- 2.34.1