From: Kavita Kavita Date: Mon, 20 Apr 2026 09:08:56 +0000 (+0530) Subject: wifi: mac80211_hwsim: Add support for extended FTM ranging X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3acaadfe91a3c7afb52b2eb7f7995767b819a47e;p=thirdparty%2Flinux.git wifi: mac80211_hwsim: Add support for extended FTM ranging Introduce support for continuous ranging and advanced timing parameters in the FTM request, response, and capability paths. This enables more flexible ranging scenarios with improved control over measurement timing and session management. Co-developed-by: Peddolla Harshavardhan Reddy Signed-off-by: Peddolla Harshavardhan Reddy Signed-off-by: Kavita Kavita Link: https://patch.msgid.link/20260420090856.2152905-14-peddolla.reddy@oss.qualcomm.com Signed-off-by: Johannes Berg --- diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c index e510357c1411..3a0c4366dfdb 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c @@ -746,6 +746,17 @@ hwsim_ftm_result_policy[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1] = { [NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD] = { .type = NLA_U64 }, [NL80211_PMSR_FTM_RESP_ATTR_LCI] = { .type = NLA_STRING }, [NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_STRING }, + [NL80211_PMSR_FTM_RESP_ATTR_TX_LTF_REPETITION_COUNT] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_RX_LTF_REPETITION_COUNT] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_NUM_TX_SPATIAL_STREAMS] = { .type = NLA_U8 }, + [NL80211_PMSR_FTM_RESP_ATTR_NUM_RX_SPATIAL_STREAMS] = { .type = NLA_U8 }, + [NL80211_PMSR_FTM_RESP_ATTR_NOMINAL_TIME] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_AVAILABILITY_WINDOW] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_PREAMBLE] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_RESP_ATTR_IS_DELAYED_LMR] = { .type = NLA_FLAG }, }; static const struct nla_policy @@ -779,6 +790,19 @@ hwsim_pmsr_peers_result_policy[NL80211_PMSR_ATTR_MAX + 1] = { [NL80211_PMSR_ATTR_PEERS] = NLA_POLICY_NESTED_ARRAY(hwsim_pmsr_peer_result_policy), }; +static const struct nla_policy +hwsim_ftm_role_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { + [NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_NTB] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_TB] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_EDCA] = { .type = NLA_FLAG }, +}; + +static const struct nla_policy +hwsim_ftm_type_capa_policy[NL80211_PMSR_FTM_TYPE_CAPA_ATTR_MAX + 1] = { + [NL80211_PMSR_FTM_TYPE_CAPA_ATTR_INFRA_SUPPORT] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_TYPE_CAPA_ATTR_PD_SUPPORT] = { .type = NLA_FLAG }, +}; + static const struct nla_policy hwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { [NL80211_PMSR_FTM_CAPA_ATTR_ASAP] = { .type = NLA_FLAG }, @@ -791,6 +815,19 @@ hwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { [NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST] = NLA_POLICY_MAX(NLA_U8, 31), [NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG }, [NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, + [NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_TX_ANTENNAS] = { .type = NLA_U8 }, + [NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_RX_ANTENNAS] = { .type = NLA_U8 }, + [NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_EDCA] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_NTB] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_CAPA_ATTR_PD_PREAMBLES] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_CAPA_ATTR_PD_BANDWIDTHS] = { .type = NLA_U32 }, + [NL80211_PMSR_FTM_CAPA_ATTR_ISTA_CAPS] = + NLA_POLICY_NESTED(hwsim_ftm_role_capa_policy), + [NL80211_PMSR_FTM_CAPA_ATTR_RSTA_CAPS] = + NLA_POLICY_NESTED(hwsim_ftm_role_capa_policy), + [NL80211_PMSR_FTM_CAPA_ATTR_TYPE_CAPS] = + NLA_POLICY_NESTED(hwsim_ftm_type_capa_policy), + [NL80211_PMSR_FTM_CAPA_ATTR_CONCURRENT_ISTA_RSTA_SUPPORT] = { .type = NLA_FLAG }, }; static const struct nla_policy @@ -3527,6 +3564,47 @@ static int mac80211_hwsim_send_pmsr_ftm_request_peer(struct sk_buff *msg, if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, request->bss_color)) return -ENOBUFS; + if (request->min_time_between_measurements && + nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS, + request->min_time_between_measurements)) + return -ENOBUFS; + + if (request->max_time_between_measurements && + nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS, + request->max_time_between_measurements)) + return -ENOBUFS; + + if (request->availability_window && + nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_AW_DURATION, + request->availability_window)) + return -ENOBUFS; + + if (request->nominal_time && + nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_NOMINAL_TIME, + request->nominal_time)) + return -ENOBUFS; + + if (request->num_measurements && + nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_MEASUREMENTS, + request->num_measurements)) + return -ENOBUFS; + + if (request->ingress_distance && + nla_put_u64_64bit(msg, NL80211_PMSR_FTM_REQ_ATTR_INGRESS, + request->ingress_distance, + NL80211_PMSR_FTM_REQ_ATTR_PAD)) + return -ENOBUFS; + + if (request->egress_distance && + nla_put_u64_64bit(msg, NL80211_PMSR_FTM_REQ_ATTR_EGRESS, + request->egress_distance, + NL80211_PMSR_FTM_REQ_ATTR_PAD)) + return -ENOBUFS; + + if (request->pd_suppress_range_results && + nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_PD_SUPPRESS_RESULTS)) + return -ENOBUFS; + nla_nest_end(msg, ftm); return 0; @@ -3896,6 +3974,69 @@ static int mac80211_hwsim_parse_ftm_result(struct nlattr *ftm, result->civicloc_len = nla_len(tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]); } + if (tb[NL80211_PMSR_FTM_RESP_ATTR_TX_LTF_REPETITION_COUNT]) { + result->tx_ltf_repetition_count_valid = 1; + result->tx_ltf_repetition_count = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_TX_LTF_REPETITION_COUNT]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_RX_LTF_REPETITION_COUNT]) { + result->rx_ltf_repetition_count_valid = 1; + result->rx_ltf_repetition_count = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_RX_LTF_REPETITION_COUNT]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS]) { + result->max_time_between_measurements_valid = 1; + result->max_time_between_measurements = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_MAX_TIME_BETWEEN_MEASUREMENTS]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS]) { + result->min_time_between_measurements_valid = 1; + result->min_time_between_measurements = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_TX_SPATIAL_STREAMS]) { + result->num_tx_spatial_streams_valid = 1; + result->num_tx_spatial_streams = + nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_TX_SPATIAL_STREAMS]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_RX_SPATIAL_STREAMS]) { + result->num_rx_spatial_streams_valid = 1; + result->num_rx_spatial_streams = + nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_RX_SPATIAL_STREAMS]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_NOMINAL_TIME]) { + result->nominal_time_valid = 1; + result->nominal_time = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_NOMINAL_TIME]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_AVAILABILITY_WINDOW]) { + result->availability_window_valid = 1; + result->availability_window = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_AVAILABILITY_WINDOW]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_CHANNEL_WIDTH]) { + result->chan_width_valid = 1; + result->chan_width = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_CHANNEL_WIDTH]); + } + + if (tb[NL80211_PMSR_FTM_RESP_ATTR_PREAMBLE]) { + result->preamble_valid = 1; + result->preamble = + nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_PREAMBLE]); + } + + result->is_delayed_lmr = + nla_get_flag(tb[NL80211_PMSR_FTM_RESP_ATTR_IS_DELAYED_LMR]); + return 0; } @@ -6280,6 +6421,82 @@ static int parse_ftm_capa(const struct nlattr *ftm_capa, struct cfg80211_pmsr_ca out->ftm.trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED]; out->ftm.non_trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED]; + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_TX_ANTENNAS]) + out->ftm.max_no_of_tx_antennas = + nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_TX_ANTENNAS]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_RX_ANTENNAS]) + out->ftm.max_no_of_rx_antennas = + nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_RX_ANTENNAS]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_EDCA]) + out->ftm.min_allowed_ranging_interval_edca = + nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_EDCA]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_NTB]) + out->ftm.min_allowed_ranging_interval_ntb = + nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_NTB]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_PREAMBLES]) + out->ftm.pd_preambles = + nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_PREAMBLES]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_BANDWIDTHS]) + out->ftm.pd_bandwidths = + nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_BANDWIDTHS]); + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_ISTA_CAPS]) { + struct nlattr *ista_tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1]; + + if (!nla_parse_nested(ista_tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, + tb[NL80211_PMSR_FTM_CAPA_ATTR_ISTA_CAPS], + hwsim_ftm_role_capa_policy, NULL)) { + out->ftm.ista.support_ntb = + !!ista_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_NTB]; + out->ftm.ista.support_tb = + !!ista_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_TB]; + out->ftm.ista.support_edca = + !!ista_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_EDCA]; + if (ista_tb[NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE]) + out->ftm.ista.max_peers = + nla_get_u32(ista_tb[NL80211_PMSR_ATTR_MAX_PEER_ISTA_ROLE]); + } + } + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_RSTA_CAPS]) { + struct nlattr *rsta_tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1]; + + if (!nla_parse_nested(rsta_tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, + tb[NL80211_PMSR_FTM_CAPA_ATTR_RSTA_CAPS], + hwsim_ftm_role_capa_policy, NULL)) { + out->ftm.rsta.support_ntb = + !!rsta_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_NTB]; + out->ftm.rsta.support_tb = + !!rsta_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_TB]; + out->ftm.rsta.support_edca = + !!rsta_tb[NL80211_PMSR_FTM_CAPA_ATTR_SUPPORT_EDCA]; + if (rsta_tb[NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE]) + out->ftm.rsta.max_peers = + nla_get_u32(rsta_tb[NL80211_PMSR_ATTR_MAX_PEER_RSTA_ROLE]); + } + } + + if (tb[NL80211_PMSR_FTM_CAPA_ATTR_TYPE_CAPS]) { + struct nlattr *type_tb[NL80211_PMSR_FTM_TYPE_CAPA_ATTR_MAX + 1]; + + if (!nla_parse_nested(type_tb, NL80211_PMSR_FTM_TYPE_CAPA_ATTR_MAX, + tb[NL80211_PMSR_FTM_CAPA_ATTR_TYPE_CAPS], + hwsim_ftm_type_capa_policy, NULL)) { + out->ftm.type.infra_support = + !!type_tb[NL80211_PMSR_FTM_TYPE_CAPA_ATTR_INFRA_SUPPORT]; + out->ftm.type.pd_support = + !!type_tb[NL80211_PMSR_FTM_TYPE_CAPA_ATTR_PD_SUPPORT]; + } + } + + out->ftm.concurrent_ista_rsta_support = + !!tb[NL80211_PMSR_FTM_CAPA_ATTR_CONCURRENT_ISTA_RSTA_SUPPORT]; + return 0; }