diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index fcc46c089a0..ea43e379364 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -492,6 +492,20 @@ static const char * const wifi_ps_param_config_err_code_tbl[] = { }; /** @endcond */ +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +/** IEEE 802.11v BTM (BSS transition management) Query reasons. + * Refer to IEEE Std 802.11v-2011 - Table 7-43x-Transition and Transition Query reasons table. + */ +enum wifi_btm_query_reason { + /** Unspecified. */ + WIFI_BTM_QUERY_REASON_UNSPECIFIED = 0, + /** Low RSSI. */ + WIFI_BTM_QUERY_REASON_LOW_RSSI = 16, + /** Leaving ESS. */ + WIFI_BTM_QUERY_REASON_LEAVING_ESS = 20, +}; +#endif + /** Helper function to get user-friendly power save error code name. */ static inline const char *wifi_ps_get_config_err_code_str(int16_t err_no) { diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 17425b8c752..a990cc2fac5 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -94,6 +94,10 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_AP_CONFIG_PARAM, /** DPP actions */ NET_REQUEST_WIFI_CMD_DPP, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM + /** BSS transition management query */ + NET_REQUEST_WIFI_CMD_BTM_QUERY, +#endif /** @cond INTERNAL_HIDDEN */ NET_REQUEST_WIFI_CMD_MAX /** @endcond */ @@ -207,6 +211,13 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_CONFIG_PARAM); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_DPP); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +/** Request a Wi-Fi BTM query */ +#define NET_REQUEST_WIFI_BTM_QUERY (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_BTM_QUERY) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_BTM_QUERY); +#endif + /** @brief Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -1110,6 +1121,16 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*channel)(const struct device *dev, struct wifi_channel_info *channel); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM + /** Send BTM query + * + * @param dev Pointer to the device structure for the driver instance. + * @param reason query reason + * + * @return 0 if ok, < 0 if error + */ + int (*btm_query)(const struct device *dev, uint8_t reason); +#endif /** Get Version of WiFi driver and Firmware * * The driver that implements the get_version function must not use stack to allocate the diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index bc045d83c4a..f6a84a1dc78 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -929,6 +929,34 @@ int supplicant_channel(const struct device *dev, struct wifi_channel_info *chann return wifi_mgmt_api->channel(dev, channel); } +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +int supplicant_btm_query(const struct device *dev, uint8_t reason) +{ + struct wpa_supplicant *wpa_s; + int ret = -1; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -1; + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + + if (!wpa_cli_cmd_v("wnm_bss_query %d", reason)) { + goto out; + } + + ret = 0; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + return ret; +} +#endif + #ifdef CONFIG_AP int supplicant_ap_enable(const struct device *dev, struct wifi_connect_req_params *params) diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index 98a413b1528..387099203d3 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -148,6 +148,17 @@ int supplicant_filter(const struct device *dev, struct wifi_filter_info *filter) */ int supplicant_channel(const struct device *dev, struct wifi_channel_info *channel); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +/** Send bss transition query + * + * @param dev Pointer to the device structure for the driver instance. + * @param reason query reason + * + * @return 0 if ok, < 0 if error + */ +int supplicant_btm_query(const struct device *dev, uint8_t reason); +#endif + #ifdef CONFIG_AP /** * @brief Set Wi-Fi AP configuration diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index 70d1c079893..2bdb9399650 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -61,6 +61,9 @@ static const struct wifi_mgmt_ops mgmt_ops = { .mode = supplicant_mode, .filter = supplicant_filter, .channel = supplicant_channel, +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM + .btm_query = supplicant_btm_query, +#endif #ifdef CONFIG_AP .ap_enable = supplicant_ap_enable, .ap_disable = supplicant_ap_disable, diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 8b6d3363b37..dc674a751e4 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -775,6 +775,28 @@ static int wifi_get_version(uint32_t mgmt_request, struct net_if *iface, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_VERSION, wifi_get_version); +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +static int wifi_btm_query(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + uint8_t query_reason = *((uint8_t *)data); + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->btm_query == NULL) { + return -ENOTSUP; + } + + if (query_reason >= WIFI_BTM_QUERY_REASON_UNSPECIFIED && + query_reason <= WIFI_BTM_QUERY_REASON_LEAVING_ESS) { + return wifi_mgmt_api->btm_query(dev, query_reason); + } + + return -EINVAL; +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_BTM_QUERY, wifi_btm_query); +#endif + static int wifi_set_rts_threshold(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c2f67e0d5ee..4c5427d76f4 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1570,6 +1570,30 @@ static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *a return 0; } +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM +static int cmd_wifi_btm_query(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = net_if_get_first_wifi(); + uint8_t query_reason = 0; + + context.sh = sh; + + if (!parse_number(sh, (long *)&query_reason, argv[1], NULL, + WIFI_BTM_QUERY_REASON_UNSPECIFIED, WIFI_BTM_QUERY_REASON_LEAVING_ESS)) { + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_BTM_QUERY, iface, &query_reason, sizeof(query_reason))) { + PR_WARNING("Setting BTM query Reason failed..Reason :%d\n", query_reason); + return -ENOEXEC; + } + + PR("Query reason %d\n", query_reason); + + return 0; +} +#endif + static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *argv[]) { struct net_if *iface = net_if_get_first_wifi(); @@ -2594,6 +2618,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, "wifi -i1 -c5.\n", cmd_wifi_channel, 2, 4), +#ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM + SHELL_CMD_ARG(11v_btm_query, + NULL, + ".\n", + cmd_wifi_btm_query, + 2, 0), +#endif SHELL_CMD_ARG(ps_timeout, NULL, " - PS inactivity timer(in ms).\n",