aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaewan Kim <jaewan@google.com>2022-10-27 11:02:57 +0900
committerJaewan Kim <jaewan@google.com>2022-11-29 20:27:25 +0900
commitf48ef133534df0354ea357bbfd24f8ed51d07235 (patch)
tree1258bcf1736f445971dd898a48774d0d52df74b5
parent0ffa311c79645863beb9a1a15268e9cbf4f36cba (diff)
downloadwmediumd-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.c221
-rw-r--r--wmediumd/pmsr.h84
-rw-r--r--wmediumd/wmediumd.c258
-rw-r--r--wmediumd/wmediumd.h21
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)