[PATCH 16/18] MLD STA: Add support for indicating per-link MLO signal poll
Veerendranath Jakkam
quic_vjakkam at quicinc.com
Thu Jul 28 06:45:45 PDT 2022
Add support fetch and indicate per-link MLO signal poll information
via control interface.
Signed-off-by: Veerendranath Jakkam <quic_vjakkam at quicinc.com>
---
src/drivers/driver.h | 13 ++++
src/drivers/driver_nl80211.c | 113 ++++++++++++++++++++++++++++++++
wpa_supplicant/ctrl_iface.c | 84 ++++++++++++++++++++++++
wpa_supplicant/driver_i.h | 3 +
wpa_supplicant/wpa_cli.c | 9 +++
wpa_supplicant/wpa_supplicant.c | 14 ++++
6 files changed, 236 insertions(+)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 3ac2f278b..c581ecfe5 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2369,6 +2369,11 @@ struct wpa_signal_info {
int center_frq2;
};
+struct wpa_mlo_signal_info {
+ u16 valid_links;
+ struct wpa_signal_info links[MAX_NUM_MLD_LINKS];
+};
+
/**
* struct wpa_channel_info - Information about the current channel
* @frequency: Center frequency of the primary 20 MHz channel
@@ -3879,6 +3884,14 @@ struct wpa_driver_ops {
*/
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
+ /**
+ * mlo_signal_poll - Get current MLO connection information
+ * @priv: Private driver interface data
+ * @mlo_signal_info: MLO connection info structure
+ */
+ int (*mlo_signal_poll)(void *priv,
+ struct wpa_mlo_signal_info *mlo_signal_info);
+
/**
* channel_info - Get parameters of the current operating channel
* @priv: Private driver interface data
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index bff267ffa..d41c38869 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8733,6 +8733,118 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
}
+static int get_links_noise(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_mlo_signal_info *mlo_sig = arg;
+ int i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_sig->valid_links & BIT(i)))
+ continue;
+
+ if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ mlo_sig->links[i].frequency)
+ continue;
+
+ mlo_sig->links[i].current_noise =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_links_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_mlo_signal_info *mlo_sig)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ return send_and_recv_msgs(drv, msg, get_links_noise, mlo_sig,
+ NULL, NULL);
+}
+
+
+static int nl80211_get_links_channel_width(struct wpa_driver_nl80211_data *drv,
+ struct wpa_mlo_signal_info *mlo_sig)
+{
+ //TODO: Kernel yet to support fetching link channel width information.
+ return 0;
+}
+
+
+static int nl80211_mlo_signal_poll(void *priv,
+ struct wpa_mlo_signal_info *mlo_si)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int res;
+ int i;
+
+ if (drv->nlmode != NL80211_IFTYPE_STATION ||
+ !drv->sta_mlo_info.valid_links)
+ return -1;
+
+ os_memset(mlo_si, 0, sizeof(*mlo_si));
+ mlo_si->valid_links = drv->sta_mlo_info.valid_links;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_si->valid_links & BIT(i)))
+ continue;
+
+ res = nl80211_get_link_signal(drv,
+ drv->sta_mlo_info.links[i].bssid,
+ &mlo_si->links[i]);
+ if (res != 0)
+ return res;
+
+ mlo_si->links[i].center_frq1 = -1;
+ mlo_si->links[i].center_frq2 = -1;
+ mlo_si->links[i].chanwidth = CHAN_WIDTH_UNKNOWN;
+ mlo_si->links[i].current_noise = WPA_INVALID_NOISE;
+ mlo_si->links[i].frequency = drv->sta_mlo_info.links[i].freq;
+ }
+
+ res = nl80211_get_links_channel_width(drv, mlo_si);
+ if (res != 0)
+ return res;
+
+ res = nl80211_get_links_noise(drv, mlo_si);
+ return res;
+}
+
+
static int nl80211_set_param(void *priv, const char *param)
{
struct i802_bss *bss = priv;
@@ -12509,6 +12621,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
+ .mlo_signal_poll = nl80211_mlo_signal_poll,
.channel_info = nl80211_channel_info,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d3a7587a7..f53bf8bc5 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -11541,6 +11541,86 @@ static int wpas_ctrl_iface_send_dscp_query(struct wpa_supplicant *wpa_s,
}
+static int wpa_supplicant_mlo_signal_poll(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+ struct wpa_mlo_signal_info mlo_si;
+
+ if (!wpa_s->valid_links)
+ return -1;
+
+ ret = wpa_drv_mlo_signal_poll(wpa_s, &mlo_si);
+ if (ret)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_si.valid_links & BIT(i)))
+ continue;
+
+ ret = os_snprintf(pos, end - pos,
+ "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%d\n"
+ "NOISE=%d\nFREQUENCY=%u\n",
+ i, mlo_si.links[i].current_signal,
+ mlo_si.links[i].current_txrate / 1000,
+ mlo_si.links[i].current_noise,
+ mlo_si.links[i].frequency);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+
+ if (mlo_si.links[i].chanwidth != CHAN_WIDTH_UNKNOWN) {
+ ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+ channel_width_to_string(
+ mlo_si.links[i].chanwidth));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].center_frq1 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+ mlo_si.links[i].center_frq1);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].center_frq2 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+ mlo_si.links[i].center_frq2);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].avg_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_RSSI=%d\n",
+ mlo_si.links[i].avg_signal);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].avg_beacon_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_BEACON_RSSI=%d\n",
+ mlo_si.links[i].avg_beacon_signal);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s,
const char *params,
char *buf, size_t buflen)
@@ -11576,6 +11656,7 @@ static int wpa_supplicant_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s,
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
+
char *reply;
const int reply_size = 4096;
int reply_len;
@@ -12587,6 +12668,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "DSCP_QUERY ", 11) == 0) {
if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11))
reply_len = -1;
+ } else if (os_strncmp(buf, "MLO_SIGNAL_POLL", 11) == 0) {
+ reply_len = wpa_supplicant_mlo_signal_poll(wpa_s, reply,
+ reply_size);
} else if (os_strncmp(buf, "MLO_STATUS", 10) == 0) {
reply_len = wpa_supplicant_ctrl_iface_mlo_status(
wpa_s, buf + 10, reply, reply_size);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index e20259073..0c838d341 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -523,6 +523,9 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
struct wpa_signal_info *si);
+int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_mlo_signal_info *mlo_si);
+
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
{
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 2b3a6b7b1..e392f88ff 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -419,6 +419,12 @@ static int wpa_cli_cmd_mlo_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_mlo_signal_poll(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "MLO_SIGNAL_POLL");
+}
+
+
static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -4046,6 +4052,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
{ "mlo_status", wpa_cli_cmd_mlo_status, NULL,
cli_cmd_flag_none,
"[verbose] = get ml links status" },
+ { "mlo_signal_poll", wpa_cli_cmd_mlo_signal_poll, NULL,
+ cli_cmd_flag_none,
+ "= get mlo signal parameters" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 1f8075a05..ba364324d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -8698,6 +8698,20 @@ int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
}
+int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_mlo_signal_info *mlo_si)
+{
+ int res;
+
+ if (!wpa_s->driver->mlo_signal_poll)
+ return -1;
+
+ res = wpa_s->driver->mlo_signal_poll(wpa_s->drv_priv, mlo_si);
+
+ return res;
+}
+
+
struct wpa_scan_results *
wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
{
--
2.25.1
More information about the Hostap
mailing list