diff --git a/.checkpatch.conf b/.checkpatch.conf index 8ed5d124ba11..2b639bea64c0 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -30,6 +30,7 @@ --ignore ENOSYS --ignore IS_ENABLED_CONFIG --ignore EMBEDDED_FUNCTION_NAME +--ignore MACRO_WITH_FLOW_CONTROL --exclude ext --exclude samples/matter/.*/src --exclude applications/matter_bridge/src diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index ebc3e644f2d0..fefb6f3393c0 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory_ifdef(CONFIG_BUILD_WITH_TFM tfm/zephyr) add_subdirectory_ifdef(CONFIG_MEMFAULT memfault-firmware-sdk) add_subdirectory_ifdef(CONFIG_MCUBOOT mcuboot/hooks) +add_subdirectory(hostap) diff --git a/modules/Kconfig b/modules/Kconfig index 67435090af79..4428ec67c210 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -6,3 +6,4 @@ osource "$(NCS_MEMFAULT_FIRMWARE_SDK_KCONFIG)" rsource "tfm/zephyr/Kconfig" +rsource "hostap/Kconfig" diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt new file mode 100644 index 000000000000..29808da070ce --- /dev/null +++ b/modules/hostap/CMakeLists.txt @@ -0,0 +1,348 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +if(CONFIG_WPA_SUPP) + +zephyr_library() + +set(HOSTAP_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../../../modules/lib/hostap) +set(WPA_SUPPLICANT_BASE ${HOSTAP_BASE}/wpa_supplicant) +set(COMMON_SRC_BASE ${HOSTAP_BASE}/src) + +set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -lnosys") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMISSING_SYSCALL_NAMES") + +zephyr_compile_definitions( + CONFIG_ZEPHYR +) + +zephyr_include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${HOSTAP_BASE}/ + ${WPA_SUPPLICANT_BASE}/ + ${COMMON_SRC_BASE}/ +) + +zephyr_library_compile_definitions( + TLS_DEFAULT_CIPHERS=\""DEFAULT:!EXP:!LOW"\" + CONFIG_SHA256 + CONFIG_SME + CONFIG_NO_CONFIG_WRITE + CONFIG_NO_CONFIG_BLOBS + CONFIG_WPA_S_ZEPHYR_L2_WIFI_MGMT + CONFIG_CTRL_IFACE + CONFIG_CTRL_IFACE_ZEPHYR + CONFIG_NO_RANDOM_POOL + CONFIG_MBO + CONFIG_WNM + CONFIG_SUITEB192 + ) + +zephyr_library_compile_definitions_ifndef(CONFIG_WPA_SUPP_CRYPTO + CONFIG_NO_PBKDF2 +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_NO_DEBUG + CONFIG_NO_STDOUT_DEBUG +) + +zephyr_library_include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${HOSTAP_BASE}/ + ${COMMON_SRC_BASE}/utils + ${COMMON_SRC_BASE}/drivers + ${HOSTAP_BASE}/src + ${ZEPHYR_BASE}/include + ${ZEPHYR_BASE}/include/net +) + +zephyr_library_sources( + ${COMMON_SRC_BASE}/common/wpa_common.c + ${COMMON_SRC_BASE}/common/ieee802_11_common.c + ${COMMON_SRC_BASE}/common/hw_features_common.c + ${COMMON_SRC_BASE}/common/wpa_ctrl.c + ${COMMON_SRC_BASE}/common/cli.c + + ${COMMON_SRC_BASE}/drivers/driver_common.c + ${COMMON_SRC_BASE}/drivers/drivers.c + ${COMMON_SRC_BASE}/l2_packet/l2_packet_zephyr.c + ${COMMON_SRC_BASE}/drivers/driver_zephyr.c + ${COMMON_SRC_BASE}/utils/common.c + ${COMMON_SRC_BASE}/utils/wpabuf.c + ${COMMON_SRC_BASE}/utils/bitfield.c + ${COMMON_SRC_BASE}/utils/eloop.c + ${COMMON_SRC_BASE}/utils/os_zephyr.c + ${COMMON_SRC_BASE}/utils/radiotap.c + ${WPA_SUPPLICANT_BASE}/config.c + ${WPA_SUPPLICANT_BASE}/notify.c + ${WPA_SUPPLICANT_BASE}/bss.c + ${WPA_SUPPLICANT_BASE}/eap_register.c + ${WPA_SUPPLICANT_BASE}/op_classes.c + ${WPA_SUPPLICANT_BASE}/rrm.c + ${WPA_SUPPLICANT_BASE}/wmm_ac.c + ${WPA_SUPPLICANT_BASE}/config_none.c + ${WPA_SUPPLICANT_BASE}/sme.c + ${WPA_SUPPLICANT_BASE}/wpa_supplicant.c + ${WPA_SUPPLICANT_BASE}/events.c + ${WPA_SUPPLICANT_BASE}/bssid_ignore.c + ${WPA_SUPPLICANT_BASE}/wpas_glue.c + ${WPA_SUPPLICANT_BASE}/scan.c + ${WPA_SUPPLICANT_BASE}/robust_av.c + ${WPA_SUPPLICANT_BASE}/ctrl_iface.c + ${WPA_SUPPLICANT_BASE}/mbo.c + ${WPA_SUPPLICANT_BASE}/wnm_sta.c + ${WPA_SUPPLICANT_BASE}/wpa_cli_cmds.c + ${WPA_SUPPLICANT_BASE}/ctrl_iface_zephyr.c + ${WPA_SUPPLICANT_BASE}/wpa_cli_zephyr.c + # Zephyr main + src/supp_main.c + src/utils/wpa_debug.c + src/supp_api.c + src/supp_events.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_CLI + src/wpa_cli.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_AP + ${WPA_SUPPLICANT_BASE}/ap.c + ${COMMON_SRC_BASE}/ap/ap_config.c + ${COMMON_SRC_BASE}/ap/ap_drv_ops.c + ${COMMON_SRC_BASE}/ap/ap_list.c + ${COMMON_SRC_BASE}/ap/ap_mlme.c + ${COMMON_SRC_BASE}/ap/authsrv.c + ${COMMON_SRC_BASE}/ap/beacon.c + ${COMMON_SRC_BASE}/ap/bss_load.c + ${COMMON_SRC_BASE}/ap/dfs.c + ${COMMON_SRC_BASE}/ap/drv_callbacks.c + ${COMMON_SRC_BASE}/ap/eap_user_db.c + ${COMMON_SRC_BASE}/ap/hostapd.c + ${COMMON_SRC_BASE}/ap/hw_features.c + ${COMMON_SRC_BASE}/ap/ieee802_11_auth.c + ${COMMON_SRC_BASE}/ap/ieee802_11.c + ${COMMON_SRC_BASE}/ap/ieee802_11_he.c + ${COMMON_SRC_BASE}/ap/ieee802_11_ht.c + ${COMMON_SRC_BASE}/ap/ieee802_11_shared.c + ${COMMON_SRC_BASE}/ap/ieee802_11_vht.c + ${COMMON_SRC_BASE}/ap/ieee802_1x.c + ${COMMON_SRC_BASE}/ap/neighbor_db.c + ${COMMON_SRC_BASE}/ap/p2p_hostapd.c + ${COMMON_SRC_BASE}/ap/pmksa_cache_auth.c + ${COMMON_SRC_BASE}/ap/preauth_auth.c + ${COMMON_SRC_BASE}/ap/rrm.c + ${COMMON_SRC_BASE}/ap/sta_info.c + ${COMMON_SRC_BASE}/ap/tkip_countermeasures.c + ${COMMON_SRC_BASE}/ap/utils.c + ${COMMON_SRC_BASE}/ap/wmm.c + + ${COMMON_SRC_BASE}/ap/wpa_auth.c + ${COMMON_SRC_BASE}/ap/wpa_auth_ie.c + ${COMMON_SRC_BASE}/ap/wpa_auth_ft.c + ${COMMON_SRC_BASE}/ap/wpa_auth_glue.c + + ${COMMON_SRC_BASE}/eap_common/eap_common.c + ${COMMON_SRC_BASE}/eap_server/eap_server.c + ${COMMON_SRC_BASE}/eap_server/eap_server_identity.c + ${COMMON_SRC_BASE}/eap_server/eap_server_methods.c + ${COMMON_SRC_BASE}/eapol_auth/eapol_auth_sm.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_AP + CONFIG_AP + CONFIG_NO_RADIUS + CONFIG_NO_VLAN + CONFIG_NO_ACCOUNTING + CONFIG_NEED_AP_MLME + CONFIG_IEEE80211AX + CONFIG_EAP_SERVER + CONFIG_EAP_SERVER_IDENTITY +) + + +zephyr_library_sources_ifndef(CONFIG_WPA_SUPP_CRYPTO + ${COMMON_SRC_BASE}/crypto/crypto_none.c + ${COMMON_SRC_BASE}/crypto/tls_none.c +) + +zephyr_library_compile_definitions_ifndef(CONFIG_WPA_SUPP_CRYPTO + CONFIG_NO_WPA + CONFIG_CRYPTO_INTERNAL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_CRYPTO + CONFIG_WEP +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_CRYPTO + ${COMMON_SRC_BASE}/common/wpa_common.c + ${COMMON_SRC_BASE}/rsn_supp/wpa.c + ${COMMON_SRC_BASE}/rsn_supp/preauth.c + ${COMMON_SRC_BASE}/rsn_supp/wpa_ie.c + + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls-bignum.c + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls-ec.c + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls.c + ${COMMON_SRC_BASE}/crypto/tls_mbedtls.c + ${COMMON_SRC_BASE}/crypto/aes-wrap.c + ${COMMON_SRC_BASE}/crypto/aes-unwrap.c + ${COMMON_SRC_BASE}/crypto/rc4.c + #${COMMON_SRC_BASE}/crypto/random.c + ${COMMON_SRC_BASE}/crypto/sha1-prf.c + ${COMMON_SRC_BASE}/crypto/sha256-prf.c + ${COMMON_SRC_BASE}/crypto/sha256-prf.c + ${COMMON_SRC_BASE}/crypto/sha384-prf.c +) + + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_WPA3 + ${COMMON_SRC_BASE}/common/sae.c + ${COMMON_SRC_BASE}/common/dragonfly.c + + ${COMMON_SRC_BASE}/crypto/dh_groups.c + ${COMMON_SRC_BASE}/crypto/sha256-kdf.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_WPA3 + CONFIG_SAE + CONFIG_ECC +) + +zephyr_library_include_directories_ifdef(CONFIG_WPA_SUPP_CRYPTO + ${CMAKE_SOURCE_DIR} +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_P2P + ${WPA_SUPPLICANT_BASE}/p2p_supplicant.c + ${WPA_SUPPLICANT_BASE}/p2p_supplicant_sd.c + ${COMMON_SRC_BASE}/p2p/p2p.c + ${COMMON_SRC_BASE}/p2p/p2p_utils.c + ${COMMON_SRC_BASE}/p2p/p2p_parse.c + ${COMMON_SRC_BASE}/p2p/p2p_build.c + ${COMMON_SRC_BASE}/p2p/p2p_go_neg.c + ${COMMON_SRC_BASE}/p2p/p2p_sd.c + ${COMMON_SRC_BASE}/p2p/p2p_pd.c + ${COMMON_SRC_BASE}/p2p/p2p_invitation.c + ${COMMON_SRC_BASE}/p2p/p2p_dev_disc.c + ${COMMON_SRC_BASE}/p2p/p2p_group.c + ${COMMON_SRC_BASE}/ap/p2p_hostapd.c + ${COMMON_SRC_BASE}/common/gas.c + ${WPA_SUPPLICANT_BASE}/gas_query.c + ${WPA_SUPPLICANT_BASE}/offchannel.c +) +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_WPS + ${WPA_SUPPLICANT_BASE}/wps_supplicant.c + ${COMMON_SRC_BASE}/utils/uuid.c + ${COMMON_SRC_BASE}/eap_peer/eap_wsc.c + ${COMMON_SRC_BASE}/eap_common/eap_wsc_common.c + ${COMMON_SRC_BASE}/wps/wps.c + ${COMMON_SRC_BASE}/ap/wps_hostapd.c + ${COMMON_SRC_BASE}/wps/wps_common.c + ${COMMON_SRC_BASE}/wps/wps_attr_parse.c + ${COMMON_SRC_BASE}/wps/wps_attr_build.c + ${COMMON_SRC_BASE}/wps/wps_attr_process.c + ${COMMON_SRC_BASE}/wps/wps_dev_attr.c + ${COMMON_SRC_BASE}/wps/wps_enrollee.c + ${COMMON_SRC_BASE}/wps/wps_registrar.c + ${COMMON_SRC_BASE}/crypto/dh_groups.c + ${COMMON_SRC_BASE}/crypto/dh_group5.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_P2P + CONFIG_P2P + CONFIG_GAS + CONFIG_OFFCHANNEL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_WPS + CONFIG_WPS + EAP_WSC +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_CRYPTO_ENTERPRISE + ${COMMON_SRC_BASE}/eap_peer/eap_tls.c + ${COMMON_SRC_BASE}/eap_peer/eap_tls_common.c + + + ${COMMON_SRC_BASE}/eap_peer/eap_peap.c + ${COMMON_SRC_BASE}/eap_common/eap_peap_common.c + ${COMMON_SRC_BASE}/eap_peer/eap_ttls.c + ${COMMON_SRC_BASE}/eap_peer/eap_md5.c + ${COMMON_SRC_BASE}/eap_peer/eap_mschapv2.c + ${COMMON_SRC_BASE}/eap_common/chap.c + ${COMMON_SRC_BASE}/eap_peer/mschapv2.c + ${COMMON_SRC_BASE}/eap_peer/eap_leap.c + + ${COMMON_SRC_BASE}/eap_peer/eap_psk.c + ${COMMON_SRC_BASE}/eap_common/eap_psk_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_fast.c + ${COMMON_SRC_BASE}/eap_peer/eap_fast_pac.c + ${COMMON_SRC_BASE}/eap_common/eap_fast_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_pax.c + ${COMMON_SRC_BASE}/eap_common/eap_pax_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_sake.c + ${COMMON_SRC_BASE}/eap_common/eap_sake_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_gpsk.c + ${COMMON_SRC_BASE}/eap_common/eap_gpsk_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_pwd.c + ${COMMON_SRC_BASE}/eap_common/eap_pwd_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_eke.c + ${COMMON_SRC_BASE}/eap_common/eap_eke_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_ikev2.c + ${COMMON_SRC_BASE}/eap_peer/ikev2.c + ${COMMON_SRC_BASE}/eap_common/eap_ikev2_common.c + ${COMMON_SRC_BASE}/eap_common/ikev2_common.c + + # common + ${COMMON_SRC_BASE}/crypto/sha384-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha256-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha1-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha1-tprf.c + ${COMMON_SRC_BASE}/crypto/ms_funcs.c + ${COMMON_SRC_BASE}/crypto/aes-eax.c + # MD4 removed from MbedTLS + ${COMMON_SRC_BASE}/crypto/md4-internal + ${COMMON_SRC_BASE}/crypto/aes-encblock.c + +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_CRYPTO_ENTERPRISE + CONFIG_EAP_TLS + CONFIG_IEEE8021X_EAPOL + CONFIG_EAP_PEAP + CONFIG_EAP_TTLS + CONFIG_EAP_MD5 + CONFIG_EAP_MSCHAPv2 + CONFIG_EAP_LEAP + CONFIG_EAP_PSK + CONFIG_EAP_FAST + CONFIG_EAP_PAX + CONFIG_EAP_SAKE + CONFIG_EAP_GPSK + CONFIG_EAP_PWD + CONFIG_EAP_EKE + CONFIG_EAP_IKEv2 +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_EAPOL + ${COMMON_SRC_BASE}/eapol_supp/eapol_supp_sm.c + ${COMMON_SRC_BASE}/eap_peer/eap.c + ${COMMON_SRC_BASE}/eap_peer/eap_methods.c + ${COMMON_SRC_BASE}/eap_common/eap_common.c + ${COMMON_SRC_BASE}/rsn_supp/pmksa_cache.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_EAPOL + IEEE8021X_EAPOL +) +endif() diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig new file mode 100644 index 000000000000..8add0121f809 --- /dev/null +++ b/modules/hostap/Kconfig @@ -0,0 +1,168 @@ +# Nordic WiFi driver for nRF52840 and nRF5340 +# +# Copyright (c) 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config WPA_SUPP + bool "WPA supplicant support" + depends on NET_SOCKETS + # Need full POSIX from libc, Zephyr's POSIX support is only partial + depends on !POSIX_API + select POSIX_CLOCK + select NET_SOCKETS_PACKET + select NET_SOCKETPAIR + select NET_L2_WIFI_MGMT + select WIFI_NM + select EXPERIMENTAL if !SOC_SERIES_NRF53X && !SOC_SERIES_NRF91X + help + WPA supplicant implements 802.1X related functions. + +if WPA_SUPP + +config WPA_SUPP_THREAD_STACK_SIZE + int "Stack size for wpa_supplicant thread" + default 8192 + +config WPA_SUPP_IFACE_WQ_STACK_SIZE + int "Stack size for wpa_supplicant iface workqueue" + default 4096 + +config WEP + bool "WEP (Legacy crypto) support" + +# To easily manage the crypto dependencies we separate the crypto +# implementations into two Kconfig options. One for the legacy crypto +# and one for the PSA crypto. +config WPA_SUPP_CRYPTO_PSA + bool "PSA Crypto support for WiFi" + select WEP + select NRF_SECURITY + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_ALG_CMAC + select PSA_WANT_ALG_CBC_PKCS7 + select PSA_WANT_ALG_CTR + select PSA_WANT_ALG_ECDSA + select PSA_WANT_GENERATE_RANDOM + select PSA_WANT_ALG_RSA_PSS + select PSA_WANT_ALG_DETERMINISTIC_ECDSA + select PSA_WANT_ALG_SHA_512 + select PSA_WANT_ALG_SHA_1 + select PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_ECC_SECP_R1_256 + # Legacy crypto, still needed + select MBEDTLS_CMAC_C + select MBEDTLS_GCM_C + select MBEDTLS_TLS_LIBRARY + select MBEDTLS_PK_WRITE_C + select MBEDTLS_X509_LIBRARY + select MBEDTLS_X509_CRT_PARSE_C + select MBEDTLS_CIPHER_C + select MBEDTLS_CIPHER_MODE_CTR + select MBEDTLS_CIPHER_MODE_CBC + select MBEDTLS_SSL_TLS_C + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + default y if BUILD_WITH_TFM + +config WPA_SUPP_CRYPTO + bool "Legacy Crypto support for WiFi" + select WEP + select MBEDTLS + select NRF_SECURITY + select MBEDTLS_CIPHER_MODE_CBC + select MBEDTLS_CIPHER_MODE_CTR + select MBEDTLS_LEGACY_CRYPTO_C + select MBEDTLS_ECP_C + select MBEDTLS_CTR_DRBG_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + default y if !BUILD_WITH_TFM + +# To fix MAC_MD5 Kconfig warning +config NET_TCP_ISN_RFC6528 + default n if WPA_SUPP_CRYPTO + +config WPA_SUPP_CRYPTO_ENTERPRISE + bool "Enterprise Crypto support for WiFi" + +config WPA_SUPP_WPA3 + bool "WPA3 support" + select WPA_SUPP_CRYPTO + default y + +config WPA_SUPP_AP + bool "AP mode support" + select WPA_SUPP_CRYPTO + +config WPA_SUPP_WPS + bool "WPS support" + +config WPA_SUPP_P2P + bool "P2P mode support" + select WPA_SUPP_AP + select WPA_SUPP_WPS + +config WPA_SUPP_EAPOL + bool "Enable EAPoL supplicant" + +config WPA_CLI + bool "CLI support for wpa_supplicant" + default n + +config NET_SOCKETPAIR_BUFFER_SIZE + default 4096 + +config POSIX_MAX_FDS + # l2_packet - 1 + # ctrl_iface - 2 * socketpairs = 4(local and global) + # z_wpa_event_sock - 1 socketpair = 2 + default 7 if !POSIX_API + +config BSS_MAX_IDLE_TIME + int "BSS max idle timeout in seconds" + range 0 64000 + default 300 + help + BSS max idle timeout is the period for which AP may keep a client + in associated state while there is no traffic from that particular + client. Set 0 to disable inclusion of BSS max idle time tag in + association request. If a non-zero value is set, STA can suggest a + timeout by including BSS max idle period in the association request. + AP may choose to consider or ignore the STA's preferred value. + Ref: Sec 11.21.13 of IEEE Std 802.11™-2020 + +# Control interface is stack heavy (buffers + snprintfs) +# Making calls to RPU from net_mgmt callbacks (status - RSSI) +config NET_MGMT_EVENT_STACK_SIZE + default 4096 + +config NET_SOCKETS_POLL_MAX + default 4 + +module = WPA_SUPP +module-str = WPA supplicant +source "subsys/logging/Kconfig.template.log_config" + +config WPA_SUPP_DEBUG_LEVEL + int "Min compiled-in debug message level for WPA supplicant" + default 0 if WPA_SUPP_LOG_LEVEL_DBG # MSG_EXCESSIVE + default 3 if WPA_SUPP_LOG_LEVEL_INF # MSG_INFO + default 4 if WPA_SUPP_LOG_LEVEL_WRN # MSG_WARNING + default 5 if WPA_SUPP_LOG_LEVEL_ERR # MSG_ERROR + default 6 + help + Minimum priority level of a debug message emitted by WPA supplicant that + is compiled-in the firmware. See wpa_debug.h file of the supplicant for + available levels and functions for emitting the messages. Note that + runtime filtering can also be configured in addition to the compile-time + filtering. + +# Debug logs need more buffer space +config LOG_BUFFER_SIZE + default 4096 if WPA_SUPP_LOG_LEVEL_DBG + default 2048 + +config WPA_SUPP_NO_DEBUG + bool "Disable printing of debug messages, saves code size significantly" +endif diff --git a/modules/hostap/module.yml b/modules/hostap/module.yml new file mode 100644 index 000000000000..9c43bc6e5fd6 --- /dev/null +++ b/modules/hostap/module.yml @@ -0,0 +1,3 @@ +build: + cmake: ./zephyr + kconfig: ./zephyr/Kconfig diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c new file mode 100644 index 000000000000..5e72ebfb182a --- /dev/null +++ b/modules/hostap/src/supp_api.c @@ -0,0 +1,547 @@ +/** + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include + +#include +#include + +#include "includes.h" +#include "common.h" +#include "common/defs.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_api.h" +#include "wpa_cli_zephyr.h" +#include "supp_events.h" + +extern struct k_sem wpa_supplicant_ready_sem; +extern struct wpa_global *global; + +enum requested_ops { + CONNECT = 0, + DISCONNECT +}; + +enum status_thread_state { + STATUS_THREAD_STOPPED = 0, + STATUS_THREAD_RUNNING, +}; + +#define OP_STATUS_POLLING_INTERVAL 1 + +#define CONNECTION_SUCCESS 0 +#define CONNECTION_FAILURE 1 +#define CONNECTION_TERMINATED 2 + +#define DISCONNECT_TIMEOUT_MS 5000 + +#define _wpa_cli_cmd_v(cmd, ...) \ + do { \ + if (z_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ + goto out; \ + } \ + } while (0) + +K_MUTEX_DEFINE(wpa_supplicant_mutex); + + +struct wpa_supp_api_ctrl { + const struct device *dev; + enum requested_ops requested_op; + enum status_thread_state status_thread_state; + int connection_timeout; /* in seconds */ + struct k_work_sync sync; + bool terminate; +}; + +static struct wpa_supp_api_ctrl wpa_supp_api_ctrl; + +static void supp_shell_connect_status(struct k_work *work); + +static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, + supp_shell_connect_status); + +static inline struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) +{ + return z_wpas_get_handle_by_ifname(dev->name); +} + +static int wait_for_disconnect_complete(const struct device *dev) +{ + int ret = 0; + int timeout = 0; + struct wpa_supplicant *wpa_s = get_wpa_s_handle(dev); + + if (!wpa_s) { + ret = -ENODEV; + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle"); + goto out; + } + + while (wpa_s->wpa_state != WPA_DISCONNECTED) { + if (timeout > DISCONNECT_TIMEOUT_MS) { + ret = -ETIMEDOUT; + wpa_printf(MSG_WARNING, "Failed to disconnect from network"); + break; + } + k_sleep(K_MSEC(10)); + timeout++; + } +out: + return ret; +} + +static void supp_shell_connect_status(struct k_work *work) +{ + static int seconds_counter; + int status = CONNECTION_SUCCESS; + struct wpa_supplicant *wpa_s; + struct wpa_supp_api_ctrl *ctrl = &wpa_supp_api_ctrl; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + if (ctrl->status_thread_state == STATUS_THREAD_RUNNING && ctrl->terminate) { + status = CONNECTION_TERMINATED; + goto out; + } + + wpa_s = get_wpa_s_handle(ctrl->dev); + if (!wpa_s) { + status = CONNECTION_FAILURE; + goto out; + } + + if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { + if (ctrl->connection_timeout > 0 && seconds_counter++ > ctrl->connection_timeout) { + _wpa_cli_cmd_v("disconnect"); + send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_CONNECT_RESULT, + -ETIMEDOUT); + status = CONNECTION_FAILURE; + goto out; + } + + k_work_reschedule(&wpa_supp_status_work, K_SECONDS(OP_STATUS_POLLING_INTERVAL)); + ctrl->status_thread_state = STATUS_THREAD_RUNNING; + k_mutex_unlock(&wpa_supplicant_mutex); + return; + } +out: + seconds_counter = 0; + + ctrl->status_thread_state = STATUS_THREAD_STOPPED; + k_mutex_unlock(&wpa_supplicant_mutex); +} + +static inline void wpa_supp_restart_status_work(void) +{ + /* Terminate synchronously */ + wpa_supp_api_ctrl.terminate = 1; + k_work_flush_delayable(&wpa_supp_status_work, + &wpa_supp_api_ctrl.sync); + wpa_supp_api_ctrl.terminate = 0; + + /* Start afresh */ + k_work_reschedule(&wpa_supp_status_work, + K_MSEC(10)); +} + +static inline int chan_to_freq(int chan) +{ + /* We use global channel list here and also use the widest + * op_class for 5GHz channels as there is no user input + * for these (yet). + */ + int freq = ieee80211_chan_to_freq(NULL, 81, chan); + + if (freq <= 0) { + freq = ieee80211_chan_to_freq(NULL, 128, chan); + } + + if (freq <= 0) { + wpa_printf(MSG_ERROR, "Invalid channel %d", chan); + return -1; + } + + return freq; +} + +static inline enum wifi_frequency_bands wpas_band_to_zephyr(enum wpa_radio_work_band band) +{ + switch (band) { + case BAND_2_4_GHZ: + return WIFI_FREQ_BAND_2_4_GHZ; + case BAND_5_GHZ: + return WIFI_FREQ_BAND_5_GHZ; + default: + return WIFI_FREQ_BAND_UNKNOWN; + } +} + +static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt) +{ + switch (key_mgmt) { + case WPA_KEY_MGMT_NONE: + return WIFI_SECURITY_TYPE_NONE; + case WPA_KEY_MGMT_PSK: + return WIFI_SECURITY_TYPE_PSK; + case WPA_KEY_MGMT_PSK_SHA256: + return WIFI_SECURITY_TYPE_PSK_SHA256; + case WPA_KEY_MGMT_SAE: + return WIFI_SECURITY_TYPE_SAE; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; + } +} + +/* Public API */ +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + struct add_network_resp resp = {0}; + + if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) { + wpa_printf(MSG_ERROR, + "Interface %s is down, dropping connect", + dev->name); + return -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; + } + + _wpa_cli_cmd_v("remove_network all"); + ret = z_wpa_ctrl_add_network(&resp); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add network"); + goto out; + } + + wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); + + _wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); + _wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); + _wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); + _wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + if (params->security != WIFI_SECURITY_TYPE_NONE) { + if (params->security == WIFI_SECURITY_TYPE_SAE) { + if (params->sae_password) { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password); + } else { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk); + } + _wpa_cli_cmd_v("set_network %d key_mgmt SAE", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { + _wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK) { + _wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", + resp.network_id); + } else { + ret = -1; + wpa_printf(MSG_ERROR, "Unsupported security type: %d", + params->security); + goto out; + } + + if (params->mfp) { + _wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp); + } + } + + /* enable and select network */ + _wpa_cli_cmd_v("enable_network %d", resp.network_id); + + if (params->channel != WIFI_CHANNEL_ANY) { + int freq = chan_to_freq(params->channel); + + if (freq < 0) { + ret = -1; + wpa_printf(MSG_ERROR, "Invalid channel %d", + params->channel); + goto out; + } + z_wpa_cli_cmd_v("set_network %d scan_freq %d", + resp.network_id, freq); + } + _wpa_cli_cmd_v("select_network %d", resp.network_id); + + z_wpa_cli_cmd_v("select_network %d", resp.network_id); + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = CONNECT; + wpa_supp_api_ctrl.connection_timeout = params->timeout; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (!ret) { + wpa_supp_restart_status_work(); + } + + return ret; +} + +int z_wpa_supplicant_disconnect(const struct device *dev) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + ret = -EINVAL; + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); + goto out; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -EINVAL; + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = DISCONNECT; + _wpa_cli_cmd_v("disconnect"); + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (ret) { + wpa_printf(MSG_ERROR, "Disconnect failed: %s", + strerror(-ret)); + return ret; + } + + wpa_supp_restart_status_work(); + + ret = wait_for_disconnect_complete(dev); + + wifi_mgmt_raise_disconnect_complete_event(iface, ret); + + return ret; +} + +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status) +{ + struct wpa_supplicant *wpa_s; + int ret = -1; + struct wpa_signal_info *si = NULL; + struct wpa_conn_info *conn_info = NULL; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Interface %s not found", dev->name); + goto out; + } + + si = os_zalloc(sizeof(struct wpa_signal_info)); + if (!si) { + wpa_printf(MSG_ERROR, "Failed to allocate memory for signal info"); + goto out; + } + + status->state = wpa_s->wpa_state; /* 1-1 Mapping */ + + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 channel; + struct signal_poll_resp signal_poll; + + os_memcpy(status->bssid, wpa_s->bssid, WIFI_MAC_ADDR_LEN); + status->band = wpas_band_to_zephyr(wpas_freq_to_band(wpa_s->assoc_freq)); + status->security = wpas_key_mgmt_to_zephyr(wpa_s->key_mgmt); + status->mfp = ssid->ieee80211w; /* Same mapping */ + ieee80211_freq_to_chan(wpa_s->assoc_freq, &channel); + status->channel = channel; + + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + struct status_resp cli_status; + + if (ssid_len == 0) { + int _res = z_wpa_ctrl_status(&cli_status); + + if (_res < 0) + ssid_len = 0; + else + ssid_len = cli_status.ssid_len; + _ssid = cli_status.ssid; + } + os_memcpy(status->ssid, _ssid, ssid_len); + status->ssid_len = ssid_len; + status->iface_mode = ssid->mode; + if (wpa_s->connection_set == 1) { + status->link_mode = wpa_s->connection_he ? WIFI_6 : + wpa_s->connection_vht ? WIFI_5 : + wpa_s->connection_ht ? WIFI_4 : + wpa_s->connection_g ? WIFI_3 : + wpa_s->connection_a ? WIFI_2 : + wpa_s->connection_b ? WIFI_1 : + WIFI_0; + } else { + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + } + } + ret = z_wpa_ctrl_signal_poll(&signal_poll); + if (!ret) { + status->rssi = signal_poll.rssi; + } else { + wpa_printf(MSG_WARNING, "%s:Failed to read RSSI\n", + __func__); + status->rssi = -WPA_INVALID_NOISE; + ret = 0; + } + + conn_info = os_zalloc(sizeof(struct wpa_conn_info)); + if (!conn_info) { + wpa_printf(MSG_ERROR, "%s:Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + goto out; + } + ret = wpa_drv_get_conn_info(wpa_s, conn_info); + if (!ret) { + status->beacon_interval = conn_info->beacon_interval; + status->dtim_period = conn_info->dtim_period; + status->twt_capable = conn_info->twt_capable; + } else { + wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n", + __func__); + status->beacon_interval = 0; + status->dtim_period = 0; + status->twt_capable = false; + ret = 0; + } + os_free(conn_info); + } else { + ret = 0; + } +out: + os_free(si); + k_mutex_unlock(&wpa_supplicant_mutex); + return ret; +} + +/* Below APIs are not natively supported by WPA supplicant, so, + * these are just wrappers around driver offload APIs. But it is + * transparent to the user. + * + * In the future these might be implemented natively by the WPA + * supplicant. + */ + +static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device *dev) +{ + struct net_wifi_mgmt_offload *off_api = + (struct net_wifi_mgmt_offload *) dev->api; + + return off_api ? off_api->wifi_mgmt_api : NULL; +} + +int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->scan) { + wpa_printf(MSG_ERROR, "Scan not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->scan(dev, params, cb); +} + +#ifdef CONFIG_NET_STATISTICS_WIFI +int z_wpa_supplicant_get_stats(const struct device *dev, + struct net_stats_wifi *stats) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_stats) { + wpa_printf(MSG_ERROR, "Get stats not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_stats(dev, stats); +} +#endif /* CONFIG_NET_STATISTICS_WIFI */ + +int z_wpa_supplicant_set_power_save(const struct device *dev, + struct wifi_ps_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_power_save) { + wpa_printf(MSG_ERROR, "Set power save not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_power_save(dev, params); +} + +int z_wpa_supplicant_set_twt(const struct device *dev, + struct wifi_twt_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_twt) { + wpa_printf(MSG_ERROR, "Set TWT not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_twt(dev, params); +} + +int z_wpa_supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_power_save_config) { + wpa_printf(MSG_ERROR, "Get power save config not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_power_save_config(dev, config); +} + +int z_wpa_supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->reg_domain) { + wpa_printf(MSG_ERROR, "Regulatory domain not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->reg_domain(dev, reg_domain); +} diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h new file mode 100644 index 000000000000..080bbd814ddc --- /dev/null +++ b/modules/hostap/src/supp_api.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + */ + +#ifndef ZEPHYR_SUPP_MGMT_H +#define ZEPHYR_SUPP_MGMT_H + +#include + +#define MAX_SSID_LEN 32 +#define MAC_ADDR_LEN 6 + +/** + * @brief Request a connection + * + * @param dev: Wi-Fi interface name to use + * @param params: Connection details + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params); +/** + * @brief Forces station to disconnect and stops any subsequent scan + * or connection attempts + * + * @param dev: Wi-Fi interface name to use + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_disconnect(const struct device *dev); + +/** + * @brief + * + * @param dev: Wi-Fi interface name to use + * @param status: Status structure to fill + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status); + +/** + * @brief Request a scan + * + * @param dev Wi-Fi interface name to use + * @param params Scan parameters + * @param cb Callback to be called for each scan result + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb); + +#if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) +/** + * @brief Get Wi-Fi statistics + * + * @param dev Wi-Fi interface name to use + * @param stats Pointer to stats structure to fill + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_get_stats(const struct device *dev, + struct net_stats_wifi *stats); +#endif /* CONFIG_NET_STATISTICS_WIFI || __DOXYGEN__ */ + +/** + * @brief Set Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param params Power save parameters to set + * + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_set_power_save(const struct device *dev, + struct wifi_ps_params *params); + +/** + * @brief Set Wi-Fi TWT parameters + * + * @param dev Wi-Fi interface name to use + * @param params TWT parameters to set + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_set_twt(const struct device *dev, + struct wifi_twt_params *params); + +/** + * @brief Get Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param config Address of power save configuration to fill + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config); + +/** + * @brief Set Wi-Fi Regulatory domain + * + * @param dev Wi-Fi interface name to use + * @param reg_domain Regulatory domain to set + * @return 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain); +#endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c new file mode 100644 index 000000000000..0ae19271da2c --- /dev/null +++ b/modules/hostap/src/supp_events.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "supp_events.h" + +#include "includes.h" +#include "common.h" + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, int status) +{ + const struct device *dev = device_get_binding(ifname); + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WIFI_CMD_CONNECT_RESULT: + wifi_mgmt_raise_connect_result_event(iface, status); + break; + case NET_EVENT_WIFI_CMD_DISCONNECT_RESULT: + wifi_mgmt_raise_disconnect_result_event(iface, status); + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} + +int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status) +{ + /* TODO: Replace device_get_binding. */ + const struct device *dev = device_get_binding(ifname); + + if (!dev) { + wpa_printf(MSG_ERROR, "Could not find device for %s", ifname); + return -ENODEV; + } + + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WPA_SUPP_CMD_READY: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_READY, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_NOT_READY: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_NOT_READY, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_ADDED, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING: + net_mgmt_event_notify(NET_EVENT_WPA_SUPP_IFACE_REMOVING, iface); + break; + case NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED: + net_mgmt_event_notify_with_info(NET_EVENT_WPA_SUPP_IFACE_REMOVED, + iface, &status, sizeof(status)); + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} diff --git a/modules/hostap/src/supp_events.h b/modules/hostap/src/supp_events.h new file mode 100644 index 000000000000..5200dcb7fe71 --- /dev/null +++ b/modules/hostap/src/supp_events.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef __SUPP_EVENTS_H__ +#define __SUPP_EVENTS_H__ + +#include + +/* Connectivity Events */ +#define _NET_MGMT_WPA_SUPP_LAYER NET_MGMT_LAYER_L2 +#define _NET_MGMT_WPA_SUPP_CODE 0x157 +#define _NET_MGMT_WPA_SUPP_BASE (NET_MGMT_LAYER(_NET_MGMT_WPA_SUPP_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_MGMT_WPA_SUPP_CODE) | \ + NET_MGMT_IFACE_BIT) +#define _NET_MGMT_WPA_SUPP_EVENT (NET_MGMT_EVENT_BIT | _NET_MGMT_WPA_SUPP_BASE) + +enum net_event_wpa_supp_cmd { + NET_EVENT_WPA_SUPP_CMD_READY = 1, + NET_EVENT_WPA_SUPP_CMD_NOT_READY, + NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, + NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, + NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + NET_EVENT_WIFI_CMD_MAX +}; + +#define NET_EVENT_WPA_SUPP_READY \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_READY) + +#define NET_EVENT_WPA_SUPP_NOT_READY \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_NOT_READY) + +#define NET_EVENT_WPA_SUPP_IFACE_ADDED \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED) + +#define NET_EVENT_WPA_SUPP_IFACE_REMOVED \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED) + +#define NET_EVENT_WPA_SUPP_IFACE_REMOVING \ + (_NET_MGMT_WPA_SUPP_EVENT | NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING) + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, int status); +int generate_supp_state_event(const char *ifname, enum net_event_wpa_supp_cmd event, int status); + +#endif /* __SUPP_EVENTS_H__ */ diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c new file mode 100644 index 000000000000..f36e9036386c --- /dev/null +++ b/modules/hostap/src/supp_main.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * WPA Supplicant / main() function for Zephyr OS + * Copyright (c) 2003-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +LOG_MODULE_REGISTER(wpa_supplicant, LOG_LEVEL_DBG); + +#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) +#include +#endif /* CONFIG_WPA_SUPP_CRYPTO */ + +#include + +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" + +#include "fst/fst.h" +#include "includes.h" +#include "p2p_supplicant.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_events.h" +#include "wpa_cli_zephyr.h" + +#include "supp_api.h" + +K_SEM_DEFINE(z_wpas_ready_sem, 0, 1); +#include + +/* Should match with the driver name */ +#define DEFAULT_IFACE_NAME "wlan0" +#define IFACE_MATCHING_PREFIX "wlan" + +static struct net_mgmt_event_callback cb; +struct k_mutex iface_up_mutex; + +struct wpa_global *global; + +static int z_wpas_event_sockpair[2]; + +static void z_wpas_start(void); +static void z_wpas_iface_work_handler(struct k_work *item); + +K_THREAD_DEFINE(z_wpa_s_tid, + CONFIG_WPA_SUPP_THREAD_STACK_SIZE, + z_wpas_start, + NULL, + NULL, + NULL, + 0, + 0, + 0); + +static K_THREAD_STACK_DEFINE(z_wpas_iface_wq_stack, + CONFIG_WPA_SUPP_IFACE_WQ_STACK_SIZE); + +/* TODO: Debug why wsing system workqueue blocks the driver dedicated + * workqueue? + */ +static struct k_work_q z_wpas_iface_wq; +static K_WORK_DEFINE(z_wpas_iface_work, + z_wpas_iface_work_handler); + +K_MUTEX_DEFINE(z_wpas_event_mutex); + +static const struct wifi_mgmt_ops wpa_supp_ops = { + .scan = z_wpa_supplicant_scan, + .connect = z_wpa_supplicant_connect, + .disconnect = z_wpa_supplicant_disconnect, + .iface_status = z_wpa_supplicant_status, +#ifdef CONFIG_NET_STATISTICS_WIFI + .get_stats = z_wpa_supplicant_get_stats, +#endif + .set_power_save = z_wpa_supplicant_set_power_save, + .set_twt = z_wpa_supplicant_set_twt, + .get_power_save_config = z_wpa_supplicant_get_power_save_config, + .reg_domain = z_wpa_supplicant_reg_domain, +}; + +DEFINE_WIFI_NM_INSTANCE(wpa_supplicant, &wpa_supp_ops); + +#ifdef CONFIG_MATCH_IFACE +static int z_wpas_init_match(struct wpa_global *global) +{ + /* + * The assumption is that the first driver is the primary driver and + * will handle the arrival / departure of interfaces. + */ + if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { + global->drv_priv[0] = wpa_drivers[0]->global_init(global); + if (!global->drv_priv[0]) { + wpa_printf(MSG_ERROR, + "Failed to initialize driver '%s'", + wpa_drivers[0]->name); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_MATCH_IFACE */ + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname) +{ + struct wpa_supplicant *wpa_s = NULL; + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(2)); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: WPA supplicant not ready: %d", __func__, ret); + return NULL; + } + + k_sem_give(&z_wpas_ready_sem); + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (!wpa_s) { + wpa_printf(MSG_ERROR, + "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); + return NULL; + } + + return wpa_s; +} + +static int z_wpas_get_iface_count(void) +{ + struct wpa_supplicant *wpa_s; + unsigned int count = 0; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + count += 1; + } + return count; +} + +#define Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS 1000 +#define Z_WPA_S_IFACE_NOTIFY_RETRY_MS 10 + +static int z_wpas_add_interface(const char *ifname) +{ + struct wpa_supplicant *wpa_s; + struct net_if *iface; + int ret = -1; + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + wpa_printf(MSG_DEBUG, "Adding interface %s\n", ifname); + + iface = net_if_lookup_by_dev(device_get_binding(ifname)); + if (!iface) { + wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); + goto err; + } + + ret = z_wpa_cli_global_cmd_v("interface_add %s %s %s %s", + ifname, "zephyr", "zephyr", "zephyr"); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add interface: %s", ifname); + goto err; + } + + /* This cannot be through control interface as need the handle */ + while (retry++ < count && !wpa_supplicant_get_iface(global, ifname)) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + wpa_printf(MSG_ERROR, "Failed to add iface: %s", ifname); + goto err; + } + + wpa_s->conf->filter_ssids = 1; + wpa_s->conf->ap_scan = 1; + + /* Default interface, kick start wpa_supplicant */ + if (z_wpas_get_iface_count() == 1) { + k_mutex_unlock(&iface_up_mutex); + } + + ret = z_wpa_ctrl_init(wpa_s); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to initialize control interface"); + goto err; + } + + ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface); + + if (ret) { + wpa_printf(MSG_ERROR, "Failed to register mgd iface with native stack: %s (%d)", + ifname, ret); + goto err; + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_ADDED, 0); + + if (z_wpas_get_iface_count() == 1) { + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_READY, 0); + } + + return 0; +err: + return ret; +} + +static int z_wpas_remove_interface(const char *ifname) +{ + int ret = -1; + union wpa_event_data *event = os_zalloc(sizeof(*event)); + struct wpa_supplicant *wpa_s = wpa_supplicant_get_iface(global, ifname); + struct net_if *iface = net_if_lookup_by_dev(device_get_binding(ifname)); + + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + if (!event) { + wpa_printf(MSG_ERROR, "Failed to allocate event data"); + goto err; + } + + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle for %s", ifname); + goto err; + } + + if (!iface) { + wpa_printf(MSG_ERROR, "Failed to get net_if handle for %s", ifname); + goto err; + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVING, 0); + wpa_printf(MSG_DEBUG, "Remove interface %s\n", ifname); + + os_memcpy(event->interface_status.ifname, ifname, IFNAMSIZ); + event->interface_status.ievent = EVENT_INTERFACE_REMOVED; + + struct wpa_supplicant_event_msg msg = { + .global = true, + .ctx = global, + .event = EVENT_INTERFACE_STATUS, + .data = event, + }; + + z_wpas_send_event(&msg); + + while (retry++ < count && + wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + wpa_printf(MSG_ERROR, "Failed to notify remove interface: %s", ifname); + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + -1); + goto err; + } + + ret = z_wpa_cli_global_cmd_v("interface_remove %s", ifname); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to remove interface: %s", ifname); + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, + -EINVAL); + goto err; + } + + ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to unregister mgd iface with native stack: %s (%d)", + ifname, ret); + goto err; + } + + if (z_wpas_get_iface_count() == 0) { + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); + } + + generate_supp_state_event(ifname, NET_EVENT_WPA_SUPP_CMD_IFACE_REMOVED, 0); + + return 0; +err: + if (event) { + os_free(event); + } + return ret; +} + +static void iface_event_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + const char *ifname = iface->if_dev->dev->name; + + if (strncmp(ifname, IFACE_MATCHING_PREFIX, sizeof(IFACE_MATCHING_PREFIX) - 1) != 0) { + return; + } + + wpa_printf(MSG_DEBUG, "Event: %d", mgmt_event); + if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { + z_wpas_add_interface(ifname); + } else if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { + z_wpas_remove_interface(ifname); + } +} + +static void register_iface_events(void) +{ + k_mutex_init(&iface_up_mutex); + + k_mutex_lock(&iface_up_mutex, K_FOREVER); + net_mgmt_init_event_callback(&cb, iface_event_handler, + NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN); + net_mgmt_add_event_callback(&cb); +} + +static void wait_for_interface_up(const char *iface_name) +{ + if (z_wpas_get_iface_count() == 0) { + k_mutex_lock(&iface_up_mutex, K_FOREVER); + } +} + +#include "config.h" +static void iface_cb(struct net_if *iface, void *user_data) +{ + const char *ifname = iface->if_dev->dev->name; + + if (ifname == NULL) { + return; + } + + if (strncmp(ifname, DEFAULT_IFACE_NAME, strlen(ifname)) != 0) { + return; + } + + /* Check default interface */ + if (net_if_is_admin_up(iface)) { + z_wpas_add_interface(ifname); + } + + register_iface_events(); +} + + +static void z_wpas_iface_work_handler(struct k_work *item) +{ + ARG_UNUSED(item); + + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(5)); + + if (ret) { + wpa_printf(MSG_ERROR, "Timed out waiting for wpa_supplicant"); + return; + } + + net_if_foreach(iface_cb, NULL); + wait_for_interface_up(DEFAULT_IFACE_NAME); + + k_sem_give(&z_wpas_ready_sem); +} + +static void z_wpas_event_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +{ + int ret; + + ARG_UNUSED(eloop_ctx); + ARG_UNUSED(sock_ctx); + struct wpa_supplicant_event_msg msg; + + ret = recv(sock, &msg, sizeof(msg), 0); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "Failed to recv the message: %s", strerror(errno)); + return; + } + + if (ret != sizeof(msg)) { + wpa_printf(MSG_ERROR, "Received incomplete message: got: %d, expected:%d", + ret, sizeof(msg)); + return; + } + + wpa_printf(MSG_DEBUG, "Passing message %d to wpa_supplicant", msg.event); + + if (msg.global) { + wpa_supplicant_event_global(msg.ctx, msg.event, msg.data); + } else { + wpa_supplicant_event(msg.ctx, msg.event, msg.data); + } + + if (msg.data) { + if (msg.event == EVENT_AUTH) { + union wpa_event_data *data = msg.data; + + os_free((char *)data->auth.ies); + } + os_free(msg.data); + } +} + +static int register_wpa_event_sock(void) +{ + int ret; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, z_wpas_event_sockpair); + + if (ret != 0) { + wpa_printf(MSG_ERROR, "Failed to initialize socket: %s", strerror(errno)); + return -1; + } + + eloop_register_read_sock(z_wpas_event_sockpair[0], z_wpas_event_sock_handler, NULL, NULL); + + return 0; +} + +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg) +{ + int ret; + unsigned int retry = 0; + + k_mutex_lock(&z_wpas_event_mutex, K_FOREVER); + + if (z_wpas_event_sockpair[1] < 0) { + goto err; + } + +retry_send: + ret = send(z_wpas_event_sockpair[1], msg, sizeof(*msg), 0); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) { + k_msleep(2); + if (retry++ < 3) { + goto retry_send; + } else { + wpa_printf(MSG_WARNING, "Event send fail (max retries): %s", + strerror(errno)); + goto err; + } + } else { + wpa_printf(MSG_WARNING, "Event send fail: %s", + strerror(errno)); + goto err; + } + } + + ret = 0; +err: + k_mutex_unlock(&z_wpas_event_mutex); + return -1; +} + +static void z_wpas_start(void) +{ + struct wpa_params params; + int exitcode = -1; + +#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) + /* Needed for crypto operation as default is no-op and fails */ + mbedtls_platform_set_calloc_free(calloc, free); +#endif /* CONFIG_WPA_CRYPTO */ + + k_work_queue_init(&z_wpas_iface_wq); + + k_work_queue_start(&z_wpas_iface_wq, + z_wpas_iface_wq_stack, + K_THREAD_STACK_SIZEOF(z_wpas_iface_wq_stack), + 7, + NULL); + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = CONFIG_WPA_SUPP_DEBUG_LEVEL; + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); + exitcode = -1; + goto out; + } else { + wpa_printf(MSG_INFO, "Successfully initialized " + "wpa_supplicant"); + } + + if (fst_global_init()) { + wpa_printf(MSG_ERROR, "Failed to initialize FST"); + exitcode = -1; + goto out; + } + +#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) + if (!fst_global_add_ctrl(fst_ctrl_cli)) { + wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); + } +#endif + z_global_wpa_ctrl_init(); + + register_wpa_event_sock(); + + k_work_submit_to_queue(&z_wpas_iface_wq, &z_wpas_iface_work); + +#ifdef CONFIG_MATCH_IFACE + if (exitcode == 0) { + exitcode = z_wpas_init_match(global); + } +#endif /* CONFIG_MATCH_IFACE */ + + if (exitcode == 0) { + k_sem_give(&z_wpas_ready_sem); + exitcode = wpa_supplicant_run(global); + } + + generate_supp_state_event(DEFAULT_IFACE_NAME, NET_EVENT_WPA_SUPP_CMD_NOT_READY, 0); + eloop_unregister_read_sock(z_wpas_event_sockpair[0]); + + z_wpa_ctrl_deinit(); + z_global_wpa_ctrl_deinit(); + wpa_supplicant_deinit(global); + + fst_global_deinit(); + + close(z_wpas_event_sockpair[0]); + close(z_wpas_event_sockpair[1]); + +out: +#ifdef CONFIG_MATCH_IFACE + os_free(params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ + os_free(params.pid_file); + + wpa_printf(MSG_INFO, "z_wpas_start: exitcode %d", exitcode); +} diff --git a/modules/hostap/src/supp_main.h b/modules/hostap/src/supp_main.h new file mode 100644 index 000000000000..ae4477dc70b0 --- /dev/null +++ b/modules/hostap/src/supp_main.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#ifndef __SUPP_MAIN_H_ +#define __SUPP_MAIN_H_ + +#include "wpa_supplicant_i.h" + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char *ifname); +struct wpa_supplicant_event_msg { + bool global; + void *ctx; + unsigned int event; + void *data; +}; +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg); +#endif /* __SUPP_MAIN_H_ */ diff --git a/modules/hostap/src/utils/wpa_debug.c b/modules/hostap/src/utils/wpa_debug.c new file mode 100644 index 000000000000..7d42857fae13 --- /dev/null +++ b/modules/hostap/src/utils/wpa_debug.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "wpa_debug.h" + +#include + +#define WPA_DEBUG_MAX_LINE_LENGTH 256 + +LOG_MODULE_REGISTER(wpa_supp, CONFIG_WPA_SUPP_LOG_LEVEL); + +int wpa_debug_level = MSG_INFO; +int wpa_debug_show_keys; +int wpa_debug_timestamp; + +#ifndef CONFIG_NO_STDOUT_DEBUG + +void wpa_printf_impl(int level, const char *fmt, ...) +{ + va_list ap; + char buffer[WPA_DEBUG_MAX_LINE_LENGTH]; + + if (level < wpa_debug_level) + return; + + va_start(ap, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + switch (level) { + case MSG_ERROR: + LOG_ERR("%s", buffer); + break; + case MSG_WARNING: + LOG_WRN("%s", buffer); + break; + case MSG_INFO: + LOG_INF("%s", buffer); + break; + case MSG_DEBUG: + case MSG_MSGDUMP: + case MSG_EXCESSIVE: + LOG_DBG("%s", buffer); + break; + default: + break; + } + + forced_memzero(buffer, sizeof(buffer)); +} + +static void _wpa_hexdump(int level, const char *title, const u8 *buf, size_t len, int show) +{ + size_t i; + const char *content; + char *content_buf = NULL; + + if (level < wpa_debug_level) + return; + + if (buf == NULL) { + content = " [NULL]"; + } else if (show) { + content = content_buf = os_malloc(3 * len + 1); + + if (content == NULL) { + wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to allocate message buffer"); + return; + } + + for (i = 0; i < len; i++) { + os_snprintf(&content_buf[i * 3], 4, " %02x", buf[i]); + } + } else { + content = " [REMOVED]"; + } + + wpa_printf(level, "%s - hexdump(len=%lu):%s", title, (unsigned long)len, content); + bin_clear_free(content_buf, 3 * len + 1); +} + +void wpa_hexdump_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, 1); +} + +void wpa_hexdump_key_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); +} + +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len, int show) +{ + const char *content; + + if (level < wpa_debug_level) { + return; + } + + if (buf == NULL) { + content = " [NULL]"; + } else if (show) { + content = ""; + } else { + content = " [REMOVED]"; + } + + wpa_printf(level, "%s - hexdump_ascii(len=%lu):%s", title, (unsigned long)len, content); + + if (buf == NULL || !show) { + return; + } + + switch (level) { + case MSG_ERROR: + LOG_HEXDUMP_ERR(buf, len, ""); + break; + case MSG_WARNING: + LOG_HEXDUMP_WRN(buf, len, ""); + break; + case MSG_INFO: + LOG_HEXDUMP_INF(buf, len, ""); + break; + case MSG_DEBUG: + case MSG_MSGDUMP: + case MSG_EXCESSIVE: + LOG_HEXDUMP_DBG(buf, len, ""); + break; + default: + break; + } +} + +void wpa_hexdump_ascii_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, 1); +} + +void wpa_hexdump_ascii_key_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); +} + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + +#ifndef CONFIG_NO_WPA_MSG + +static wpa_msg_cb_func wpa_msg_cb; + +void wpa_msg_register_cb(wpa_msg_cb_func func) +{ + wpa_msg_cb = func; +} + +static wpa_msg_get_ifname_func wpa_msg_ifname_cb; + +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) +{ + wpa_msg_ifname_cb = func; +} + +void wpa_msg_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + char prefix[130]; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + prefix[0] = '\0'; + if (wpa_msg_ifname_cb) { + const char *ifname = wpa_msg_ifname_cb(ctx); + + if (ifname) { + int res = os_snprintf(prefix, sizeof(prefix), "%s: ", ifname); + + if (os_snprintf_error(sizeof(prefix), res)) + prefix[0] = '\0'; + } + } + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s%s", prefix, buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_ctrl_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + if (!wpa_msg_cb) + return; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_ctrl_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + if (!wpa_msg_cb) + return; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_global_ctrl: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_no_global_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_only_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer", __func__); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len); + os_free(buf); +} + +#endif /* CONFIG_NO_WPA_MSG */ + +#ifndef CONFIG_NO_HOSTAPD_LOGGER + +static hostapd_logger_cb_func hostapd_logger_cb; + +void hostapd_logger_register_cb(hostapd_logger_cb_func func) +{ + hostapd_logger_cb = func; +} + +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + if (hostapd_logger_cb) + hostapd_logger_cb(ctx, addr, module, level, buf, len); + else if (addr) + wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", MAC2STR(addr), buf); + else + wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); + bin_clear_free(buf, buflen); +} + +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + +const char *debug_level_str(int level) +{ + switch (level) { + case MSG_EXCESSIVE: + return "EXCESSIVE"; + case MSG_MSGDUMP: + return "MSGDUMP"; + case MSG_DEBUG: + return "DEBUG"; + case MSG_INFO: + return "INFO"; + case MSG_WARNING: + return "WARNING"; + case MSG_ERROR: + return "ERROR"; + default: + return "?"; + } +} + +int str_to_debug_level(const char *s) +{ + if (os_strcasecmp(s, "EXCESSIVE") == 0) + return MSG_EXCESSIVE; + if (os_strcasecmp(s, "MSGDUMP") == 0) + return MSG_MSGDUMP; + if (os_strcasecmp(s, "DEBUG") == 0) + return MSG_DEBUG; + if (os_strcasecmp(s, "INFO") == 0) + return MSG_INFO; + if (os_strcasecmp(s, "WARNING") == 0) + return MSG_WARNING; + if (os_strcasecmp(s, "ERROR") == 0) + return MSG_ERROR; + return -1; +} diff --git a/modules/hostap/src/utils/wpa_debug.h b/modules/hostap/src/utils/wpa_debug.h new file mode 100644 index 000000000000..c065ffe467d0 --- /dev/null +++ b/modules/hostap/src/utils/wpa_debug.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + +#include + +#include + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + +enum { MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; + +/** + * wpa_debug_level_enabled - determine if the given priority level is enabled + * by compile-time configuration. + * + * @level: priority level of a message + */ +#define wpa_debug_level_enabled(level) (CONFIG_WPA_SUPP_DEBUG_LEVEL <= (level)) + +/** + * wpa_debug_cond_run - run the action if the given condition is met + * + * @cond: condition expression + * @action: action to run + */ +#define wpa_debug_cond_run(cond, action) \ + do { \ + if (cond) { \ + action; \ + } \ + } while (0) + + +#ifdef CONFIG_NO_STDOUT_DEBUG + +#define wpa_printf(args...) do { } while (0) +#define wpa_hexdump(l, t, b, e) do { } while (0) +#define wpa_hexdump_buf(l, t, b) do { } while (0) +#define wpa_hexdump_key(l, t, b, le) do { } while (0) +#define wpa_hexdump_buf_key(l, t, b) do { } while (0) +#define wpa_hexdump_ascii(l, t, b, le) do { } while (0) +#define wpa_hexdump_ascii_key(l, t, b, le) do { } while (0) +#define wpa_dbg(args...) do { } while (0) + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +/** + * wpa_printf - conditional printf + * + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. + */ +#define wpa_printf(level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_printf_impl(level, fmt, ##__VA_ARGS__)) + +void wpa_printf_impl(int level, const char *fmt, ...) PRINTF_FORMAT(2, 3); + +/** + * wpa_hexdump - conditional hex dump + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump. + */ +#define wpa_hexdump(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), wpa_hexdump_impl(level, title, buf, len)) + +void wpa_hexdump_impl(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) +{ + wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump. This works like wpa_hexdump(), but by default, does + * not include secret keys (passwords, etc.) in debug output. + */ +#define wpa_hexdump_key(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_key_impl(level, title, buf, len)) + +void wpa_hexdump_key_impl(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) +{ + wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump with both the hex numbers and ASCII characters (for + * printable range) shown. 16 bytes per line will be shown. + */ +#define wpa_hexdump_ascii(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_ascii_impl(level, title, buf, len)) + +void wpa_hexdump_ascii_impl(int level, const char *title, const void *buf, size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump with both the hex numbers and ASCII characters (for + * printable range) shown. 16 bytes per line will be shown. This works like + * wpa_hexdump_ascii(), but by default, does not include secret keys + * (passwords, etc.) in debug output. + */ +#define wpa_hexdump_ascii_key(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_ascii_key_impl(level, title, buf, len)); + +void wpa_hexdump_ascii_key_impl(int level, const char *title, const void *buf, size_t len); + +/* + * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce + * binary size. As such, it should be used with debugging messages that are not + * needed in the control interface while wpa_msg() has to be used for anything + * that needs to shown to control interface monitors. + */ +#define wpa_dbg(args...) wpa_msg(args) + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NO_WPA_MSG + +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_ctrl(args...) do { } while (0) +#define wpa_msg_global(args...) do { } while (0) +#define wpa_msg_global_ctrl(args...) do { } while (0) +#define wpa_msg_no_global(args...) do { } while (0) +#define wpa_msg_global_only(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) +#define wpa_msg_register_ifname_cb(f) do { } while (0) + +#else /* CONFIG_NO_WPA_MSG */ + +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. This function is like + * wpa_printf(), but it also sends the same message to all attached ctrl_iface + * monitors. + */ +#define wpa_msg(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +#define wpa_msg_ctrl(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_ctrl_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_ctrl_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global - Global printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output as a global event, + * i.e., without being specific to an interface. For backwards compatibility, + * an old style event is also delivered on one of the interfaces (the one + * specified by the context data). + */ +#define wpa_msg_global(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only to the + * attached global ctrl_iface monitors. In other words, it can be used for + * frequent events that do not need to be sent to syslog. + */ +#define wpa_msg_global_ctrl(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_ctrl_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_ctrl_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_no_global - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it does not send the output as a global + * event. + */ +#define wpa_msg_no_global(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_no_global_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_no_global_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_only - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only as a + * global event. + */ +#define wpa_msg_global_only(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_only_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_only_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +enum wpa_msg_type { + WPA_MSG_PER_INTERFACE, + WPA_MSG_GLOBAL, + WPA_MSG_NO_GLOBAL, + WPA_MSG_ONLY_GLOBAL, +}; + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, const char *txt, + size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); + +typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); + +#endif /* CONFIG_NO_WPA_MSG */ + + +#ifdef CONFIG_NO_HOSTAPD_LOGGER + +#define hostapd_logger(args...) do { } while (0) +#define hostapd_logger_register_cb(f) do { } while (0) + +#else /* CONFIG_NO_HOSTAPD_LOGGER */ + +#define HOSTAPD_MODULE_IEEE80211 0x00000001 +#define HOSTAPD_MODULE_IEEE8021X 0x00000002 +#define HOSTAPD_MODULE_RADIUS 0x00000004 +#define HOSTAPD_MODULE_WPA 0x00000008 +#define HOSTAPD_MODULE_DRIVER 0x00000010 +#define HOSTAPD_MODULE_MLME 0x00000040 + +enum hostapd_logger_level { + HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, + HOSTAPD_LEVEL_DEBUG = 1, + HOSTAPD_LEVEL_INFO = 2, + HOSTAPD_LEVEL_NOTICE = 3, + HOSTAPD_LEVEL_WARNING = 4 +}; + +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) + PRINTF_FORMAT(5, 6); + +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, unsigned int module, int level, + const char *txt, size_t len); + +/** + * hostapd_logger_register_cb - Register callback function for hostapd_logger() + * @func: Callback function (NULL to unregister) + */ +void hostapd_logger_register_cb(hostapd_logger_cb_func func); + +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + + +/* CONFIG_DEBUG_FILE is not supported by Zephyr */ + +static inline int wpa_debug_open_file(const char *path) { return 0; } +static inline int wpa_debug_reopen_file(void) { return 0; } +static inline void wpa_debug_close_file(void) {} +static inline void wpa_debug_setup_stdout(void) {} + + +/* CONFIG_DEBUG_SYSLOG is not supported by Zephyr */ + +static inline void wpa_debug_open_syslog(void) {} +static inline void wpa_debug_close_syslog(void) {} + + +/* CONFIG_DEBUG_LINUX_TRACING is not supported by Zephyr */ + +static inline int wpa_debug_open_linux_tracing(void) { return 0; } +static inline void wpa_debug_close_linux_tracing(void) {} + + +#ifdef EAPOL_TEST +#define WPA_ASSERT __ASSERT +#else +#define WPA_ASSERT(a) do {} while (0) +#endif + + +const char *debug_level_str(int level); +int str_to_debug_level(const char *s); + +#endif /* WPA_DEBUG_H */ diff --git a/modules/hostap/src/wpa_cli.c b/modules/hostap/src/wpa_cli.c new file mode 100644 index 000000000000..3ad1e5d9fb82 --- /dev/null +++ b/modules/hostap/src/wpa_cli.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* @file + * @brief wpa_cli implementation for Zephyr OS + */ + +#include +#include +#include + +#include "wpa_cli_zephyr.h" + +static int cmd_wpa_cli(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + ARG_UNUSED(sh); + + if (argc == 1) { + shell_error(sh, "Missing argument"); + return -EINVAL; + } + + /* Remove wpa_cli from the argument list */ + return z_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); +} + +/* Persisting with "wpa_cli" naming for compatibility with Wi-Fi + * certification applications and scripts. + */ +SHELL_CMD_REGISTER(wpa_cli, + NULL, + "wpa_cli commands (only for internal use)", + cmd_wpa_cli); diff --git a/subsys/net/l2_wifi_if_conn/l2_wifi_conn.c b/subsys/net/l2_wifi_if_conn/l2_wifi_conn.c index b0d98d2382a9..510aad127e27 100644 --- a/subsys/net/l2_wifi_if_conn/l2_wifi_conn.c +++ b/subsys/net/l2_wifi_if_conn/l2_wifi_conn.c @@ -12,7 +12,7 @@ LOG_MODULE_REGISTER(l2_wifi_mgr_conn); #include #include #include -#include +#include #include "conn_mgr_private.h" #define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_CONNECT_RESULT | \ diff --git a/west.yml b/west.yml index 293cd62d675a..32196708bd67 100644 --- a/west.yml +++ b/west.yml @@ -109,7 +109,7 @@ manifest: - name: hostap repo-path: sdk-hostap path: modules/lib/hostap - revision: 6921e3c211b70e8a7be6f342533a078a9b7ee87d + revision: 4b93835253587b3b4193db23689b585a118b75a9 userdata: ncs: upstream-url: https://w1.fi/cgit/hostap/