diff options
author | Jaewan Kim <jaewan@google.com> | 2022-10-27 11:02:57 +0900 |
---|---|---|
committer | Jaewan Kim <jaewan@google.com> | 2022-11-29 20:27:25 +0900 |
commit | f48ef133534df0354ea357bbfd24f8ed51d07235 (patch) | |
tree | 1258bcf1736f445971dd898a48774d0d52df74b5 | |
parent | 0ffa311c79645863beb9a1a15268e9cbf4f36cba (diff) | |
download | wmediumd-f48ef133534df0354ea357bbfd24f8ed51d07235.tar.gz |
Add RTT support
This CL adds PMSR (peer measurement) support,
which is generic measurement between peers.
And also adds its one and only mearsurement type - RTT (Round Trip Time).
Bug: 237448302
Test: Following script works as expected &&
$ wmediumd_control -- set_position 42:00:00:00:00:00 10 0 &&
$ wmediumd_control set_lci 42:00:00:00:00:00 "11' 22' 33'" &&
$ wmediumd_control set_civicloc 42:00:00:00:00:00 "Google, CA, USA" &&
$ wmediumd_control -- set_position 42:00:00:00:01:00 -50 0 &&
$ CONFIG_FILE="/sdcard/Download/ftmcfg" &&
$ adb shell "rm ${CONFIG_FILE}" &&
$ adb shell "echo \"42:00:00:00:00:00 bw=40|80 retries=10 preamble=legacy lci cf=2412 bursts_exp=2 retries=1 ftms_per_burst=5\" >> ${CONFIG_FILE}" &&
$ adb shell "echo \"42:00:00:00:01:00 bw=40|80 retries=10 preamble=legacy lci cf=2412 bursts_exp=2 retries=1 ftms_per_burst=5\" >> ${CONFIG_FILE}" &&
$ adb shell "echo \"aa:00:00:00:00:00 bw=40|80 retries=10 preamble=legacy lci cf=2412 bursts_exp=2 retries=1 ftms_per_burst=5\" >> ${CONFIG_FILE}" &&
$ adb shell "iw dev wlan0 measurement ftm_request ${CONFIG_FILE}"
Change-Id: I962a2a8de6cb8c47c45480c130a054d12771d418
-rw-r--r-- | wmediumd/pmsr.c | 221 | ||||
-rw-r--r-- | wmediumd/pmsr.h | 84 | ||||
-rw-r--r-- | wmediumd/wmediumd.c | 258 | ||||
-rw-r--r-- | wmediumd/wmediumd.h | 21 |
4 files changed, 583 insertions, 1 deletions
diff --git a/wmediumd/pmsr.c b/wmediumd/pmsr.c new file mode 100644 index 0000000..7484500 --- /dev/null +++ b/wmediumd/pmsr.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 The Android Open Source Project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "pmsr.h" + +#include <errno.h> +#include <stdio.h> + +static int parse_pmsr_request_ftm(struct nlattr *req, + struct pmsr_request_ftm *out) +{ + struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1]; + + nla_parse_nested(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, req, NULL); + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) + out->preamble = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]); + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]) + out->burst_period = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]); + + out->asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP]; + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]) + out->num_bursts_exp = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]); + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) + out->burst_duration = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]) + out->ftms_per_burst = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]); + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]) + out->ftmr_retries = + nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]); + + out->request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI]; + + out->request_civicloc = + !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC]; + + out->trigger_based = + !!tb[NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED]; + + out->non_trigger_based = + !!tb[NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED]; + + out->lmr_feedback = + !!tb[NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK]; + + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR]) + out->bss_color = + nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR]); + + return 0; +} + +int parse_pmsr_channel(struct nlattr *req, + struct pmsr_channel *out) +{ + struct nlattr *nla; + int rem; + + if (!req) + return -EINVAL; + + nla_for_each_attr(nla, req, nla_len(req), rem) { + switch (nla_type(nla)) { + case NL80211_ATTR_WIPHY_FREQ: + out->center_freq = nla_get_u32(nla); + break; + case NL80211_ATTR_WIPHY_FREQ_OFFSET: + out->freq_offset = nla_get_u32(nla); + break; + case NL80211_ATTR_WIPHY_CHANNEL_TYPE: + out->channel_type = nla_get_u32(nla); + break; + case NL80211_ATTR_CHANNEL_WIDTH: + out->width = nla_get_u32(nla); + break; + case NL80211_ATTR_CENTER_FREQ1: + out->center_freq1 = nla_get_u32(nla); + break; + case NL80211_ATTR_CENTER_FREQ2: + out->center_freq2 = nla_get_u32(nla); + break; + default: + printf("%s: unknown attributes\n", __func__); + } + } + + return 0; +} + +static int parse_pmsr_request_peer(struct nlattr *req, + struct pmsr_request_peer *out) +{ + struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; + struct nlattr *tb_req[NL80211_PMSR_REQ_ATTR_MAX + 1]; + struct nlattr *nla; + int err, rem; + + if (!req) + return EINVAL; + + err = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, + req, NULL); + if (err) { + printf("%s: Failed to parse PMSR peer\n", __func__); + return err; + } + + if (!tb[NL80211_PMSR_PEER_ATTR_ADDR]) { + printf("%s: Failed to parse PMSR peer. Missing peer address\n", __func__); + return -EINVAL; + } + + memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN); + + err = parse_pmsr_channel(tb[NL80211_PMSR_PEER_ATTR_CHAN], + &out->channel); + if (err) + return err; + + err = nla_parse_nested(tb_req, NL80211_PMSR_REQ_ATTR_MAX, + tb[NL80211_PMSR_PEER_ATTR_REQ], NULL); + if (err) + return err; + + if (tb_req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF]) + out->report_ap_tsf = true; + + if (!tb_req[NL80211_PMSR_REQ_ATTR_DATA]) { + printf("%s: missing NL80211_PMSR_REQ_ATTR_DATA\n", __func__); + return -EINVAL; + } + + nla_for_each_nested(nla, tb_req[NL80211_PMSR_REQ_ATTR_DATA], rem) { + switch (nla_type(nla)) { + case NL80211_PMSR_TYPE_FTM: + err = parse_pmsr_request_ftm(nla, &out->ftm); + if (err) + return err; + break; + default: + printf("%s: unsupported measurement type\n", __func__); + return -EINVAL; + } + } + + return 0; +} + +int parse_pmsr_request(struct nlattr *req, + struct pmsr_request *out) +{ + struct nlattr *nla; + struct pmsr_request_peer *peer, *tmp; + int rem; + int err = 0; + + if (!req) + return -EINVAL; + + INIT_LIST_HEAD(&out->peers); + out->n_peers = 0; + + req = nla_find(nla_data(req), nla_len(req), NL80211_ATTR_PEER_MEASUREMENTS); + + nla_for_each_nested(nla, req, rem) { + switch (nla_type(nla)) { + case NL80211_ATTR_TIMEOUT: + out->timeout = nla_get_u32(nla); + break; + case NL80211_ATTR_MAC: + memcpy(out->mac_addr, nla_data(nla), ETH_ALEN); + break; + case NL80211_ATTR_MAC_MASK: + memcpy(out->mac_addr_mask, nla_data(nla), ETH_ALEN); + break; + case NL80211_PMSR_ATTR_PEERS: + peer = calloc(1, sizeof(struct pmsr_request_peer)); + list_add(&peer->list, &out->peers); + err = parse_pmsr_request_peer(nla, peer); + if (err) + goto out_err; + out->n_peers++; + break; + } + } + +out_err: + if (err) + list_for_each_entry_safe(peer, tmp, &out->peers, list) { + list_del(&peer->list); + free(peer); + } + return err; +} + diff --git a/wmediumd/pmsr.h b/wmediumd/pmsr.h new file mode 100644 index 0000000..74d6a68 --- /dev/null +++ b/wmediumd/pmsr.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 The Android Open Source Project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef PMSR_H_ +#define PMSR_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <netlink/attr.h> +#include <linux/nl80211.h> + +#include "ieee80211.h" +#include "list.h" + +struct pmsr_channel { + uint32_t center_freq; + uint32_t freq_offset; + enum nl80211_channel_type channel_type; + enum nl80211_chan_width width; + uint32_t center_freq1; + uint32_t center_freq2; +}; + +struct pmsr_request_ftm { + enum nl80211_preamble preamble; + uint32_t burst_period; + uint8_t asap:1, + request_lci:1, + request_civicloc:1, + trigger_based:1, + non_trigger_based:1, + lmr_feedback:1; + uint8_t num_bursts_exp; + uint8_t burst_duration; + uint8_t ftms_per_burst; + uint8_t ftmr_retries; + uint8_t bss_color; +}; + +struct pmsr_request_peer { + struct list_head list; + + uint8_t addr[ETH_ALEN]; + struct pmsr_channel channel; + uint8_t report_ap_tsf:1; + struct pmsr_request_ftm ftm; +}; + +struct pmsr_request { + uint32_t timeout; + + uint8_t mac_addr[ETH_ALEN]; + uint8_t mac_addr_mask[ETH_ALEN]; + + uint32_t n_peers; + + // keeps pmsr_request_peer + struct list_head peers; +}; + +/* + * Parse pmsr request. + * + * Caller has responsibility to release peers in returned pmsr_request. + */ +int parse_pmsr_request(struct nlattr *req, struct pmsr_request *out); + +#endif /* PMSR_H_ */ diff --git a/wmediumd/wmediumd.c b/wmediumd/wmediumd.c index a935f03..5fcf33e 100644 --- a/wmediumd/wmediumd.c +++ b/wmediumd/wmediumd.c @@ -31,9 +31,11 @@ #include <getopt.h> #include <signal.h> #include <math.h> +#include <sys/syslog.h> #include <sys/timerfd.h> #include <errno.h> #include <limits.h> +#include <time.h> #include <unistd.h> #include <stdarg.h> #include <endian.h> @@ -47,6 +49,7 @@ #include "ieee80211.h" #include "config.h" #include "api.h" +#include "pmsr.h" USFSTL_SCHEDULER(scheduler); @@ -80,6 +83,37 @@ static inline int div_round(int a, int b) return (a + b - 1) / b; } +static inline u64 sec_to_ns(time_t sec) +{ + return sec * 1000 * 1000 * 1000; +} + +static inline u64 ns_to_us(u64 ns) +{ + return ns / 1000L; +} + +static inline u64 ts_to_ns(struct timespec ts) +{ + return sec_to_ns(ts.tv_sec) + ts.tv_nsec; +} + +static inline double distance_to_rtt(double distance) +{ + const long light_speed = 299792458L; + return distance / light_speed; +} + +static inline double sec_to_ps(double sec) +{ + return sec * 1000 * 1000 * 1000; +} + +static inline double meter_to_mm(double meter) +{ + return meter * 1000; +} + static inline int pkt_duration(int len, int rate) { /* preamble + signal + t_sym * n_sym, rate in 100 kbps */ @@ -159,7 +193,6 @@ static inline bool frame_is_probe_req(struct frame *frame) (FTYPE_MGMT | STYPE_PROBE_REQ); } - static inline bool frame_has_zero_rates(const struct frame *frame) { for (int i = 0; i < frame->tx_rates_count; i++) { @@ -901,6 +934,222 @@ int nl_err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg) return NL_SKIP; } +static int send_pmsr_result_ftm(struct nl_msg *msg, + struct pmsr_request_ftm *req, + struct wmediumd *ctx, + struct station *sender, + struct station *receiver) +{ + struct nlattr *ftm; + int err; + + ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); + if (!ftm) + return -ENOMEM; + + if (!receiver) { + err = nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, + NL80211_PMSR_FTM_FAILURE_NO_RESPONSE); + goto out; + } + + double distance = + sqrt(pow(sender->x - receiver->x, 2) + pow(sender->y - receiver->y, 2)); + double distance_in_mm = meter_to_mm(distance); + double rtt_in_ps = sec_to_ps(distance_to_rtt(distance)); + if (distance_in_mm > UINT64_MAX || rtt_in_ps > UINT64_MAX) { + w_logf(ctx, LOG_WARNING, + "%s: Devices are too far away", __func__); + return nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, + NL80211_PMSR_FTM_FAILURE_NO_RESPONSE); + } + + int rssi = receiver->tx_power - + ctx->calc_path_loss(NULL, sender, receiver); + + if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS, + req->ftmr_retries) || + nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES, + req->ftmr_retries) || + nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP, + req->num_bursts_exp) || + nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION, + req->burst_duration) || + nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST, + req->ftms_per_burst) || + nla_put_s32(msg, NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG, rssi) || + nla_put_s32(msg, NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD, 0) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG, + (uint64_t)rtt_in_ps) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE, 0) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD, 0) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG, + (uint64_t)distance_in_mm) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE, 0) || + nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD, 0)) { + w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__); + return -ENOMEM; + } + +out: + if (ftm) + nla_nest_end(msg, ftm); + + return 0; +} + +static int send_pmsr_result_peer(struct nl_msg *msg, + struct pmsr_request_peer *req, + struct wmediumd *ctx, + struct station *sender) +{ + struct nlattr *peer, *resp, *data; + struct station *receiver; + int status; + struct timespec ts; + u64 host_time_ns; + u64 ap_tsf_us; + int err; + + peer = nla_nest_start(msg, 1); + if (!peer) + return -ENOMEM; + + receiver = get_station_by_addr(ctx, req->addr); + if (receiver) + status = NL80211_PMSR_STATUS_SUCCESS; + else { + w_logf(ctx, LOG_WARNING, "%s: unknown pmsr target " MAC_FMT "\n", + __func__, MAC_ARGS(req->addr)); + status = NL80211_PMSR_STATUS_FAILURE; + } + + if (clock_gettime(CLOCK_BOOTTIME, &ts)) { + w_logf(ctx, LOG_ERR, "%s: clock_gettime() failed\n", __func__); + return -EINVAL; + } + + host_time_ns = ts_to_ns(ts); + ap_tsf_us = ns_to_us(ts_to_ns(ts)); + + err = nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, req->addr); + if (err) + return err; + + resp = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_RESP); + if (!resp) + return -ENOMEM; + + if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, status) || + nla_put_u64(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME, host_time_ns) || + nla_put_u64(msg, NL80211_PMSR_RESP_ATTR_AP_TSF, ap_tsf_us) || + nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL)) { + w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__); + return -ENOMEM; + } + + data = nla_nest_start(msg, NL80211_PMSR_RESP_ATTR_DATA); + if (!data) + return -ENOMEM; + + err = send_pmsr_result_ftm(msg, &req->ftm, ctx, sender, receiver); + + nla_nest_end(msg, data); + nla_nest_end(msg, resp); + nla_nest_end(msg, peer); + + return err; +} + +static void send_pmsr_result(struct pmsr_request* request, struct wmediumd *ctx, + struct station *sender, struct client *client) +{ + struct nl_msg *msg; + struct nlattr *pmsr, *peers; + struct pmsr_request_peer *peer; + int cnt; + int err; + + msg = nlmsg_alloc(); + if (!msg) { + w_logf(ctx, LOG_ERR, "%s: nlmsg_alloc failed\n", __func__); + return; + } + + if (!genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id, + 0, NLM_F_REQUEST, HWSIM_CMD_REPORT_PMSR, VERSION_NR)) { + w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__); + goto out; + } + + err = nla_put(msg, HWSIM_ATTR_ADDR_TRANSMITTER, + ETH_ALEN, sender->hwaddr); + + pmsr = nla_nest_start(msg, HWSIM_ATTR_PMSR_RESULT); + if (!pmsr) + goto out; + + peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); + if (!peers) + goto out; + + list_for_each_entry(peer, &request->peers, list) { + err = send_pmsr_result_peer(msg, peer, ctx, sender); + if (err) { + w_logf(ctx, LOG_ERR, + "%s: Failed to send pmsr result from " MAC_FMT \ + " to " MAC_FMT ". Stopping\n", __func__, + MAC_ARGS(sender->addr), + MAC_ARGS(peer->addr)); + break; + } + } + + nla_nest_end(msg, peers); + nla_nest_end(msg, pmsr); + + wmediumd_send_to_client(ctx, client, msg); + +out: + nlmsg_free(msg); +} + +static void process_start_pmsr(struct nlattr *attrs[], struct wmediumd *ctx, + struct client *client) +{ + u8 *hwaddr; + struct station *sender; + + struct pmsr_request request; + struct pmsr_request_peer *peer, *tmp; + int err; + + if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) { + w_logf(ctx, LOG_ERR, "%s: Missing sender information\n", + __func__); + } + + hwaddr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); + sender = get_station_by_addr(ctx, hwaddr); + if (!sender) { + w_logf(ctx, LOG_ERR, "%s: Unknown sender " MAC_FMT "\n", + __func__, MAC_ARGS(hwaddr)); + return; + } + + err = parse_pmsr_request(attrs[HWSIM_ATTR_PMSR_REQUEST], &request); + if (err) + goto out; + + send_pmsr_result(&request, ctx, sender, client); + +out: + list_for_each_entry_safe(peer, tmp, &request.peers, list) { + list_del(&peer->list); + free(peer); + } +} + /* * Handle events from the kernel. Process CMD_FRAME events and queue them * for later delivery with the scheduler. @@ -1028,6 +1277,13 @@ static void _process_messages(struct nl_msg *msg, break; } break; + case HWSIM_CMD_START_PMSR: + process_start_pmsr(attrs, ctx, client); + break; + + case HWSIM_CMD_ABORT_PMSR: + // Do nothing. Too late to abort any PMSR. + break; } } diff --git a/wmediumd/wmediumd.h b/wmediumd/wmediumd.h index 111c879..c5459bc 100644 --- a/wmediumd/wmediumd.h +++ b/wmediumd/wmediumd.h @@ -39,6 +39,9 @@ enum { HWSIM_CMD_GET_RADIO, HWSIM_CMD_ADD_MAC_ADDR, HWSIM_CMD_DEL_MAC_ADDR, + HWSIM_CMD_START_PMSR, + HWSIM_CMD_ABORT_PMSR, + HWSIM_CMD_REPORT_PMSR, __HWSIM_CMD_MAX, }; #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) @@ -78,6 +81,16 @@ enum { * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received. + * @HWSIM_ATTR_TX_INFO_FLAGS: additional flags for corresponding + * rates of %HWSIM_ATTR_TX_INFO + * @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio + * @HWSIM_ATTR_IFTYPE_SUPPORT: u32 attribute of supported interface types bits + * @HWSIM_ATTR_CIPHER_SUPPORT: u32 array of supported cipher types + * @HWSIM_ATTR_MLO_SUPPORT: claim MLO support (exact parameters TBD) for + * the new radio + * @HWSIM_ATTR_PMSR_SUPPORT: claim peer measurement support + * @HWSIM_ATTR_PMSR_REQUEST: peer measurement request + * @HWSIM_ATTR_PMSR_RESULT: peer measurement result * @__HWSIM_ATTR_MAX: enum limit */ @@ -104,6 +117,14 @@ enum { HWSIM_ATTR_NO_VIF, HWSIM_ATTR_FREQ, HWSIM_ATTR_PAD, + HWSIM_ATTR_TX_INFO_FLAGS, + HWSIM_ATTR_PERM_ADDR, + HWSIM_ATTR_IFTYPE_SUPPORT, + HWSIM_ATTR_CIPHER_SUPPORT, + HWSIM_ATTR_MLO_SUPPORT, + HWSIM_ATTR_PMSR_SUPPORT, + HWSIM_ATTR_PMSR_REQUEST, + HWSIM_ATTR_PMSR_RESULT, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) |