diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index babf67722c1575..78800f451e76bb 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -180,6 +180,14 @@ enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, + /** AP mode enable result */ + NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT, + /** AP mode disable result */ + NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT, + /** STA connected to AP */ + NET_EVENT_WIFI_CMD_AP_STA_CONNECTED, + /** STA disconnected from AP */ + NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED, }; #define NET_EVENT_WIFI_SCAN_RESULT \ @@ -209,6 +217,18 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) +#define NET_EVENT_WIFI_AP_ENABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_ENABLE_RESULT) + +#define NET_EVENT_WIFI_AP_DISABLE_RESULT \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_DISABLE_RESULT) + +#define NET_EVENT_WIFI_AP_STA_CONNECTED \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_CONNECTED) + +#define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ + (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) + /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -351,12 +371,35 @@ enum wifi_disconn_reason { WIFI_REASON_DISCONN_INACTIVITY, }; +/** Wi-Fi AP mode result codes. To be overlaid on top of \ref wifi_status + * in the AP mode enable or disable result event for detailed status. + */ +enum wifi_ap_status { + /** AP mode enable or disable successful */ + WIFI_STATUS_AP_SUCCESS = 0, + /** AP mode enable or disable failed - generic failure */ + WIFI_STATUS_AP_FAIL, + /** AP mode enable failed - channel not supported */ + WIFI_STATUS_AP_CHANNEL_NOT_SUPPORTED, + /** AP mode enable failed - channel not allowed */ + WIFI_STATUS_AP_CHANNEL_NOT_ALLOWED, + /** AP mode enable failed - SSID not allowed */ + WIFI_STATUS_AP_SSID_NOT_ALLOWED, + /** AP mode enable failed - authentication type not supported */ + WIFI_STATUS_AP_AUTH_TYPE_NOT_SUPPORTED, + /** AP mode enable failed - operation not supported */ + WIFI_STATUS_AP_OP_NOT_SUPPORTED, + /** AP mode enable failed - operation not permitted */ + WIFI_STATUS_AP_OP_NOT_PERMITTED, +}; + /** Generic Wi-Fi status for commands and events */ struct wifi_status { union { int status; enum wifi_conn_status conn_status; enum wifi_disconn_reason disconn_reason; + enum wifi_ap_status ap_status; }; }; @@ -535,6 +578,18 @@ struct wifi_raw_scan_result { }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ +/** AP mode - connected STA details */ +struct wifi_ap_sta_info { + /** Link mode, see enum wifi_link_mode */ + enum wifi_link_mode link_mode; + /** MAC address */ + uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** MAC address length */ + uint8_t mac_length; + /** is TWT capable ? */ + bool twt_capable; +}; + /* for use in max info size calculations */ union wifi_mgmt_events { struct wifi_scan_result scan_result; @@ -544,6 +599,7 @@ union wifi_mgmt_events { struct wifi_raw_scan_result raw_scan_result; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ struct wifi_twt_params twt_params; + struct wifi_ap_sta_info ap_sta_info; }; /** Wi-Fi mode setup */ @@ -802,6 +858,35 @@ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); +/** Wi-Fi management AP mode enable result event + * + * @param iface Network interface + * @param status AP mode enable result status + */ +void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, enum wifi_ap_status status); + +/** Wi-Fi management AP mode disable result event + * + * @param iface Network interface + * @param status AP mode disable result status + */ +void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, enum wifi_ap_status status); + +/** Wi-Fi management AP mode STA connected event + * + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + +/** Wi-Fi management AP mode STA disconnected event + * @param iface Network interface + * @param sta_info STA information + */ +void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info); + /** * @} */ diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 134448aa57f472..2816be56d746d3 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -64,6 +64,14 @@ config WIFI_MGMT_SCAN_CHAN_MAX_MANUAL There are approximately 100 channels allocated across the three supported bands. The default of 3 allows the 3 most common channels (2.4GHz: 1, 6, 11) to be specified. +config WIFI_SHELL_MAX_AP_STA + int "Maximum number of APs and STAs that can be managed in Wi-Fi shell" + range 1 5 + default 1 + help + This option defines the maximum number of APs and STAs that can be managed + in Wi-Fi shell. + config WIFI_NM bool "Wi-Fi Network manager support" help diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 1a866d4c47cf73..6e0cb761dbf758 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -707,3 +707,43 @@ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, iface, &cnx_status, sizeof(struct wifi_status)); } + +void wifi_mgmt_raise_ap_enable_result_event(struct net_if *iface, + enum wifi_ap_status status) +{ + struct wifi_status cnx_status = { + .status = status, + }; + + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_ENABLE_RESULT, + iface, &cnx_status, + sizeof(enum wifi_ap_status)); +} + +void wifi_mgmt_raise_ap_disable_result_event(struct net_if *iface, + enum wifi_ap_status status) +{ + struct wifi_status cnx_status = { + .status = status, + }; + + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_DISABLE_RESULT, + iface, &cnx_status, + sizeof(enum wifi_ap_status)); +} + +void wifi_mgmt_raise_ap_sta_connected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info) +{ + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_CONNECTED, + iface, sta_info, + sizeof(struct wifi_ap_sta_info)); +} + +void wifi_mgmt_raise_ap_sta_disconnected_event(struct net_if *iface, + struct wifi_ap_sta_info *sta_info) +{ + net_mgmt_event_notify_with_info(NET_EVENT_WIFI_AP_STA_DISCONNECTED, + iface, sta_info, + sizeof(struct wifi_ap_sta_info)); +} diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c7899635105214..ec85008229159b 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -25,24 +25,27 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include +#include #include "net_private.h" #define WIFI_SHELL_MODULE "wifi" +#define WIFI_SHELL_MGMT_EVENTS_COMMON (NET_EVENT_WIFI_SCAN_DONE |\ + NET_EVENT_WIFI_CONNECT_RESULT |\ + NET_EVENT_WIFI_DISCONNECT_RESULT | \ + NET_EVENT_WIFI_TWT |\ + NET_EVENT_WIFI_RAW_SCAN_RESULT |\ + NET_EVENT_WIFI_AP_ENABLE_RESULT |\ + NET_EVENT_WIFI_AP_DISABLE_RESULT |\ + NET_EVENT_WIFI_AP_STA_CONNECTED |\ + NET_EVENT_WIFI_AP_STA_DISCONNECTED) + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY -#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_RAW_SCAN_RESULT | \ - NET_EVENT_WIFI_SCAN_DONE | \ - NET_EVENT_WIFI_CONNECT_RESULT | \ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ - NET_EVENT_WIFI_TWT) +#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON) #else -#define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_SCAN_RESULT | \ - NET_EVENT_WIFI_SCAN_DONE | \ - NET_EVENT_WIFI_CONNECT_RESULT | \ - NET_EVENT_WIFI_DISCONNECT_RESULT | \ - NET_EVENT_WIFI_TWT | \ - NET_EVENT_WIFI_RAW_SCAN_RESULT) +#define WIFI_SHELL_MGMT_EVENTS (WIFI_SHELL_MGMT_EVENTS_COMMON |\ + NET_EVENT_WIFI_SCAN_RESULT) #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS_ONLY */ static struct { @@ -63,6 +66,13 @@ static uint32_t scan_result; static struct net_mgmt_event_callback wifi_shell_mgmt_cb; +static K_MUTEX_DEFINE(wifi_ap_sta_list_lock); +struct wifi_ap_sta_node { + bool valid; + struct wifi_ap_sta_info sta_info; +}; +static struct wifi_ap_sta_node sta_list[CONFIG_WIFI_SHELL_MAX_AP_STA]; + #define print(sh, level, fmt, ...) \ do { \ if (sh) { \ @@ -303,6 +313,87 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) } } +static void handle_wifi_ap_enable_result(struct net_mgmt_event_callback *cb) +{ + const struct wifi_status *status = + (const struct wifi_status *)cb->info; + + if (status->status) { + print(context.sh, SHELL_WARNING, + "AP enable request failed (%d)\n", status->status); + } else { + print(context.sh, SHELL_NORMAL, "AP enabled\n"); + } +} + +static void handle_wifi_ap_disable_result(struct net_mgmt_event_callback *cb) +{ + const struct wifi_status *status = + (const struct wifi_status *)cb->info; + + if (status->status) { + print(context.sh, SHELL_WARNING, + "AP disable request failed (%d)\n", status->status); + } else { + print(context.sh, SHELL_NORMAL, "AP disabled\n"); + } + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + memset(&sta_list, 0, sizeof(sta_list)); + k_mutex_unlock(&wifi_ap_sta_list_lock); +} + +static void handle_wifi_ap_sta_connected(struct net_mgmt_event_callback *cb) +{ + const struct wifi_ap_sta_info *sta_info = + (const struct wifi_ap_sta_info *)cb->info; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + int i; + + print(context.sh, SHELL_NORMAL, "Station connected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + if (!sta_list[i].valid) { + sta_list[i].sta_info = *sta_info; + sta_list[i].valid = true; + break; + } + } + if (i == CONFIG_WIFI_SHELL_MAX_AP_STA) { + print(context.sh, SHELL_WARNING, "No space to store station info: " + "Increase CONFIG_WIFI_SHELL_MAX_AP_STA\n"); + } + k_mutex_unlock(&wifi_ap_sta_list_lock); +} + +static void handle_wifi_ap_sta_disconnected(struct net_mgmt_event_callback *cb) +{ + const struct wifi_ap_sta_info *sta_info = + (const struct wifi_ap_sta_info *)cb->info; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + + print(context.sh, SHELL_NORMAL, "Station disconnected: %s\n", + net_sprint_ll_addr_buf(sta_info->mac, WIFI_MAC_ADDR_LEN, + mac_string_buf, sizeof(mac_string_buf))); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + if (!sta_list[i].valid) { + continue; + } + + if (!memcmp(sta_list[i].sta_info.mac, sta_info->mac, + WIFI_MAC_ADDR_LEN)) { + sta_list[i].valid = false; + break; + } + } + k_mutex_unlock(&wifi_ap_sta_list_lock); +} + static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { @@ -327,6 +418,18 @@ static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, handle_wifi_raw_scan_result(cb); break; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ + case NET_EVENT_WIFI_AP_ENABLE_RESULT: + handle_wifi_ap_enable_result(cb); + break; + case NET_EVENT_WIFI_AP_DISABLE_RESULT: + handle_wifi_ap_disable_result(cb); + break; + case NET_EVENT_WIFI_AP_STA_CONNECTED: + handle_wifi_ap_sta_connected(cb); + break; + case NET_EVENT_WIFI_AP_STA_DISCONNECTED: + handle_wifi_ap_sta_disconnected(cb); + break; default: break; } @@ -1108,6 +1211,8 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, context.sh = sh; + k_mutex_init(&wifi_ap_sta_list_lock); + ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface, &cnx_params, sizeof(struct wifi_connect_req_params)); if (ret) { @@ -1115,7 +1220,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode enabled\n"); + shell_fprintf(sh, SHELL_NORMAL, "AP mode enable requested\n"); return 0; } @@ -1132,7 +1237,49 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "AP mode disabled\n"); + shell_fprintf(sh, SHELL_NORMAL, "AP mode disable requested\n"); + return 0; +} + +static int cmd_wifi_ap_stations(const struct shell *sh, size_t argc, + char *argv[]) +{ + size_t id = 1; + + ARG_UNUSED(argv); + ARG_UNUSED(argc); + + shell_fprintf(sh, SHELL_NORMAL, "AP stations:\n"); + shell_fprintf(sh, SHELL_NORMAL, "============\n"); + + k_mutex_lock(&wifi_ap_sta_list_lock, K_FOREVER); + for (int i = 0; i < CONFIG_WIFI_SHELL_MAX_AP_STA; i++) { + struct wifi_ap_sta_info *sta; + uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; + + if (!sta_list[i].valid) { + continue; + } + + sta = &sta_list[i].sta_info; + + shell_fprintf(sh, SHELL_NORMAL, "Station %zu:\n", id++); + shell_fprintf(sh, SHELL_NORMAL, "==========\n"); + shell_fprintf(sh, SHELL_NORMAL, "MAC: %s\n", + net_sprint_ll_addr_buf(sta->mac, + WIFI_MAC_ADDR_LEN, + mac_string_buf, + sizeof(mac_string_buf))); + shell_fprintf(sh, SHELL_NORMAL, "Link mode: %s\n", + wifi_link_mode_txt(sta->link_mode)); + shell_fprintf(sh, SHELL_NORMAL, "TWT: %s\n", + sta->twt_capable ? "Supported" : "Not supported"); + } + + if (id == 1) { + shell_fprintf(sh, SHELL_NORMAL, "No stations connected\n"); + } + k_mutex_unlock(&wifi_ap_sta_list_lock); return 0; } @@ -1615,6 +1762,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, ": 0:Disable, 1:Optional, 2:Required.\n", cmd_wifi_ap_enable, 2, 4), + SHELL_CMD_ARG(stations, NULL, + "List stations connected to the AP", + cmd_wifi_ap_stations, + 1, 0), SHELL_SUBCMD_SET_END );