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 | 160 ++++++++++++++++++++++++++++++++ wpa_supplicant/ctrl_iface.c | 83 +++++++++++++++++ wpa_supplicant/driver_i.h | 3 + wpa_supplicant/wpa_cli.c | 9 ++ wpa_supplicant/wpa_supplicant.c | 14 +++ 6 files changed, 282 insertions(+) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9bebebcc6..525c7763d 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2392,6 +2392,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 @@ -3986,6 +3991,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 9a23ff823..2650aa08f 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -8774,6 +8774,165 @@ 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 get_links_channel_width(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wpa_mlo_signal_info *mlo_sig = arg; + struct nlattr *link; + int rem_links; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_MLO_LINKS]) + return NL_SKIP; + + nla_for_each_nested(link, tb[NL80211_ATTR_MLO_LINKS], rem_links) { + struct nlattr *tb2[NL80211_ATTR_MAX + 1]; + int link_id; + + nla_parse(tb2, NL80211_ATTR_MAX, nla_data(link), nla_len(link), + NULL); + + if (!tb2[NL80211_ATTR_MLO_LINK_ID]) + continue; + + link_id = nla_get_u8(tb2[NL80211_ATTR_MLO_LINK_ID]); + if (link_id >= MAX_NUM_MLD_LINKS) + continue; + + if (tb2[NL80211_ATTR_CHANNEL_WIDTH]) { + mlo_sig->links[link_id].chanwidth = convert2width( + nla_get_u32(tb2[NL80211_ATTR_CHANNEL_WIDTH])); + if (tb2[NL80211_ATTR_CENTER_FREQ1]) + mlo_sig->links[link_id].center_frq1 = + nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ1]); + if (tb2[NL80211_ATTR_CENTER_FREQ2]) + mlo_sig->links[link_id].center_frq2 = + nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ2]); + } + } + + return NL_SKIP; +} + + +static int nl80211_get_links_channel_width(struct wpa_driver_nl80211_data *drv, + struct wpa_mlo_signal_info *mlo_sig) +{ + struct nl_msg *msg; + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE); + return send_and_recv_msgs(drv, msg, get_links_channel_width, mlo_sig, + NULL, NULL); +} + + +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; @@ -12713,6 +12872,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 cd8a20fbd..356a58d89 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -11540,6 +11540,86 @@ static int wpas_ctrl_iface_send_dscp_query(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_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 wpas_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s, const char *params, char *buf, size_t buflen) @@ -12589,6 +12669,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "MLO_STATUS") == 0) { reply_len = wpas_ctrl_iface_mlo_status(wpa_s, buf + 10, reply, reply_size); + } else if (os_strcmp(buf, "MLO_SIGNAL_POLL") == 0) { + reply_len = wpas_ctrl_iface_mlo_signal_poll(wpa_s, reply, + reply_size); } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 41d353f91..dc7db4b32 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 e0f0d4f8d..2663a39f1 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 8d9228874..745722140 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -8814,6 +8814,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