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 <peddolla.reddy@oss.qualcomm.com>
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
Signed-off-by: Kavita Kavita <kavita.kavita@oss.qualcomm.com>
Link: https://patch.msgid.link/20260420090856.2152905-14-peddolla.reddy@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Kavita Kavita 2026-04-20 14:38:56 +05:30 committed by Johannes Berg
parent 4bb6e58bc2
commit 3acaadfe91

View File

@ -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;
}