Add support fetch and indicate per-link MLO signal poll information via control interface. Signed-off-by: Veerendranath Jakkam <quic_vjakkam@xxxxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap