From a6811adac774ea52b2a0941c8d6bda39bf766dd8 Mon Sep 17 00:00:00 2001 From: Kapil Gupta Date: Fri, 13 May 2022 13:32:24 +0530 Subject: [PATCH] wpa_supplicant: Add WPS registrar support for softAP mode --- components/wpa_supplicant/CMakeLists.txt | 29 +- components/wpa_supplicant/Kconfig | 9 +- .../esp_supplicant/include/esp_wps.h | 59 +- .../esp_supplicant/src/esp_common.c | 1 + .../esp_supplicant/src/esp_hostap.c | 15 +- .../esp_supplicant/src/esp_hostpad_wps.c | 254 +++ .../esp_supplicant/src/esp_wpa_main.c | 82 +- .../esp_supplicant/src/esp_wpas_glue.c | 22 + .../esp_supplicant/src/esp_wpas_glue.h | 2 + .../esp_supplicant/src/esp_wps.c | 136 +- .../esp_supplicant/src/esp_wps_i.h | 45 + .../wpa_supplicant/include/utils/wpa_debug.h | 19 +- components/wpa_supplicant/src/ap/ap_config.h | 8 +- .../wpa_supplicant/src/ap/eap_user_db.c | 28 +- components/wpa_supplicant/src/ap/hostapd.h | 36 +- components/wpa_supplicant/src/ap/ieee802_1x.c | 421 ++++- components/wpa_supplicant/src/ap/ieee802_1x.h | 6 +- components/wpa_supplicant/src/ap/sta_info.c | 1375 +---------------- components/wpa_supplicant/src/ap/sta_info.h | 37 +- components/wpa_supplicant/src/ap/wpa_auth.c | 28 +- .../wpa_supplicant/src/ap/wps_hostapd.c | 586 +++++++ .../wpa_supplicant/src/ap/wps_hostapd.h | 22 +- .../src/common/ieee802_11_common.c | 33 + .../src/common/ieee802_11_common.h | 2 + .../wpa_supplicant/src/eap_peer/eap_defs.h | 45 +- .../wpa_supplicant/src/eap_server/eap.h | 6 +- .../wpa_supplicant/src/eap_server/eap_i.h | 4 +- .../src/eap_server/eap_methods.h | 2 +- .../src/eap_server/eap_server.c | 22 +- .../src/eap_server/eap_server_identity.c | 2 +- .../src/eap_server/eap_server_wsc.c | 100 +- .../src/eapol_auth/eapol_auth_sm.c | 27 +- .../src/eapol_auth/eapol_auth_sm_i.h | 4 +- components/wpa_supplicant/src/wps/wps.c | 5 +- components/wpa_supplicant/src/wps/wps.h | 6 +- .../wpa_supplicant/src/wps/wps_enrollee.c | 17 +- .../wpa_supplicant/src/wps/wps_registrar.c | 57 +- 37 files changed, 1812 insertions(+), 1740 deletions(-) create mode 100644 components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c create mode 100644 components/wpa_supplicant/src/ap/wps_hostapd.c diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 702d9aa000..140bcb8169 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -4,6 +4,7 @@ set(srcs "port/os_xtensa.c" "src/ap/ieee802_1x.c" "src/ap/wpa_auth.c" "src/ap/wpa_auth_ie.c" + "src/ap/sta_info.c" "src/common/sae.c" "src/common/wpa_common.c" "src/utils/bitfield.c" @@ -24,6 +25,7 @@ set(srcs "port/os_xtensa.c" "src/crypto/md4-internal.c" "src/crypto/sha1-tprf.c" "src/eap_common/eap_wsc_common.c" + "src/common/ieee802_11_common.c" "src/eap_peer/chap.c" "src/eap_peer/eap.c" "src/eap_peer/eap_common.c" @@ -54,7 +56,6 @@ set(srcs "port/os_xtensa.c" "src/wps/wps_common.c" "src/wps/wps_dev_attr.c" "src/wps/wps_enrollee.c") -# "src/wps/wps_registrar.c") set(esp_srcs "esp_supplicant/src/esp_wpa2.c" "esp_supplicant/src/esp_wpa_main.c" @@ -176,8 +177,23 @@ else() set(dpp_src "") endif() -idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" - "${crypto_src}" "${mbo_src}" "${dpp_src}" +if(CONFIG_WPA_WPS_SOFTAP_REGISTRAR) + set(wps_registrar_src + "src/ap/wps_hostapd.c" + "src/eap_server/eap_server.c" + "src/eap_server/eap_server_methods.c" + "src/eap_server/eap_server_wsc.c" + "src/ap/eap_user_db.c" + "src/eapol_auth/eapol_auth_sm.c" + "src/eap_server/eap_server_identity.c" + "esp_supplicant/src/esp_hostpad_wps.c" + "src/wps/wps_registrar.c") +else() + set(wps_registrar_src "") +endif() + +idf_component_register(SRCS "${srcs}" "${esp_srcs}" "${tls_src}" "${roaming_src}" + "${crypto_src}" "${mbo_src}" "${dpp_src}" "${wps_registrar_src}" INCLUDE_DIRS include port/include esp_supplicant/include PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src src/crypto PRIV_REQUIRES mbedtls esp_timer) @@ -193,14 +209,14 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE EAP_TLS EAP_PEAP USE_WPA2_TASK - CONFIG_WPS2 - CONFIG_WPS_PIN + CONFIG_WPS USE_WPS_TASK ESPRESSIF_USE ESP32_WORKAROUND CONFIG_ECC CONFIG_IEEE80211W CONFIG_SHA256 + CONFIG_NO_RADIUS ) if(CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE) @@ -242,4 +258,7 @@ if(CONFIG_WPA_MBEDTLS_CRYPTO) else() target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_CRYPTO_INTERNAL) endif() +if(CONFIG_WPA_WPS_SOFTAP_REGISTRAR) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_REGISTRAR) +endif() set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3) diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig index 5501c47906..f4a3fdf410 100644 --- a/components/wpa_supplicant/Kconfig +++ b/components/wpa_supplicant/Kconfig @@ -105,9 +105,16 @@ menu "Supplicant" Select this option to enable WiFi Easy Connect Support. config WPA_11R_SUPPORT - bool "Enable 802.11R (Fast Transition)" + bool "Enable 802.11R (Fast Transition) Support" default n help Select this option to enable WiFi Fast Transition Support. + config WPA_WPS_SOFTAP_REGISTRAR + bool "Add WPS Registrar support in SoftAP mode" + depends on ESP_WIFI_SOFTAP_SUPPORT + default n + help + Select this option to enable WPS registrar support in softAP mode. + endmenu diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_wps.h b/components/wpa_supplicant/esp_supplicant/include/esp_wps.h index ef885eb802..3b5af6a031 100644 --- a/components/wpa_supplicant/esp_supplicant/include/esp_wps.h +++ b/components/wpa_supplicant/esp_supplicant/include/esp_wps.h @@ -25,13 +25,6 @@ extern "C" { * @{ */ -/** \defgroup WPS_APIs WPS APIs - * @brief ESP32 WPS APIs - * - * WPS can only be used when ESP32 station is enabled. - * - */ - /** @addtogroup WPS_APIs * @{ */ @@ -59,9 +52,11 @@ typedef struct { char device_name[WPS_MAX_DEVICE_NAME_LEN]; /*!< Device name, null-terminated string. The default device name is used if the string is empty */ } wps_factory_information_t; +#define PIN_LEN 9 typedef struct { wps_type_t wps_type; wps_factory_information_t factory_info; + char pin[PIN_LEN]; } esp_wps_config_t; #define WPS_CONFIG_INIT_DEFAULT(type) { \ @@ -70,14 +65,15 @@ typedef struct { ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(manufacturer, "ESPRESSIF") \ ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(model_number, "ESP32") \ ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(model_name, "ESPRESSIF IOT") \ - ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(device_name, "ESP STATION") \ - } \ + ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(device_name, "ESP DEVICE") \ + }, \ + ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_STR(pin, "00000000") \ } /** * @brief Enable Wi-Fi WPS function. * - * @attention WPS can only be used when ESP32 station is enabled. + * @attention WPS can only be used when station is enabled. * * @param wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported * @@ -103,7 +99,7 @@ esp_err_t esp_wifi_wps_disable(void); /** * @brief WPS starts to work. * - * @attention WPS can only be used when ESP32 station is enabled. + * @attention WPS can only be used when station is enabled. * * @param timeout_ms : maximum blocking time before API return. * - 0 : non-blocking @@ -118,6 +114,47 @@ esp_err_t esp_wifi_wps_disable(void); */ esp_err_t esp_wifi_wps_start(int timeout_ms); +/** + * @brief Enable Wi-Fi AP WPS function. + * + * @attention WPS can only be used when softAP is enabled. + * + * @param wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + * - ESP_FAIL : wps initialization fails + */ +esp_err_t esp_wifi_ap_wps_enable(const esp_wps_config_t *config); + +/** + * @brief Disable Wi-Fi SoftAP WPS function and release resource it taken. + * + * @param null + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + */ +esp_err_t esp_wifi_ap_wps_disable(void); + +/** + * @brief WPS starts to work. + * + * @attention WPS can only be used when softAP is enabled. + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid + * - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on + * - ESP_ERR_WIFI_WPS_SM : wps state machine is not initialized + * - ESP_FAIL : wps initialization fails + */ +esp_err_t esp_wifi_ap_wps_start(const unsigned char *pin); + + /** * @} */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_common.c b/components/wpa_supplicant/esp_supplicant/src/esp_common.c index 93d5e0ae73..89fbb02cf7 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_common.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_common.c @@ -866,6 +866,7 @@ void esp_set_scan_ie(void) { } void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool mdie) { } int esp_supplicant_common_init(struct wpa_funcs *wpa_cb) { + wpa_cb->wpa_sta_rx_mgmt = NULL; return 0; } void esp_supplicant_common_deinit(void) { } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c index d0d37731bd..1b3a6db832 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostap.c @@ -18,12 +18,18 @@ #include "esp_wifi_driver.h" #include "esp_wifi_types.h" +struct hostapd_data *global_hapd; + +struct hostapd_data *hostapd_get_hapd_data(void) +{ + return global_hapd; +} + void *hostap_init(void) { struct wifi_ssid *ssid = esp_wifi_ap_get_prof_ap_ssid_internal(); struct hostapd_data *hapd = NULL; struct wpa_auth_config *auth_conf; - u8 mac[6]; u16 spp_attrubute = 0; u8 pairwise_cipher; wifi_pmf_config_t pmf_cfg; @@ -40,6 +46,7 @@ void *hostap_init(void) os_free(hapd); return NULL; } + hapd->conf->max_num_sta = MAX_STA_COUNT; auth_conf = (struct wpa_auth_config *)os_zalloc(sizeof(struct wpa_auth_config)); @@ -122,11 +129,12 @@ void *hostap_init(void) hapd->conf->ap_max_inactivity = 5 * 60; hostapd_setup_wpa_psk(hapd->conf); - esp_wifi_get_macaddr_internal(WIFI_IF_AP, mac); + esp_wifi_get_macaddr_internal(WIFI_IF_AP, hapd->own_addr); - hapd->wpa_auth = wpa_init(mac, auth_conf, NULL); + hapd->wpa_auth = wpa_init(hapd->own_addr, auth_conf, NULL); esp_wifi_set_appie_internal(WIFI_APPIE_WPA, hapd->wpa_auth->wpa_ie, (uint16_t)hapd->wpa_auth->wpa_ie_len, 0); os_free(auth_conf); + global_hapd = hapd; return (void *)hapd; } @@ -161,6 +169,7 @@ bool hostap_deinit(void *data) os_free(hapd); esp_wifi_unset_appie_internal(WIFI_APPIE_WPA); + global_hapd = NULL; return true; } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c new file mode 100644 index 0000000000..72344af8fd --- /dev/null +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c @@ -0,0 +1,254 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "utils/common.h" + +#include "rsn_supp/wpa.h" +#include "common/eapol_common.h" +#include "utils/wpa_debug.h" +#include "common/ieee802_11_defs.h" +#include "wps/wps_i.h" +#include "wps/wps_dev_attr.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" +#include "esp_wifi_driver.h" +#include "esp_event.h" +#include "esp_wifi.h" +#include "esp_err.h" +#include "esp_private/wifi.h" +#include "esp_wps.h" +#include "esp_wps_i.h" +#include "eap_common/eap_wsc_common.h" +#include "esp_wpas_glue.h" +#include "ap/hostapd.h" +#include "ap/ap_config.h" +#include "ap/wps_hostapd.h" + +extern struct wps_sm *gWpsSm; +extern void *s_wps_api_lock; +extern void *s_wps_api_sem; +extern bool s_wps_enabled; + +static int wifi_ap_wps_init(void) +{ + struct wps_sm *sm = NULL; + uint8_t mac[ETH_ALEN]; + struct wps_config cfg = {0}; + + if (gWpsSm) { + goto _out; + } + + wpa_printf(MSG_DEBUG, "wifi wps init"); + + gWpsSm = os_zalloc(sizeof(struct wps_sm)); /* alloc Wps_sm */ + if (!gWpsSm) { + goto _out; + } + + sm = gWpsSm; + + esp_wifi_get_macaddr_internal(WIFI_IF_AP, mac); + os_memcpy(sm->ownaddr, mac, ETH_ALEN); + + sm->identity_len = WSC_ID_REGISTRAR_LEN; + os_memcpy(sm->identity, WSC_ID_REGISTRAR, sm->identity_len); + + sm->wps_ctx = os_zalloc(sizeof(struct wps_context)); /* alloc wps_ctx */ + if (!sm->wps_ctx) { + goto _err; + } + + if (wps_dev_init() != 0) { + goto _err; + } + + cfg.registrar = 1; + cfg.wps = sm->wps_ctx; + + wps_init_cfg_pin(&cfg); + os_memcpy(cfg.wps->uuid, sm->uuid, WPS_UUID_LEN); + if ((sm->wps = wps_init(&cfg)) == NULL) { /* alloc wps_data */ + goto _err; + } + + hostapd_init_wps(hostapd_get_hapd_data(), sm->wps, sm->wps_ctx); + return ESP_OK; + +_err: + if (sm->dev) { + wps_dev_deinit(sm->dev); + sm->dev = NULL; + } + if (sm->wps_ctx) { + os_free(sm->wps_ctx); + sm->wps_ctx = NULL; + } + if (sm->wps) { + wps_deinit(sm->wps); + sm->wps = NULL; + } + os_free(gWpsSm); + gWpsSm = NULL; + return ESP_FAIL; +_out: + return ESP_FAIL; +} + +int wifi_ap_wps_deinit(void) +{ + struct wps_sm *sm = gWpsSm; + + hostapd_deinit_wps(hostapd_get_hapd_data()); + if (gWpsSm == NULL) { + return ESP_FAIL; + } + + if (sm->dev) { + wps_dev_deinit(sm->dev); + sm->dev = NULL; + } + if (sm->wps_ctx) { + os_free(sm->wps_ctx); + sm->wps_ctx = NULL; + } + if (sm->wps) { + wps_deinit(sm->wps); + sm->wps = NULL; + } + os_free(gWpsSm); + gWpsSm = NULL; + + return ESP_OK; +} + +int wifi_ap_wps_enable_internal(const esp_wps_config_t *config) +{ + int ret = 0; + + wpa_printf(MSG_DEBUG, "ESP WPS crypto initialize!"); + if (config->wps_type == WPS_TYPE_DISABLE) { + wpa_printf(MSG_ERROR, "wps enable: invalid wps type"); + return ESP_ERR_WIFI_WPS_TYPE; + } + + wpa_printf(MSG_DEBUG, "Set factory information."); + ret = wps_set_factory_info(config); + if (ret != 0) { + return ret; + } + + wpa_printf(MSG_INFO, "wifi_wps_enable\n"); + + wps_set_type(config->wps_type); + wps_set_status(WPS_STATUS_DISABLE); + + ret = wifi_ap_wps_init(); + + if (ret != 0) { + wps_set_type(WPS_STATUS_DISABLE); + wps_set_status(WPS_STATUS_DISABLE); + return ESP_FAIL; + } + + return ESP_OK; +} + +int esp_wifi_ap_wps_enable(const esp_wps_config_t *config) +{ + int ret; + wifi_mode_t mode = WIFI_MODE_NULL; + + ret = esp_wifi_get_mode(&mode); + if (mode != WIFI_MODE_AP) { + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + if (s_wps_enabled) { + API_MUTEX_GIVE(); + wpa_printf(MSG_DEBUG, "wps enable: already enabled"); + return ESP_OK; + } + + ret = wifi_ap_wps_enable_internal(config); + s_wps_enabled = true; + API_MUTEX_GIVE(); + return ret; +} + +int esp_wifi_ap_wps_disable(void) +{ + int ret = 0; + wifi_mode_t mode = WIFI_MODE_NULL; + + ret = esp_wifi_get_mode(&mode); + if (mode != WIFI_MODE_AP) { + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + + if (!s_wps_enabled) { + wpa_printf(MSG_DEBUG, "wps disable: already disabled"); + API_MUTEX_GIVE(); + return ESP_OK; + } + + wpa_printf(MSG_INFO, "wifi_wps_disable"); + wps_set_status(WPS_STATUS_DISABLE); + wps_set_type(WPS_TYPE_DISABLE); + + wifi_ap_wps_deinit(); + + if (ESP_OK != ret) { + wpa_printf(MSG_ERROR, "wps disable: failed to disable wps, ret=%d", ret); + } + + s_wps_enabled = false; + API_MUTEX_GIVE(); + return ESP_OK; +} + +int esp_wifi_ap_wps_start(const unsigned char *pin) +{ + wifi_mode_t mode = WIFI_MODE_NULL; + + esp_wifi_get_mode(&mode); + if (mode != WIFI_MODE_AP) { + wpa_printf(MSG_ERROR, "wps start: mode=%d is not AP", mode); + return ESP_ERR_WIFI_MODE; + } + + API_MUTEX_TAKE(); + + if (!s_wps_enabled) { + wpa_printf(MSG_ERROR, "wps start: wps not enabled"); + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_WPS_SM; + } + + if (wps_get_type() == WPS_TYPE_DISABLE || (wps_get_status() != WPS_STATUS_DISABLE && wps_get_status() != WPS_STATUS_SCANNING)) { + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_WPS_TYPE; + } + + if (esp_wifi_get_user_init_flag_internal() == 0) { + API_MUTEX_GIVE(); + return ESP_ERR_WIFI_STATE; + } + + /* TODO ideally SoftAP mode should also do a single scan in PBC mode + * however softAP scanning is not available at the moment */ + wps_set_status(WPS_STATUS_PENDING); + if (wps_get_type() == WPS_TYPE_PBC) { + hostapd_wps_button_pushed(hostapd_get_hapd_data(), NULL); + } else if (wps_get_type() == WPS_TYPE_PIN) { + hostapd_wps_add_pin(hostapd_get_hapd_data(), pin); + } + API_MUTEX_GIVE(); + return ESP_OK; +} diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 8d8856cebf..f8e8f3bc18 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -11,6 +11,7 @@ #include "rsn_supp/wpa_i.h" #include "common/eapol_common.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "rsn_supp/wpa_ie.h" #include "ap/wpa_auth.h" #include "ap/wpa_auth_i.h" @@ -30,6 +31,13 @@ #include "esp_wpa2.h" #include "esp_common_i.h" +#include "esp_wps.h" +#include "eap_server/eap.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "ap/ieee802_1x.h" +#include "ap/sta_info.h" +#include "wps/wps_defs.h" + void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, enum key_flag key_flag) { @@ -134,16 +142,24 @@ uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len) return hapd->wpa_auth->wpa_ie; } -bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len) +bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len) { struct hostapd_data *hapd = (struct hostapd_data *)hapd_data; - struct wpa_state_machine *sm = (struct wpa_state_machine *)sm_data; - - if (!hapd || !sm) { + struct sta_info *sta = (struct sta_info *)sm_data; + if (!hapd || !sta) { + wpa_printf(MSG_DEBUG, "hapd=%p sta=%p", hapd, sta); return false; } +#ifdef CONFIG_WPS_REGISTRAR + int wps_type = esp_wifi_get_wps_type_internal(); - wpa_receive(hapd->wpa_auth, sm, data, data_len); + if ((wps_type == WPS_TYPE_PBC) || + (wps_type == WPS_TYPE_PIN)) { + ieee802_1x_receive(hapd, sta->addr, data, data_len); + return true; + } +#endif + wpa_receive(hapd->wpa_auth, sta->wpa_sm, data, data_len); return true; } @@ -226,6 +242,60 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) } } +#ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT + +#ifdef CONFIG_WPS_REGISTRAR +static int check_n_add_wps_sta(struct hostapd_data *hapd, struct sta_info *sta_info, u8 *ies, u8 ies_len, bool *pmf_enable) +{ + struct wpabuf *wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA); + int wps_type = esp_wifi_get_wps_type_internal(); + + /* Condition for this, WPS is running and WPS IEs are part of assoc req */ + if (!wps_ie || (wps_type == WPS_TYPE_DISABLE)) { + return 0; + } + + sta_info->wps_ie = wps_ie; + sta_info->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta_info); + + if (sta_info->eapol_sm) { + wpa_printf(MSG_DEBUG, "considering station " MACSTR " for WPS", MAC2STR(sta_info->addr)); + return 1; + } + + return 0; +} +#endif + +static bool hostap_sta_join(void **sm, u8 *bssid, u8 *wpa_ie, u8 wpa_ie_len, bool *pmf_enable) +{ + struct sta_info *sta_info; + struct hostapd_data *hapd = hostapd_get_hapd_data(); + + if (!hapd) { + return 0; + } + sta_info = ap_sta_add(hapd, bssid); + if (!sta_info) { + wpa_printf(MSG_ERROR, "failed to add station " MACSTR, MAC2STR(bssid)); + return 0; + } +#ifdef CONFIG_WPS_REGISTRAR + if (check_n_add_wps_sta(hapd, sta_info, wpa_ie, wpa_ie_len, pmf_enable)) { + *sm = sta_info; + return true; + } +#endif + if (wpa_ap_join(sm, bssid, wpa_ie, wpa_ie_len, pmf_enable)) { + sta_info->wpa_sm = *sm; + *sm = sta_info; + return true; + } + + return false; +} +#endif + int esp_supplicant_init(void) { int ret = ESP_OK; @@ -244,7 +314,7 @@ int esp_supplicant_init(void) wpa_cb->wpa_sta_in_4way_handshake = wpa_sta_in_4way_handshake; #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT - wpa_cb->wpa_ap_join = wpa_ap_join; + wpa_cb->wpa_ap_join = hostap_sta_join; wpa_cb->wpa_ap_remove = wpa_ap_remove; wpa_cb->wpa_ap_get_wpa_ie = wpa_ap_get_wpa_ie; wpa_cb->wpa_ap_rx_eapol = wpa_ap_rx_eapol; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c index aeb7bb8c6c..e37b78cec1 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c @@ -73,6 +73,28 @@ int wpa_ether_send(void *ctx, const u8 *dest, u16 proto, return ESP_OK; } +int hostapd_send_eapol(const u8 *source, const u8 *sta_addr, + const u8 *data, size_t data_len) +{ + void *buffer = os_malloc(data_len + sizeof(struct l2_ethhdr)); + struct l2_ethhdr *eth = buffer; + + if (!buffer){ + wpa_printf( MSG_DEBUG, "send_eapol, buffer=%p\n", buffer); + return -1; + } + + memcpy(eth->h_dest, sta_addr, ETH_ALEN); + memcpy(eth->h_source, source, ETH_ALEN); + eth->h_proto = host_to_be16(ETH_P_EAPOL); + + memcpy((char *)buffer + sizeof(struct l2_ethhdr), data, data_len); + esp_wifi_internal_tx(WIFI_IF_AP, buffer, sizeof(struct l2_ethhdr) + data_len); + os_free(buffer); + return 0; + +} + u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h b/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h index 7d702314dd..220a01c633 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h @@ -31,4 +31,6 @@ void wpa_free_eapol(u8 *buffer); int wpa_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *data, size_t data_len); +int hostapd_send_eapol(const u8 *source, const u8 *sta_addr, + const u8 *data, size_t data_len); #endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c index 3e040fe694..3adf996e6f 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c @@ -31,25 +31,12 @@ #include "eap_common/eap_wsc_common.h" #include "esp_wpas_glue.h" -#define API_MUTEX_TAKE() do {\ - if (!s_wps_api_lock) {\ - s_wps_api_lock = xSemaphoreCreateRecursiveMutex();\ - if (!s_wps_api_lock) {\ - wpa_printf(MSG_ERROR, "wps api lock create failed");\ - return ESP_ERR_NO_MEM;\ - }\ - }\ - xSemaphoreTakeRecursive(s_wps_api_lock, portMAX_DELAY);\ -} while(0) - -#define API_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_api_lock) -#define DATA_MUTEX_TAKE() xSemaphoreTakeRecursive(s_wps_data_lock, portMAX_DELAY) -#define DATA_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_data_lock) - -#define WPS_ADDR_LEN 6 +void *s_wps_api_lock = NULL; /* Used in WPS public API only, never be freed */ +void *s_wps_api_sem = NULL; /* Sync semaphore used between WPS publi API caller task and WPS task */ +bool s_wps_enabled = false; #ifdef USE_WPS_TASK struct wps_rx_param { - u8 sa[WPS_ADDR_LEN]; + u8 sa[ETH_ALEN]; u8 *buf; int len; STAILQ_ENTRY(wps_rx_param) bqentry; @@ -63,11 +50,8 @@ typedef struct { static TaskHandle_t s_wps_task_hdl = NULL; static void *s_wps_queue = NULL; -static void *s_wps_api_lock = NULL; /* Used in WPS public API only, never be freed */ -static void *s_wps_api_sem = NULL; /* Sync semaphore used between WPS publi API caller task and WPS task */ static void *s_wps_data_lock = NULL; static void *s_wps_task_create_sem = NULL; -static bool s_wps_enabled = false; static uint8_t s_wps_sig_cnt[SIG_WPS_NUM] = {0}; #endif @@ -89,31 +73,6 @@ void wps_add_discard_ap(u8 *bssid); struct wps_sm *gWpsSm = NULL; static wps_factory_information_t *s_factory_info = NULL; -#ifdef CONFIG_WPS_TESTING -int wps_version_number = 0x20; -int wps_testing_dummy_cred = 0; -#endif /* CONFIG_WPS_TESTING */ - -int wps_get_type(void) -{ - return esp_wifi_get_wps_type_internal(); -} - -int wps_set_type(uint32_t type) -{ - return esp_wifi_set_wps_type_internal(type); -} - -int wps_get_status(void) -{ - return esp_wifi_get_wps_status_internal(); -} - -int wps_set_status(uint32_t status) -{ - return esp_wifi_set_wps_status_internal(status); -} - static void wps_rxq_init(void) { DATA_MUTEX_TAKE(); @@ -395,7 +354,7 @@ wps_parse_scan_result(struct wps_scan_ie *scan) } if (!scan->rsn && !scan->wpa && (scan->capinfo & WLAN_CAPABILITY_PRIVACY)) { - wpa_printf(MSG_INFO, "WEP not suppported in WPS"); + wpa_printf(MSG_DEBUG, "WEP not suppported in WPS"); return false; } @@ -916,7 +875,7 @@ int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len) } os_memcpy(param->buf, buf, len); param->len = len; - os_memcpy(param->sa, src_addr, WPS_ADDR_LEN); + os_memcpy(param->sa, src_addr, ETH_ALEN); wps_rxq_enqueue(param); return wps_post(SIG_WPS_RX, 0); @@ -1041,7 +1000,7 @@ int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len) tmp = (u8 *)(ehdr + 1) + 1; ret = wps_process_wps_mX_req(tmp, plen - sizeof(*ehdr) - 1, &res); - if (ret == 0 && res != WPS_FAILURE && res != WPS_IGNORE && res != WPS_FRAGMENT) { + if (ret == 0 && res != WPS_FAILURE && res != WPS_FRAGMENT) { ret = wps_send_wps_mX_rsp(ehdr->identifier); if (ret == 0) { wpa_printf(MSG_DEBUG, "sm->wps->state = %d", sm->wps->state); @@ -1050,9 +1009,6 @@ int wps_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len) } else if (ret == 0 && res == WPS_FRAGMENT) { wpa_printf(MSG_DEBUG, "wps frag, continue..."); ret = ESP_OK; - } else if (res == WPS_IGNORE) { - wpa_printf(MSG_DEBUG, "IGNORE overlap Mx"); - ret = ESP_OK; /* IGNORE the overlap */ } else { ret = ESP_FAIL; } @@ -1382,12 +1338,32 @@ static int save_credentials_cb(void *ctx, const struct wps_credential *cred) return ESP_OK; } +int wps_init_cfg_pin(struct wps_config *cfg) +{ + if (wps_get_type() != WPS_TYPE_PIN) { + cfg->pbc = 1; + return 0; + } + + cfg->pbc = 0; + if (os_strncmp((char *)cfg->pin, "00000000", 8) != 0) { + unsigned int spin = 0; + cfg->dev_pw_id = DEV_PW_DEFAULT; + cfg->pin_len = 8; + if (wps_generate_pin(&spin) < 0) { + return -1; + } + os_sprintf((char *)cfg->pin, "%08d", spin); + } + + return 0; +} + int wifi_station_wps_init(void) { struct wps_funcs *wps_cb; struct wps_sm *sm = NULL; - uint8_t mac[6]; struct wps_config cfg = {0}; if (gWpsSm) { @@ -1403,8 +1379,7 @@ wifi_station_wps_init(void) sm = gWpsSm; - esp_wifi_get_macaddr_internal(WIFI_IF_STA, mac); - os_memcpy(sm->ownaddr, mac, ETH_ALEN); + esp_wifi_get_macaddr_internal(WIFI_IF_STA, sm->ownaddr); sm->identity_len = WSC_ID_ENROLLEE_LEN; os_memcpy(sm->identity, WSC_ID_ENROLLEE, sm->identity_len); @@ -1419,34 +1394,17 @@ wifi_station_wps_init(void) } cfg.wps = sm->wps_ctx; - if (IS_WPS_REGISTRAR(wps_get_type())) { - cfg.registrar = 1; - } - - /* TODO add for Registrar */ - if (wps_get_type() == WPS_TYPE_PIN) { - unsigned int spin = 0; - cfg.dev_pw_id = DEV_PW_DEFAULT; - cfg.pin_len = 8; - cfg.pin = os_zalloc(cfg.pin_len + 1); - if (!cfg.pin) { - goto _err; - } - if (wps_generate_pin(&spin) < 0) { - goto _err; - } - os_sprintf((char *)cfg.pin, "%08d", spin); - } else if (wps_get_type() == WPS_TYPE_PBC) { - cfg.pbc = 1; + + if (wps_init_cfg_pin(&cfg) < 0) { + goto _err; } + os_memcpy(cfg.wps->uuid, sm->uuid, WPS_UUID_LEN); if ((sm->wps = wps_init(&cfg)) == NULL) { /* alloc wps_data */ goto _err; } - if (cfg.pin) { - os_free((u8 *)cfg.pin); - } + /* Report PIN */ if (wps_get_type() == WPS_TYPE_PIN) { wifi_event_sta_wps_er_pin_t evt; os_memcpy(evt.pin_code, sm->wps->dev_password, 8); @@ -1478,13 +1436,12 @@ wifi_station_wps_init(void) wps_cb = os_malloc(sizeof(struct wps_funcs)); if (wps_cb == NULL) { goto _err; - } else { - wps_cb->wps_parse_scan_result = wps_parse_scan_result; - wps_cb->wifi_station_wps_start = wifi_station_wps_start; - wps_cb->wps_sm_rx_eapol = wps_sm_rx_eapol; - wps_cb->wps_start_pending = wps_start_pending; - esp_wifi_set_wps_cb_internal(wps_cb); } + wps_cb->wps_parse_scan_result = wps_parse_scan_result; + wps_cb->wifi_station_wps_start = wifi_station_wps_start; + wps_cb->wps_sm_rx_eapol = wps_sm_rx_eapol; + wps_cb->wps_start_pending = wps_start_pending; + esp_wifi_set_wps_cb_internal(wps_cb); return ESP_OK; @@ -1647,6 +1604,11 @@ void wifi_wps_scan(void) #endif } +static int wps_rf_band_cb(void *ctx) +{ + return WPS_RF_24GHZ; +} + int wifi_station_wps_start(void) { struct wps_sm *sm = wps_sm_get(); @@ -1666,7 +1628,7 @@ int wifi_station_wps_start(void) sm->wps->wps->dh_privkey = wpabuf_dup(sm->wps->dh_privkey); sm->wps->wps->dh_ctx = sm->wps->dh_ctx; sm->wps->wps->dh_pubkey = sm->wps->dh_pubkey_e; - sm->wps->wps->rf_band_cb = NULL; + sm->wps->wps->rf_band_cb = wps_rf_band_cb; wpabuf_clear_free(sm->wps->dh_privkey); sm->wps->dh_privkey = NULL; wifi_wps_scan(); @@ -1872,12 +1834,6 @@ int wifi_wps_enable_internal(const esp_wps_config_t *config) return ESP_ERR_WIFI_WPS_TYPE; } - /* currently , we don't support REGISTRAR */ - if (IS_WPS_REGISTRAR(config->wps_type)) { - wpa_printf(MSG_ERROR, "wps enable: not support registrar"); - return ESP_ERR_WIFI_WPS_TYPE; - } - wpa_printf(MSG_DEBUG, "Set factory information."); ret = wps_set_factory_info(config); if (ret != 0) { @@ -1974,13 +1930,11 @@ int esp_wifi_wps_start(int timeout_ms) } wpa_printf(MSG_DEBUG, "wps scan"); - #ifdef USE_WPS_TASK wps_post_block(SIG_WPS_START, 0); #else ic_pp_post(SIG_PP_WPS, 0); #endif - API_MUTEX_GIVE(); return ESP_OK; } diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h index 945fd489b8..d397f00837 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_wifi_driver.h" +#include "esp_wps.h" + /* WPS message flag */ enum wps_msg_flag { WPS_MSG_FLAG_MORE = 0x01, @@ -38,6 +41,10 @@ struct discard_ap_list_t{ #define MAX_PASSPHRASE_LEN 64 #endif +#ifndef MAX_CRED_COUNT +#define MAX_CRED_COUNT 10 +#endif + #define WPS_OUTBUF_SIZE 500 struct wps_sm { struct wps_config *wps_cfg; @@ -72,9 +79,47 @@ struct wps_sm { u8 discard_ap_cnt; }; +#define API_MUTEX_TAKE() do {\ + if (!s_wps_api_lock) {\ + s_wps_api_lock = xSemaphoreCreateRecursiveMutex();\ + if (!s_wps_api_lock) {\ + wpa_printf(MSG_ERROR, "wps api lock create failed");\ + return ESP_ERR_NO_MEM;\ + }\ + }\ + xSemaphoreTakeRecursive(s_wps_api_lock, portMAX_DELAY);\ +} while(0) + +#define API_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_api_lock) +#define DATA_MUTEX_TAKE() xSemaphoreTakeRecursive(s_wps_data_lock, portMAX_DELAY) +#define DATA_MUTEX_GIVE() xSemaphoreGiveRecursive(s_wps_data_lock) + struct wps_sm *wps_sm_get(void); int wps_station_wps_unregister_cb(void); int wps_start_pending(void); int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); int wps_dev_deinit(struct wps_device_data *dev); +int wps_dev_init(void); +int wps_set_factory_info(const esp_wps_config_t *config); + +static inline int wps_get_type(void) +{ + return esp_wifi_get_wps_type_internal(); +} + +static inline int wps_set_type(uint32_t type) +{ + return esp_wifi_set_wps_type_internal(type); +} + +static inline int wps_get_status(void) +{ + return esp_wifi_get_wps_status_internal(); +} + +static inline int wps_set_status(uint32_t status) +{ + return esp_wifi_set_wps_status_internal(status); +} +int wps_init_cfg_pin(struct wps_config *cfg); diff --git a/components/wpa_supplicant/include/utils/wpa_debug.h b/components/wpa_supplicant/include/utils/wpa_debug.h index 4664975e15..02f1fb4f4e 100644 --- a/components/wpa_supplicant/include/utils/wpa_debug.h +++ b/components/wpa_supplicant/include/utils/wpa_debug.h @@ -65,14 +65,6 @@ void wpa_debug_print_timestamp(void); #define wpa_dbg(ctx, level, fmt, args...) wpa_printf(level, fmt, ##args) void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len); -static inline void wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len) -{ - -} - -static inline void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len) -{ -} /** * wpa_hexdump - conditional hex dump @@ -87,6 +79,16 @@ static inline void wpa_hexdump_ascii_key(int level, const char *title, const voi */ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); +static inline void wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len) +{ + wpa_hexdump(level, title, buf, len); +} + +static inline void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len) +{ + wpa_hexdump(level, title, buf, len); +} + static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) { @@ -108,7 +110,6 @@ static inline void wpa_hexdump_buf(int level, const char *title, */ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); - static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) { diff --git a/components/wpa_supplicant/src/ap/ap_config.h b/components/wpa_supplicant/src/ap/ap_config.h index 71d9be9091..62b4c423aa 100644 --- a/components/wpa_supplicant/src/ap/ap_config.h +++ b/components/wpa_supplicant/src/ap/ap_config.h @@ -12,7 +12,7 @@ #include "common/defs.h" #include "common/wpa_common.h" -#define MAX_STA_COUNT 4 +#define MAX_STA_COUNT 10 #define MAX_VLAN_ID 4094 typedef u8 macaddr[ETH_ALEN]; @@ -105,7 +105,6 @@ struct hostapd_wpa_psk { u8 addr[ETH_ALEN]; }; -#if 0 struct hostapd_eap_user { struct hostapd_eap_user *next; u8 *identity; @@ -124,6 +123,7 @@ struct hostapd_eap_user { int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ }; +#if 0 struct hostapd_radius_attr { u8 type; struct wpabuf *val; @@ -247,7 +247,11 @@ struct hostapd_bss_config { */ u16 max_listen_interval; + int wps_state; #ifdef CONFIG_WPS +#define WPS_DEV_TYPE_LEN 8 +/* maximum number of advertised WPS vendor extension attributes */ +#define MAX_WPS_VENDOR_EXTENSIONS 10 int ap_setup_locked; u8 uuid[16]; char *wps_pin_requests; diff --git a/components/wpa_supplicant/src/ap/eap_user_db.c b/components/wpa_supplicant/src/ap/eap_user_db.c index a510ee3e29..41fb245d1f 100644 --- a/components/wpa_supplicant/src/ap/eap_user_db.c +++ b/components/wpa_supplicant/src/ap/eap_user_db.c @@ -233,10 +233,9 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, size_t identity_len, int phase2) { const struct hostapd_bss_config *conf = hapd->conf; - struct hostapd_eap_user *user = conf->eap_user; #ifdef CONFIG_WPS - if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN && + if (identity_len == WSC_ID_ENROLLEE_LEN && os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) { static struct hostapd_eap_user wsc_enrollee; os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee)); @@ -245,7 +244,7 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, return &wsc_enrollee; } - if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN && + if (identity_len == WSC_ID_REGISTRAR_LEN && os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) { static struct hostapd_eap_user wsc_registrar; os_memset(&wsc_registrar, 0, sizeof(wsc_registrar)); @@ -258,27 +257,6 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, } #endif /* CONFIG_WPS */ - while (user) { - if (!phase2 && user->identity == NULL) { - /* Wildcard match */ - break; - } - - if (user->phase2 == !!phase2 && user->wildcard_prefix && - identity_len >= user->identity_len && - os_memcmp(user->identity, identity, user->identity_len) == - 0) { - /* Wildcard prefix match */ - break; - } - - if (user->phase2 == !!phase2 && - user->identity_len == identity_len && - os_memcmp(user->identity, identity, identity_len) == 0) - break; - user = user->next; - } - #ifdef CONFIG_SQLITE if (user == NULL && conf->eap_user_sqlite) { return eap_user_sqlite_get(hapd, identity, identity_len, @@ -286,5 +264,5 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, } #endif /* CONFIG_SQLITE */ - return user; + return NULL; } diff --git a/components/wpa_supplicant/src/ap/hostapd.h b/components/wpa_supplicant/src/ap/hostapd.h index 5bedf09d0a..92192c609f 100644 --- a/components/wpa_supplicant/src/ap/hostapd.h +++ b/components/wpa_supplicant/src/ap/hostapd.h @@ -63,6 +63,25 @@ struct hostapd_frame_info { int ssi_signal; /* dBm */ }; +#ifdef CONFIG_WPS +enum hapd_wps_status { + WPS_SUCCESS_STATUS = 1, + WPS_FAILURE_STATUS +}; + +enum pbc_status { + WPS_PBC_STATUS_DISABLE, + WPS_PBC_STATUS_ACTIVE, + WPS_PBC_STATUS_TIMEOUT, + WPS_PBC_STATUS_OVERLAP +}; + +struct wps_stat { + enum hapd_wps_status status; + enum pbc_status pbc_status; + u8 peer_addr[ETH_ALEN]; +}; +#endif /** * struct hostapd_data - hostapd per-BSS data structure @@ -73,9 +92,13 @@ struct hostapd_data { int interface_added; /* virtual interface added for this BSS */ u8 own_addr[ETH_ALEN]; - + struct sta_info *sta_list; /* STA info list head */ +#define STA_HASH_SIZE 10 +#define STA_HASH(sta) (sta[5] & 0xa) + struct sta_info *sta_hash[STA_HASH_SIZE]; int num_sta; /* number of entries in sta_list */ + struct eapol_authenticator *eapol_auth; struct wpa_authenticator *wpa_auth; #ifdef CONFIG_FULL_DYNAMIC_VLAN @@ -83,10 +106,15 @@ struct hostapd_data { #endif /* CONFIG_FULL_DYNAMIC_VLAN */ #ifdef CONFIG_WPS + struct wps_context *wps; unsigned int ap_pin_failures; unsigned int ap_pin_failures_consecutive; struct upnp_wps_device_sm *wps_upnp; unsigned int ap_pin_lockout_time; + + struct wps_stat wps_stats; + void (*wps_event_cb)(void *ctx, enum wps_event event, + union wps_event_data *data); #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P @@ -112,4 +140,10 @@ struct hostapd_data { #endif /* CONFIG_SQLITE */ }; +struct hostapd_data *hostapd_get_hapd_data(void); + +const struct hostapd_eap_user * +hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, + size_t identity_len, int phase2); + #endif /* HOSTAPD_H */ diff --git a/components/wpa_supplicant/src/ap/ieee802_1x.c b/components/wpa_supplicant/src/ap/ieee802_1x.c index 9f8fd1bd8e..5e3c078baf 100644 --- a/components/wpa_supplicant/src/ap/ieee802_1x.c +++ b/components/wpa_supplicant/src/ap/ieee802_1x.c @@ -9,14 +9,138 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/eloop.h" #include "crypto/crypto.h" #include "common/ieee802_11_defs.h" #include "hostapd.h" #include "ap/sta_info.h" #include "ap/wpa_auth.h" +#include "eap_server/eap.h" #include "ap/ap_config.h" +#include "eap_common/eap_wsc_common.h" #include "ap/ieee802_1x.h" #include "utils/wpa_debug.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "eapol_auth/eapol_auth_sm_i.h" +#include "eap_server/eap.h" +#include "sta_info.h" +#include "ieee802_1x.h" + +int hostapd_send_eapol(const u8 *source, const u8 *sta_addr, + const u8 *data, size_t data_len); + +static void ieee802_1x_finished(struct hostapd_data *hapd, + struct sta_info *sta, int success, + int remediation); + +static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, + u8 type, const u8 *data, size_t datalen) +{ + u8 *buf; + struct ieee802_1x_hdr *xhdr; + size_t len; + + len = sizeof(*xhdr) + datalen; + buf = os_zalloc(len); + if (!buf) { + wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)", + __func__, (unsigned long) len); + return; + } + + xhdr = (struct ieee802_1x_hdr *) buf; + xhdr->version = EAPOL_VERSION; + xhdr->type = type; + xhdr->length = host_to_be16(datalen); + + if (datalen > 0 && data != NULL) + os_memcpy(xhdr + 1, data, datalen); + + hostapd_send_eapol(hapd->own_addr, sta->addr, buf, len); + os_free(buf); +} + + + +static void handle_eap_response(struct hostapd_data *hapd, + struct sta_info *sta, struct eap_hdr *eap, + size_t len) +{ + u8 type, *data; + struct eapol_state_machine *sm = sta->eapol_sm; + + if (!sm) + return; + + data = (u8 *) (eap + 1); + + if (len < sizeof(*eap) + 1) { + wpa_printf(MSG_INFO, "%s: too short response data", __func__); + return; + } + + sm->eap_type_supp = type = data[0]; + + sm->dot1xAuthEapolRespFramesRx++; + + wpabuf_free(sm->eap_if->eapRespData); + sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); + sm->eapolEap = true; +} + +/* Process incoming EAP packet from Supplicant */ +static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, + u8 *buf, size_t len) +{ + struct eap_hdr *eap; + u16 eap_len; + + if (len < sizeof(*eap)) { + wpa_printf(MSG_INFO, " too short EAP packet"); + return; + } + + eap = (struct eap_hdr *) buf; + + eap_len = be_to_host16(eap->length); + wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", + eap->code, eap->identifier, + eap_len); + if (eap_len < sizeof(*eap)) { + wpa_printf(MSG_DEBUG, " Invalid EAP length"); + return; + } else if (eap_len > len) { + wpa_printf(MSG_DEBUG, + " Too short frame to contain this EAP packet"); + return; + } else if (eap_len < len) { + wpa_printf(MSG_DEBUG, + " Ignoring %lu extra bytes after EAP packet", + (unsigned long) len - eap_len); + } + + switch (eap->code) { + case EAP_CODE_RESPONSE: + handle_eap_response(hapd, sta, eap, eap_len); + break; + case EAP_CODE_INITIATE: + break; + } +} + +struct eapol_state_machine * +ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) +{ + int flags = 0; + + if (sta->wpa_sm) { + flags |= EAPOL_SM_USES_WPA; + } + return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, + sta->wps_ie, NULL, sta, + sta->identity, NULL); +} + /** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant @@ -35,35 +159,44 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, struct ieee802_1x_eapol_key *key; u16 datalen; - wpa_printf( MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, + wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, (unsigned long) len, MAC2STR(sa)); sta = ap_get_sta(hapd, sa); - if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) { - wpa_printf( MSG_DEBUG, "IEEE 802.1X data frame from not " - "associated/Pre-authenticating STA"); + if (!sta) { + wpa_printf(MSG_DEBUG, + "IEEE 802.1X data frame from not associated/Pre-authenticating STA"); + return; } if (len < sizeof(*hdr)) { - wpa_printf( MSG_DEBUG, " too short IEEE 802.1X packet\n"); + wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); return; } hdr = (struct ieee802_1x_hdr *) buf; datalen = be_to_host16(hdr->length); - wpa_printf( MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", + wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", hdr->version, hdr->type, datalen); if (len - sizeof(*hdr) < datalen) { - wpa_printf( MSG_DEBUG, " frame too short for this IEEE 802.1X packet\n"); + wpa_printf(MSG_INFO, + " frame too short for this IEEE 802.1X packet"); + if (sta->eapol_sm) + sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; return; } if (len - sizeof(*hdr) > datalen) { - wpa_printf( MSG_DEBUG, " ignoring %lu extra octets after " - "IEEE 802.1X packet", + wpa_printf(MSG_DEBUG, + " ignoring %lu extra octets after IEEE 802.1X packet", (unsigned long) len - sizeof(*hdr) - datalen); } + if (sta->eapol_sm) { + sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; + sta->eapol_sm->dot1xAuthEapolFramesRx++; + } + key = (struct ieee802_1x_eapol_key *) (hdr + 1); if (datalen >= sizeof(struct ieee802_1x_eapol_key) && hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && @@ -73,4 +206,274 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, sizeof(*hdr) + datalen); return; } + + if (!sta->eapol_sm) { + sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); + if (!sta->eapol_sm) + return; + +#ifdef CONFIG_WPS + if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { + u32 wflags = sta->flags & (WLAN_STA_WPS | + WLAN_STA_WPS2 | + WLAN_STA_MAYBE_WPS); + if (wflags == WLAN_STA_MAYBE_WPS || + wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { + /* + * Delay EAPOL frame transmission until a + * possible WPS STA initiates the handshake + * with EAPOL-Start. Only allow the wait to be + * skipped if the STA is known to support WPS + * 2.0. + */ + wpa_printf(MSG_DEBUG, + "WPS: Do not start EAPOL until EAPOL-Start is received"); + sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + } + } +#endif /* CONFIG_WPS */ + + sta->eapol_sm->eap_if->portEnabled = true; + } + + /* since we support version 1, we can ignore version field and proceed + * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ + /* TODO: actually, we are not version 1 anymore.. However, Version 2 + * does not change frame contents, so should be ok to process frames + * more or less identically. Some changes might be needed for + * verification of fields. */ + + switch (hdr->type) { + case IEEE802_1X_TYPE_EAP_PACKET: + handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); + break; + + case IEEE802_1X_TYPE_EAPOL_START: + sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; + sta->eapol_sm->eapolStart = true; + sta->eapol_sm->dot1xAuthEapolStartFramesRx++; + eap_server_clear_identity(sta->eapol_sm->eap); + wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); + break; + + + case IEEE802_1X_TYPE_EAPOL_LOGOFF: + break; + + case IEEE802_1X_TYPE_EAPOL_KEY: + wpa_printf(MSG_DEBUG, " EAPOL-Key"); + break; + + case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: + wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); + /* TODO: implement support for this; show data */ + break; + + default: + wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); + sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; + break; + } + + eapol_auth_step(sta->eapol_sm); +} + + +void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) +{ + struct eapol_state_machine *sm = sta->eapol_sm; + + if (!sm) + return; + + sta->eapol_sm = NULL; + eapol_auth_free(sm); +} + + +static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, + const u8 *data, size_t datalen) +{ +#ifdef CONFIG_WPS + struct sta_info *sta = sta_ctx; + + if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == + WLAN_STA_MAYBE_WPS) { + const u8 *identity; + size_t identity_len; + struct eapol_state_machine *sm = sta->eapol_sm; + + identity = eap_get_identity(sm->eap, &identity_len); + if (identity && + ((identity_len == WSC_ID_ENROLLEE_LEN && + os_memcmp(identity, WSC_ID_ENROLLEE, + WSC_ID_ENROLLEE_LEN) == 0) || + (identity_len == WSC_ID_REGISTRAR_LEN && + os_memcmp(identity, WSC_ID_REGISTRAR, + WSC_ID_REGISTRAR_LEN) == 0))) { + wpa_printf(MSG_DEBUG, + "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS"); + sta->flags |= WLAN_STA_WPS; + } + } +#endif /* CONFIG_WPS */ + + ieee802_1x_send(ctx, sta_ctx, type, data, datalen); +} + + +static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, + const u8 *data, size_t datalen) +{ +#ifndef CONFIG_NO_RADIUS + struct hostapd_data *hapd = ctx; + struct sta_info *sta = sta_ctx; + + ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); +#endif /* CONFIG_NO_RADIUS */ +} + + +static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, + int preauth, int remediation) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta = sta_ctx; + ieee802_1x_finished(hapd, sta, success, remediation); +} + + +static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, + size_t identity_len, int phase2, + struct eap_user *user) +{ + struct hostapd_data *hapd = ctx; + const struct hostapd_eap_user *eap_user; + int i; + int rv = -1; + + eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); + if (!eap_user) + goto out; + + os_memset(user, 0, sizeof(*user)); + user->phase2 = phase2; + for (i = 0; i < EAP_MAX_METHODS; i++) { + user->methods[i].vendor = eap_user->methods[i].vendor; + user->methods[i].method = eap_user->methods[i].method; + } + + if (eap_user->password) { + user->password = os_memdup(eap_user->password, + eap_user->password_len); + if (!user->password) + goto out; + user->password_len = eap_user->password_len; + user->password_hash = eap_user->password_hash; + } + user->force_version = eap_user->force_version; + user->ttls_auth = eap_user->ttls_auth; + rv = 0; + +out: + if (rv) + wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); + + return rv; +} + + +static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta; + + sta = ap_get_sta(hapd, addr); + if (!sta || !sta->eapol_sm) + return 0; + return 1; +} + + +static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, + int authorized) +{ +} + + +static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) +{ +} + + +static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, + enum eapol_event type) +{ +#if 0 + /* struct hostapd_data *hapd = ctx; */ + struct sta_info *sta = sta_ctx; + + switch (type) { + case EAPOL_AUTH_SM_CHANGE: + wpa_auth_sm_notify(sta->wpa_sm); + break; + case EAPOL_AUTH_REAUTHENTICATE: + wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); + break; + } +#endif +} + + +int ieee802_1x_init(struct hostapd_data *hapd) +{ + struct eapol_auth_config conf; + struct eapol_auth_cb cb; + struct eap_config *eap_cfg; + + os_memset(&conf, 0, sizeof(conf)); + eap_cfg = os_zalloc(sizeof(struct eap_config)); + eap_cfg->max_auth_rounds = 100; + eap_cfg->max_auth_rounds_short = 50; + //eap_cfg->backend_auth = 1; + eap_cfg->eap_server = 1; + conf.eap_cfg = eap_cfg; + conf.ctx = hapd; + conf.wpa = hapd->conf->wpa; + + os_memset(&cb, 0, sizeof(cb)); + cb.eapol_send = ieee802_1x_eapol_send; + cb.aaa_send = ieee802_1x_aaa_send; + cb.finished = _ieee802_1x_finished; + cb.get_eap_user = ieee802_1x_get_eap_user; + cb.sta_entry_alive = ieee802_1x_sta_entry_alive; + cb.set_port_authorized = ieee802_1x_set_port_authorized; + cb.abort_auth = _ieee802_1x_abort_auth; + cb.eapol_event = ieee802_1x_eapol_event; + + hapd->eapol_auth = eapol_auth_init(&conf, &cb); + if (!hapd->eapol_auth) + return -1; + + return 0; +} + + +static void ieee802_1x_finished(struct hostapd_data *hapd, + struct sta_info *sta, int success, + int remediation) +{ + if (!success) { + /* + * Many devices require deauthentication after WPS provisioning + * and some may not be be able to do that themselves, so + * disconnect the client here. In addition, this may also + * benefit IEEE 802.1X/EAPOL authentication cases, too since + * the EAPOL PAE state machine would remain in HELD state for + * considerable amount of time and some EAP methods, like + * EAP-FAST with anonymous provisioning, may require another + * EAPOL authentication to be started to complete connection. + */ + ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); + } } diff --git a/components/wpa_supplicant/src/ap/ieee802_1x.h b/components/wpa_supplicant/src/ap/ieee802_1x.h index 60051ee5a0..7eb4f14c1c 100644 --- a/components/wpa_supplicant/src/ap/ieee802_1x.h +++ b/components/wpa_supplicant/src/ap/ieee802_1x.h @@ -17,8 +17,12 @@ struct hostapd_bss_config; struct hostapd_radius_attr; struct radius_msg; - void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, size_t len); +void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta); +int ieee802_1x_init(struct hostapd_data *hapd); +struct eapol_state_machine * +ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta); + #endif /* IEEE802_1X_H */ diff --git a/components/wpa_supplicant/src/ap/sta_info.c b/components/wpa_supplicant/src/ap/sta_info.c index ccd1ed931b..77b5449144 100644 --- a/components/wpa_supplicant/src/ap/sta_info.c +++ b/components/wpa_supplicant/src/ap/sta_info.c @@ -11,44 +11,15 @@ #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" -#include "common/wpa_ctrl.h" -#include "common/sae.h" -#include "common/dpp.h" -#include "radius/radius.h" -#include "radius/radius_client.h" -#include "p2p/p2p.h" -#include "fst/fst.h" #include "crypto/crypto.h" #include "hostapd.h" -#include "accounting.h" #include "ieee802_1x.h" -#include "ieee802_11.h" -#include "ieee802_11_auth.h" #include "wpa_auth.h" -#include "preauth_auth.h" #include "ap_config.h" -#include "beacon.h" -#include "ap_mlme.h" -#include "vlan_init.h" -#include "p2p_hostapd.h" -#include "ap_drv_ops.h" -#include "gas_serv.h" -#include "wnm_ap.h" -#include "mbo_ap.h" -#include "ndisc_snoop.h" #include "sta_info.h" -#include "vlan.h" -#include "wps_hostapd.h" -static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, - struct sta_info *sta); -static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); -static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx); -static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); -static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); -static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); -static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx); +void hostapd_wps_eap_completed(struct hostapd_data *hapd); int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, @@ -77,30 +48,6 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) } -#ifdef CONFIG_P2P -struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) -{ - struct sta_info *sta; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - const u8 *p2p_dev_addr; - - if (sta->p2p_ie == NULL) - continue; - - p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); - if (p2p_dev_addr == NULL) - continue; - - if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0) - return sta; - } - - return NULL; -} -#endif /* CONFIG_P2P */ - - static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) { struct sta_info *tmp; @@ -149,268 +96,22 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) " from hash table", MAC2STR(sta->addr)); } - -void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) -{ - sta_ip6addr_del(hapd, sta); -} - - -#ifdef CONFIG_PASN - -void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (sta->pasn) { - wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR, - MAC2STR(sta->addr)); - - if (sta->pasn->ecdh) - crypto_ecdh_deinit(sta->pasn->ecdh); - - wpabuf_free(sta->pasn->secret); - sta->pasn->secret = NULL; - -#ifdef CONFIG_SAE - sae_clear_data(&sta->pasn->sae); -#endif /* CONFIG_SAE */ - -#ifdef CONFIG_FILS - /* In practice this pointer should be NULL */ - wpabuf_free(sta->pasn->fils.erp_resp); - sta->pasn->fils.erp_resp = NULL; -#endif /* CONFIG_FILS */ - - bin_clear_free(sta->pasn, sizeof(*sta->pasn)); - sta->pasn = NULL; - } -} - -#endif /* CONFIG_PASN */ - void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { - int set_beacon = 0; - - accounting_sta_stop(hapd, sta); - - /* just in case */ - ap_sta_set_authorized(hapd, sta, 0); - hostapd_set_sta_flags(hapd, sta); - - if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) - hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); - - if (sta->ipaddr) - hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); - ap_sta_ip6addr_del(hapd, sta); - - if (!hapd->iface->driver_ap_teardown && - !(sta->flags & WLAN_STA_PREAUTH)) { - hostapd_drv_sta_remove(hapd, sta->addr); - sta->added_unassoc = 0; - } - ap_sta_hash_del(hapd, sta); ap_sta_list_del(hapd, sta); - if (sta->aid > 0) - hapd->sta_aid[(sta->aid - 1) / 32] &= - ~BIT((sta->aid - 1) % 32); - hapd->num_sta--; - if (sta->nonerp_set) { - sta->nonerp_set = 0; - hapd->iface->num_sta_non_erp--; - if (hapd->iface->num_sta_non_erp == 0) - set_beacon++; - } - if (sta->no_short_slot_time_set) { - sta->no_short_slot_time_set = 0; - hapd->iface->num_sta_no_short_slot_time--; - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G - && hapd->iface->num_sta_no_short_slot_time == 0) - set_beacon++; - } - - if (sta->no_short_preamble_set) { - sta->no_short_preamble_set = 0; - hapd->iface->num_sta_no_short_preamble--; - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G - && hapd->iface->num_sta_no_short_preamble == 0) - set_beacon++; - } - - if (sta->no_ht_gf_set) { - sta->no_ht_gf_set = 0; - hapd->iface->num_sta_ht_no_gf--; - } - - if (sta->no_ht_set) { - sta->no_ht_set = 0; - hapd->iface->num_sta_no_ht--; - } - - if (sta->ht_20mhz_set) { - sta->ht_20mhz_set = 0; - hapd->iface->num_sta_ht_20mhz--; - } - -#ifdef CONFIG_TAXONOMY - wpabuf_free(sta->probe_ie_taxonomy); - sta->probe_ie_taxonomy = NULL; - wpabuf_free(sta->assoc_ie_taxonomy); - sta->assoc_ie_taxonomy = NULL; -#endif /* CONFIG_TAXONOMY */ - - ht40_intolerant_remove(hapd->iface, sta); - -#ifdef CONFIG_P2P - if (sta->no_p2p_set) { - sta->no_p2p_set = 0; - hapd->num_sta_no_p2p--; - if (hapd->num_sta_no_p2p == 0) - hostapd_p2p_non_p2p_sta_disconnected(hapd); - } -#endif /* CONFIG_P2P */ - -#ifdef NEED_AP_MLME - if (hostapd_ht_operation_update(hapd->iface) > 0) - set_beacon++; -#endif /* NEED_AP_MLME */ - -#ifdef CONFIG_MESH - if (hapd->mesh_sta_free_cb) - hapd->mesh_sta_free_cb(hapd, sta); -#endif /* CONFIG_MESH */ - - if (set_beacon) - ieee802_11_set_beacons(hapd->iface); - - wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR, - __func__, MAC2STR(sta->addr)); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); - eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); - ap_sta_clear_disconnect_timeouts(hapd, sta); - sae_clear_retransmit_timer(hapd, sta); + wpa_auth_sta_deinit(sta->wpa_sm); +#ifdef CONFIG_WPS_REGISTRAR + if (ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) + eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); ieee802_1x_free_station(hapd, sta); - wpa_auth_sta_deinit(sta->wpa_sm); - rsn_preauth_free_station(hapd, sta); -#ifndef CONFIG_NO_RADIUS - if (hapd->radius) - radius_client_flush_auth(hapd->radius, sta->addr); -#endif /* CONFIG_NO_RADIUS */ - -#ifndef CONFIG_NO_VLAN - /* - * sta->wpa_sm->group needs to be released before so that - * vlan_remove_dynamic() can check that no stations are left on the - * AP_VLAN netdev. - */ - if (sta->vlan_id) - vlan_remove_dynamic(hapd, sta->vlan_id); - if (sta->vlan_id_bound) { - /* - * Need to remove the STA entry before potentially removing the - * VLAN. - */ - if (hapd->iface->driver_ap_teardown && - !(sta->flags & WLAN_STA_PREAUTH)) { - hostapd_drv_sta_remove(hapd, sta->addr); - sta->added_unassoc = 0; - } - vlan_remove_dynamic(hapd, sta->vlan_id_bound); - } -#endif /* CONFIG_NO_VLAN */ - - os_free(sta->challenge); - - os_free(sta->sa_query_trans_id); - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); - -#ifdef CONFIG_P2P - p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_INTERWORKING - if (sta->gas_dialog) { - int i; - for (i = 0; i < GAS_DIALOG_MAX; i++) - gas_serv_dialog_clear(&sta->gas_dialog[i]); - os_free(sta->gas_dialog); - } -#endif /* CONFIG_INTERWORKING */ wpabuf_free(sta->wps_ie); - wpabuf_free(sta->p2p_ie); - wpabuf_free(sta->hs20_ie); - wpabuf_free(sta->roaming_consortium); -#ifdef CONFIG_FST - wpabuf_free(sta->mb_ies); -#endif /* CONFIG_FST */ - - os_free(sta->ht_capabilities); - os_free(sta->vht_capabilities); - os_free(sta->vht_operation); - os_free(sta->he_capab); - os_free(sta->he_6ghz_capab); - hostapd_free_psk_list(sta->psk); - os_free(sta->identity); - os_free(sta->radius_cui); - os_free(sta->remediation_url); - os_free(sta->t_c_url); - wpabuf_free(sta->hs20_deauth_req); - os_free(sta->hs20_session_info_url); - -#ifdef CONFIG_SAE - sae_clear_data(sta->sae); - os_free(sta->sae); -#endif /* CONFIG_SAE */ - - mbo_ap_sta_free(sta); - os_free(sta->supp_op_classes); - -#ifdef CONFIG_FILS - os_free(sta->fils_pending_assoc_req); - wpabuf_free(sta->fils_hlp_resp); - wpabuf_free(sta->hlp_dhcp_discover); - eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); -#ifdef CONFIG_FILS_SK_PFS - crypto_ecdh_deinit(sta->fils_ecdh); - wpabuf_clear_free(sta->fils_dh_ss); - wpabuf_free(sta->fils_g_sta); -#endif /* CONFIG_FILS_SK_PFS */ -#endif /* CONFIG_FILS */ - -#ifdef CONFIG_OWE - bin_clear_free(sta->owe_pmk, sta->owe_pmk_len); - crypto_ecdh_deinit(sta->owe_ecdh); -#endif /* CONFIG_OWE */ - -#ifdef CONFIG_DPP2 - dpp_pfs_free(sta->dpp_pfs); - sta->dpp_pfs = NULL; -#endif /* CONFIG_DPP2 */ - - os_free(sta->ext_capability); - -#ifdef CONFIG_WNM_AP - eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); -#endif /* CONFIG_WNM_AP */ - -#ifdef CONFIG_PASN - ap_free_sta_pasn(hapd, sta); -#endif /* CONFIG_PASN */ - - os_free(sta->ifname_wds); - -#ifdef CONFIG_TESTING_OPTIONS - os_free(sta->sae_postponed_commit); -#endif /* CONFIG_TESTING_OPTIONS */ +#endif os_free(sta); } @@ -424,10 +125,6 @@ void hostapd_free_stas(struct hostapd_data *hapd) while (sta) { prev = sta; - if (sta->flags & WLAN_STA_AUTH) { - mlme_deauthenticate_indication( - hapd, sta, WLAN_REASON_UNSPECIFIED); - } sta = sta->next; wpa_printf(MSG_DEBUG, "Removing station " MACSTR, MAC2STR(prev->addr)); @@ -436,279 +133,9 @@ void hostapd_free_stas(struct hostapd_data *hapd) } -/** - * ap_handle_timer - Per STA timer handler - * @eloop_ctx: struct hostapd_data * - * @timeout_ctx: struct sta_info * - * - * This function is called to check station activity and to remove inactive - * stations. - */ -void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - unsigned long next_time = 0; - int reason; - - wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d", - hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags, - sta->timeout_next); - if (sta->timeout_next == STA_REMOVE) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "local deauth request"); - ap_free_sta(hapd, sta); - return; - } - - if ((sta->flags & WLAN_STA_ASSOC) && - (sta->timeout_next == STA_NULLFUNC || - sta->timeout_next == STA_DISASSOC)) { - int inactive_sec; - /* - * Add random value to timeout so that we don't end up bouncing - * all stations at the same time if we have lots of associated - * stations that are idle (but keep re-associating). - */ - int fuzz = os_random() % 20; - inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); - if (inactive_sec == -1) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "Check inactivity: Could not " - "get station info from kernel driver for " - MACSTR, MAC2STR(sta->addr)); - /* - * The driver may not support this functionality. - * Anyway, try again after the next inactivity timeout, - * but do not disconnect the station now. - */ - next_time = hapd->conf->ap_max_inactivity + fuzz; - } else if (inactive_sec == -ENOENT) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "Station " MACSTR " has lost its driver entry", - MAC2STR(sta->addr)); - - /* Avoid sending client probe on removed client */ - sta->timeout_next = STA_DISASSOC; - goto skip_poll; - } else if (inactive_sec < hapd->conf->ap_max_inactivity) { - /* station activity detected; reset timeout state */ - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "Station " MACSTR " has been active %is ago", - MAC2STR(sta->addr), inactive_sec); - sta->timeout_next = STA_NULLFUNC; - next_time = hapd->conf->ap_max_inactivity + fuzz - - inactive_sec; - } else { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "Station " MACSTR " has been " - "inactive too long: %d sec, max allowed: %d", - MAC2STR(sta->addr), inactive_sec, - hapd->conf->ap_max_inactivity); - - if (hapd->conf->skip_inactivity_poll) - sta->timeout_next = STA_DISASSOC; - } - } - - if ((sta->flags & WLAN_STA_ASSOC) && - sta->timeout_next == STA_DISASSOC && - !(sta->flags & WLAN_STA_PENDING_POLL) && - !hapd->conf->skip_inactivity_poll) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR - " has ACKed data poll", MAC2STR(sta->addr)); - /* data nullfunc frame poll did not produce TX errors; assume - * station ACKed it */ - sta->timeout_next = STA_NULLFUNC; - next_time = hapd->conf->ap_max_inactivity; - } - -skip_poll: - if (next_time) { - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%lu seconds)", - __func__, MAC2STR(sta->addr), next_time); - eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, - sta); - return; - } - - if (sta->timeout_next == STA_NULLFUNC && - (sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, " Polling STA"); - sta->flags |= WLAN_STA_PENDING_POLL; - hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, - sta->flags & WLAN_STA_WMM); - } else if (sta->timeout_next != STA_REMOVE) { - int deauth = sta->timeout_next == STA_DEAUTH; - - if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) { - /* Cannot disassociate not-associated STA, so move - * directly to deauthentication. */ - sta->timeout_next = STA_DEAUTH; - deauth = 1; - } - - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, - "Timeout, sending %s info to STA " MACSTR, - deauth ? "deauthentication" : "disassociation", - MAC2STR(sta->addr)); - - if (deauth) { - hostapd_drv_sta_deauth( - hapd, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } else { - reason = (sta->timeout_next == STA_DISASSOC) ? - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : - WLAN_REASON_PREV_AUTH_NOT_VALID; - - hostapd_drv_sta_disassoc(hapd, sta->addr, reason); - } - } - - switch (sta->timeout_next) { - case STA_NULLFUNC: - sta->timeout_next = STA_DISASSOC; - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)", - __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY); - eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, - hapd, sta); - break; - case STA_DISASSOC: - case STA_DISASSOC_FROM_CLI: - ap_sta_set_authorized(hapd, sta, 0); - sta->flags &= ~WLAN_STA_ASSOC; - hostapd_set_sta_flags(hapd, sta); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - if (!sta->acct_terminate_cause) - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(hapd, sta); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "disassociated due to " - "inactivity"); - reason = (sta->timeout_next == STA_DISASSOC) ? - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : - WLAN_REASON_PREV_AUTH_NOT_VALID; - sta->timeout_next = STA_DEAUTH; - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", - __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); - eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, - hapd, sta); - mlme_disassociate_indication(hapd, sta, reason); - break; - case STA_DEAUTH: - case STA_REMOVE: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "inactivity (timer DEAUTH/REMOVE)"); - if (!sta->acct_terminate_cause) - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; - mlme_deauthenticate_indication( - hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - ap_free_sta(hapd, sta); - break; - } -} - - -static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - - wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_AUTHORIZED))) { - if (sta->flags & WLAN_STA_GAS) { - wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " - "entry " MACSTR, MAC2STR(sta->addr)); - ap_free_sta(hapd, sta); - } - return; - } - - hostapd_drv_sta_deauth(hapd, sta->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - mlme_deauthenticate_indication(hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "deauthenticated due to " - "session timeout"); - sta->acct_terminate_cause = - RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; - ap_free_sta(hapd, sta); -} - - -void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout) -{ - if (eloop_replenish_timeout(session_timeout, 0, - ap_handle_session_timer, hapd, sta) == 1) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "setting session timeout " - "to %d seconds", session_timeout); - } -} - - -void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, - u32 session_timeout) -{ - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " - "seconds", session_timeout); - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); - eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, - hapd, sta); -} - - -void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) -{ - eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); -} - - -static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx) -{ -#ifdef CONFIG_WNM_AP - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - - wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for " - MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); - if (sta->hs20_session_info_url == NULL) - return; - - wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url, - sta->hs20_disassoc_timer); -#endif /* CONFIG_WNM_AP */ -} - - -void ap_sta_session_warning_timeout(struct hostapd_data *hapd, - struct sta_info *sta, int warning_time) -{ - eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); - eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer, - hapd, sta); -} - - struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; - int i; sta = ap_get_sta(hapd, addr); if (sta) @@ -727,29 +154,6 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) wpa_printf(MSG_ERROR, "malloc failed"); return NULL; } - sta->acct_interim_interval = hapd->conf->acct_interim_interval; - if (accounting_sta_get_id(hapd, sta) < 0) { - os_free(sta); - return NULL; - } - - for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { - if (!hapd->iface->basic_rates) - break; - if (hapd->iface->basic_rates[i] < 0) - break; - sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5; - } - sta->supported_rates_len = i; - - if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { - wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " - "for " MACSTR " (%d seconds - ap_max_inactivity)", - __func__, MAC2STR(addr), - hapd->conf->ap_max_inactivity); - eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, - ap_handle_timer, hapd, sta); - } /* initialize STA info data */ os_memcpy(sta->addr, addr, ETH_ALEN); @@ -757,741 +161,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); - ap_sta_remove_in_other_bss(hapd, sta); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; - dl_list_init(&sta->ip6addr); - -#ifdef CONFIG_TAXONOMY - sta_track_claim_taxonomy_info(hapd->iface, addr, - &sta->probe_ie_taxonomy); -#endif /* CONFIG_TAXONOMY */ return sta; } - -static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) -{ - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - - if (sta->ipaddr) - hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); - ap_sta_ip6addr_del(hapd, sta); - - wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver", - hapd->conf->iface, MAC2STR(sta->addr)); - if (hostapd_drv_sta_remove(hapd, sta->addr) && - sta->flags & WLAN_STA_ASSOC) { - wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR - " from kernel driver", - hapd->conf->iface, MAC2STR(sta->addr)); - return -1; - } - sta->added_unassoc = 0; - return 0; -} - - -static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct hostapd_iface *iface = hapd->iface; - size_t i; - - for (i = 0; i < iface->num_bss; i++) { - struct hostapd_data *bss = iface->bss[i]; - struct sta_info *sta2; - /* bss should always be set during operation, but it may be - * NULL during reconfiguration. Assume the STA is not - * associated to another BSS in that case to avoid NULL pointer - * dereferences. */ - if (bss == hapd || bss == NULL) - continue; - sta2 = ap_get_sta(bss, sta->addr); - if (!sta2) - continue; - - wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR - " association from another BSS %s", - hapd->conf->iface, MAC2STR(sta2->addr), - bss->conf->iface); - ap_sta_disconnect(bss, sta2, sta2->addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } -} - - -static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - - wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - ap_sta_remove(hapd, sta); - mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); -} - - -void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason) -{ - wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { - /* Skip deauthentication in DMG/IEEE 802.11ad */ - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_ASSOC_REQ_OK); - sta->timeout_next = STA_REMOVE; - } else { - sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - sta->timeout_next = STA_DEAUTH; - } - ap_sta_set_authorized(hapd, sta, 0); - hostapd_set_sta_flags(hapd, sta); - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DISASSOC)", - __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DISASSOC); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(hapd, sta); - wpa_auth_sta_deinit(sta->wpa_sm); - sta->wpa_sm = NULL; - - sta->disassoc_reason = reason; - sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; - eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); - eloop_register_timeout(hapd->iface->drv_flags & - WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, - ap_sta_disassoc_cb_timeout, hapd, sta); -} - - -static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - - wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - ap_sta_remove(hapd, sta); - mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); -} - - -void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason) -{ - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { - /* Deauthentication is not used in DMG/IEEE 802.11ad; - * disassociate the STA instead. */ - ap_sta_disassociate(hapd, sta, reason); - return; - } - - wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - ap_sta_set_authorized(hapd, sta, 0); - hostapd_set_sta_flags(hapd, sta); - sta->timeout_next = STA_REMOVE; - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DEAUTH)", - __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DEAUTH); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(hapd, sta); - - sta->deauth_reason = reason; - sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; - eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); - eloop_register_timeout(hapd->iface->drv_flags & - WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, - ap_sta_deauth_cb_timeout, hapd, sta); -} - - -#ifdef CONFIG_WPS -int ap_sta_wps_cancel(struct hostapd_data *hapd, - struct sta_info *sta, void *ctx) -{ - if (sta && (sta->flags & WLAN_STA_WPS)) { - ap_sta_deauthenticate(hapd, sta, - WLAN_REASON_PREV_AUTH_NOT_VALID); - wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR, - __func__, MAC2STR(sta->addr)); - return 1; - } - - return 0; -} -#endif /* CONFIG_WPS */ - - -static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd) -{ - struct hostapd_vlan *vlan; - int vlan_id = MAX_VLAN_ID + 2; - -retry: - for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { - if (vlan->vlan_id == vlan_id) { - vlan_id++; - goto retry; - } - } - return vlan_id; -} - - -int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta, - struct vlan_description *vlan_desc) -{ - struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL; - int old_vlan_id, vlan_id = 0, ret = 0; - - /* Check if there is something to do */ - if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) { - /* This sta is lacking its own vif */ - } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED && - !hapd->conf->ssid.per_sta_vif && sta->vlan_id) { - /* sta->vlan_id needs to be reset */ - } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) { - return 0; /* nothing to change */ - } - - /* Now the real VLAN changed or the STA just needs its own vif */ - if (hapd->conf->ssid.per_sta_vif) { - /* Assign a new vif, always */ - /* find a free vlan_id sufficiently big */ - vlan_id = ap_sta_get_free_vlan_id(hapd); - /* Get wildcard VLAN */ - for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { - if (vlan->vlan_id == VLAN_ID_WILDCARD) - break; - } - if (!vlan) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "per_sta_vif missing wildcard"); - vlan_id = 0; - ret = -1; - goto done; - } - } else if (vlan_desc && vlan_desc->notempty) { - for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { - if (!vlan_compare(&vlan->vlan_desc, vlan_desc)) - break; - if (vlan->vlan_id == VLAN_ID_WILDCARD) - wildcard_vlan = vlan; - } - if (vlan) { - vlan_id = vlan->vlan_id; - } else if (wildcard_vlan) { - vlan = wildcard_vlan; - vlan_id = vlan_desc->untagged; - if (vlan_desc->tagged[0]) { - /* Tagged VLAN configuration */ - vlan_id = ap_sta_get_free_vlan_id(hapd); - } - } else { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "missing vlan and wildcard for vlan=%d%s", - vlan_desc->untagged, - vlan_desc->tagged[0] ? "+" : ""); - vlan_id = 0; - ret = -1; - goto done; - } - } - - if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) { - vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc); - if (vlan == NULL) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "could not add dynamic VLAN interface for vlan=%d%s", - vlan_desc ? vlan_desc->untagged : -1, - (vlan_desc && vlan_desc->tagged[0]) ? - "+" : ""); - vlan_id = 0; - ret = -1; - goto done; - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "added new dynamic VLAN interface '%s'", - vlan->ifname); - } else if (vlan && vlan->dynamic_vlan > 0) { - vlan->dynamic_vlan++; - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "updated existing dynamic VLAN interface '%s'", - vlan->ifname); - } -done: - old_vlan_id = sta->vlan_id; - sta->vlan_id = vlan_id; - sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL; - - if (vlan_id != old_vlan_id && old_vlan_id) - vlan_remove_dynamic(hapd, old_vlan_id); - - return ret; -} - - -int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) -{ -#ifndef CONFIG_NO_VLAN - const char *iface; - struct hostapd_vlan *vlan = NULL; - int ret; - int old_vlanid = sta->vlan_id_bound; - - if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) { - wpa_printf(MSG_DEBUG, - "Do not override WDS VLAN assignment for STA " - MACSTR, MAC2STR(sta->addr)); - return 0; - } - - iface = hapd->conf->iface; - if (hapd->conf->ssid.vlan[0]) - iface = hapd->conf->ssid.vlan; - - if (sta->vlan_id > 0) { - for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { - if (vlan->vlan_id == sta->vlan_id) - break; - } - if (vlan) - iface = vlan->ifname; - } - - /* - * Do not increment ref counters if the VLAN ID remains same, but do - * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might - * have been called before. - */ - if (sta->vlan_id == old_vlanid) - goto skip_counting; - - if (sta->vlan_id > 0 && !vlan && - !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " - "binding station to (vlan_id=%d)", - sta->vlan_id); - ret = -1; - goto done; - } else if (vlan && vlan->dynamic_vlan > 0) { - vlan->dynamic_vlan++; - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "updated existing dynamic VLAN interface '%s'", - iface); - } - - /* ref counters have been increased, so mark the station */ - sta->vlan_id_bound = sta->vlan_id; - -skip_counting: - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "binding station to interface " - "'%s'", iface); - - if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) - wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); - - ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); - if (ret < 0) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "could not bind the STA " - "entry to vlan_id=%d", sta->vlan_id); - } - - /* During 1x reauth, if the vlan id changes, then remove the old id. */ - if (old_vlanid > 0 && old_vlanid != sta->vlan_id) - vlan_remove_dynamic(hapd, old_vlanid); -done: - - return ret; -#else /* CONFIG_NO_VLAN */ - return 0; -#endif /* CONFIG_NO_VLAN */ -} - - -int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) -{ - u32 tu; - struct os_reltime now, passed; - os_get_reltime(&now); - os_reltime_sub(&now, &sta->sa_query_start, &passed); - tu = (passed.sec * 1000000 + passed.usec) / 1024; - if (hapd->conf->assoc_sa_query_max_timeout < tu) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association SA Query timed out"); - sta->sa_query_timed_out = 1; - os_free(sta->sa_query_trans_id); - sta->sa_query_trans_id = NULL; - sta->sa_query_count = 0; - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); - return 1; - } - - return 0; -} - - -static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = timeout_ctx; - unsigned int timeout, sec, usec; - u8 *trans_id, *nbuf; - - wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR - " (count=%d)", - hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count); - - if (sta->sa_query_count > 0 && - ap_check_sa_query_timeout(hapd, sta)) - return; - if (sta->sa_query_count >= 1000) - return; - - nbuf = os_realloc_array(sta->sa_query_trans_id, - sta->sa_query_count + 1, - WLAN_SA_QUERY_TR_ID_LEN); - if (nbuf == NULL) - return; - if (sta->sa_query_count == 0) { - /* Starting a new SA Query procedure */ - os_get_reltime(&sta->sa_query_start); - } - trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; - sta->sa_query_trans_id = nbuf; - sta->sa_query_count++; - - if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) { - /* - * We don't really care which ID is used here, so simply - * hardcode this if the mostly theoretical os_get_random() - * failure happens. - */ - trans_id[0] = 0x12; - trans_id[1] = 0x34; - } - - timeout = hapd->conf->assoc_sa_query_retry_timeout; - sec = ((timeout / 1000) * 1024) / 1000; - usec = (timeout % 1000) * 1024; - eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "association SA Query attempt %d", sta->sa_query_count); - - ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); -} - - -void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -{ - ap_sa_query_timer(hapd, sta); -} - - -void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -{ - eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); - os_free(sta->sa_query_trans_id); - sta->sa_query_trans_id = NULL; - sta->sa_query_count = 0; -} - - -const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, - struct sta_info *sta) -{ - struct hostapd_wpa_psk *psk; - struct hostapd_ssid *ssid; - const u8 *pmk; - int pmk_len; - - ssid = &hapd->conf->ssid; - - pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); - if (!pmk || pmk_len != PMK_LEN) - return NULL; - - for (psk = ssid->wpa_psk; psk; psk = psk->next) - if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) - break; - if (!psk) - return NULL; - if (!psk || !psk->keyid[0]) - return NULL; - - return psk->keyid; -} - - -void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, - int authorized) -{ - const u8 *dev_addr = NULL; - char buf[100]; -#ifdef CONFIG_P2P - u8 addr[ETH_ALEN]; - u8 ip_addr_buf[4]; -#endif /* CONFIG_P2P */ - - if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) - return; - - if (authorized) - sta->flags |= WLAN_STA_AUTHORIZED; - else - sta->flags &= ~WLAN_STA_AUTHORIZED; - -#ifdef CONFIG_P2P - if (hapd->p2p_group == NULL) { - if (sta->p2p_ie != NULL && - p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0) - dev_addr = addr; - } else - dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); - - if (dev_addr) - os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, - MAC2STR(sta->addr), MAC2STR(dev_addr)); - else -#endif /* CONFIG_P2P */ - os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); - - if (hapd->sta_authorized_cb) - hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, - sta->addr, authorized, dev_addr); - - if (authorized) { - const char *keyid; - char keyid_buf[100]; - char ip_addr[100]; - - keyid_buf[0] = '\0'; - ip_addr[0] = '\0'; -#ifdef CONFIG_P2P - if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { - os_snprintf(ip_addr, sizeof(ip_addr), - " ip_addr=%u.%u.%u.%u", - ip_addr_buf[0], ip_addr_buf[1], - ip_addr_buf[2], ip_addr_buf[3]); - } -#endif /* CONFIG_P2P */ - - keyid = ap_sta_wpa_get_keyid(hapd, sta); - if (keyid) { - os_snprintf(keyid_buf, sizeof(keyid_buf), - " keyid=%s", keyid); - } - - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s", - buf, ip_addr, keyid_buf); - - if (hapd->msg_ctx_parent && - hapd->msg_ctx_parent != hapd->msg_ctx) - wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED "%s%s%s", - buf, ip_addr, keyid_buf); - } else { - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); - - if (hapd->msg_ctx_parent && - hapd->msg_ctx_parent != hapd->msg_ctx) - wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_DISCONNECTED "%s", buf); - } - -#ifdef CONFIG_FST - if (hapd->iface->fst) { - if (authorized) - fst_notify_peer_connected(hapd->iface->fst, sta->addr); - else - fst_notify_peer_disconnected(hapd->iface->fst, - sta->addr); - } -#endif /* CONFIG_FST */ -} - - -void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *addr, u16 reason) -{ - if (sta) - wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u", - hapd->conf->iface, __func__, MAC2STR(sta->addr), - reason); - else if (addr) - wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u", - hapd->conf->iface, __func__, MAC2STR(addr), - reason); - - if (sta == NULL && addr) - sta = ap_get_sta(hapd, addr); - - if (addr) - hostapd_drv_sta_deauth(hapd, addr, reason); - - if (sta == NULL) - return; - ap_sta_set_authorized(hapd, sta, 0); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - hostapd_set_sta_flags(hapd, sta); - wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout " - "for " MACSTR " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DEAUTH)", - hapd->conf->iface, __func__, MAC2STR(sta->addr), - AP_MAX_INACTIVITY_AFTER_DEAUTH); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, - ap_handle_timer, hapd, sta); - sta->timeout_next = STA_REMOVE; - - if (hapd->iface->current_mode && - hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { - /* Deauthentication is not used in DMG/IEEE 802.11ad; - * disassociate the STA instead. */ - sta->disassoc_reason = reason; - sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; - eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); - eloop_register_timeout(hapd->iface->drv_flags & - WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? - 2 : 0, 0, ap_sta_disassoc_cb_timeout, - hapd, sta); - return; - } - - sta->deauth_reason = reason; - sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; - eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); - eloop_register_timeout(hapd->iface->drv_flags & - WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, - ap_sta_deauth_cb_timeout, hapd, sta); -} - - -void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { - wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); - return; - } - sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; - eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); - ap_sta_deauth_cb_timeout(hapd, sta); -} - - -void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { - wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); - return; - } - sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; - eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); - ap_sta_disassoc_cb_timeout(hapd, sta); -} - - -void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, - struct sta_info *sta) -{ - if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0) - wpa_printf(MSG_DEBUG, - "%s: Removed ap_sta_deauth_cb_timeout timeout for " - MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0) - wpa_printf(MSG_DEBUG, - "%s: Removed ap_sta_disassoc_cb_timeout timeout for " - MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0) - { - wpa_printf(MSG_DEBUG, - "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for " - MACSTR, - hapd->conf->iface, MAC2STR(sta->addr)); - if (sta->flags & WLAN_STA_WPS) - hostapd_wps_eap_completed(hapd); - } -} - - -int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) -{ - int res; - - buf[0] = '\0'; - res = os_snprintf(buf, buflen, - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), - (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), - (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), - (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : - ""), - (flags & WLAN_STA_SHORT_PREAMBLE ? - "[SHORT_PREAMBLE]" : ""), - (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (flags & WLAN_STA_WMM ? "[WMM]" : ""), - (flags & WLAN_STA_MFP ? "[MFP]" : ""), - (flags & WLAN_STA_WPS ? "[WPS]" : ""), - (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), - (flags & WLAN_STA_WDS ? "[WDS]" : ""), - (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), - (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), - (flags & WLAN_STA_GAS ? "[GAS]" : ""), - (flags & WLAN_STA_HT ? "[HT]" : ""), - (flags & WLAN_STA_VHT ? "[VHT]" : ""), - (flags & WLAN_STA_HE ? "[HE]" : ""), - (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""), - (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), - (flags & WLAN_STA_WNM_SLEEP_MODE ? - "[WNM_SLEEP_MODE]" : "")); - if (os_snprintf_error(buflen, res)) - res = -1; - - return res; -} - - static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) { struct hostapd_data *hapd = eloop_ctx; @@ -1502,10 +175,8 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) "IEEE 802.1X: Scheduled disconnection of " MACSTR " after EAP-Failure", MAC2STR(sta->addr)); - reason = sta->disconnect_reason_code; - if (!reason) - reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED; - ap_sta_disconnect(hapd, sta, sta->addr, reason); + reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED; + esp_wifi_ap_deauth_internal(sta->addr, reason); if (sta->flags & WLAN_STA_WPS) hostapd_wps_eap_completed(hapd); } @@ -1535,33 +206,3 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); } - - -int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) -{ - /* - * If a station that is already associated to the AP, is trying to - * authenticate again, remove the STA entry, in order to make sure the - * STA PS state gets cleared and configuration gets updated. To handle - * this, station's added_unassoc flag is cleared once the station has - * completed association. - */ - ap_sta_set_authorized(hapd, sta, 0); - hostapd_drv_sta_remove(hapd, sta->addr); - sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED); - - if (hostapd_sta_add(hapd, sta->addr, 0, 0, - sta->supported_rates, - sta->supported_rates_len, - 0, NULL, NULL, NULL, 0, NULL, - sta->flags, 0, 0, 0, 0)) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_NOTICE, - "Could not add STA to kernel driver"); - return -1; - } - - sta->added_unassoc = 1; - return 0; -} diff --git a/components/wpa_supplicant/src/ap/sta_info.h b/components/wpa_supplicant/src/ap/sta_info.h index b187933f7e..f5ff61889f 100644 --- a/components/wpa_supplicant/src/ap/sta_info.h +++ b/components/wpa_supplicant/src/ap/sta_info.h @@ -1,6 +1,6 @@ /* * hostapd / Station table - * Copyright (c) 2002-2011, Jouni Malinen + * Copyright (c) 2002-2017, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -42,36 +42,20 @@ struct sta_info { struct sta_info *next; /* next entry in sta list */ struct sta_info *hnext; /* next entry in hash table list */ u8 addr[6]; - u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ u32 flags; /* Bitfield of WLAN_STA_* */ - u16 capability; - u16 listen_interval; /* or beacon_int for APs */ - u8 supported_rates[WLAN_SUPP_RATES_MAX]; - int supported_rates_len; - - u16 auth_alg; - - enum { - STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE - } timeout_next; + /* IEEE 802.1X related data */ + struct eapol_state_machine *eapol_sm; struct wpa_state_machine *wpa_sm; -#ifdef CONFIG_IEEE80211W - int sa_query_count; /* number of pending SA Query requests; - * 0 = no SA Query in progress */ - int sa_query_timed_out; - u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * - * sa_query_count octets of pending SA Query - * transaction identifiers */ - struct os_time sa_query_start; -#endif /* CONFIG_IEEE80211W */ + char *identity; /* User-Name from RADIUS */ #ifdef CONFIG_INTERWORKING #define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */ struct gas_dialog_info *gas_dialog; u8 gas_dialog_next; #endif /* CONFIG_INTERWORKING */ + struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ #ifdef CONFIG_SAE enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state; @@ -137,5 +121,16 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); +void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, + struct sta_info *sta); + +int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); +void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, + struct sta_info *sta); +int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, + struct sta_info *sta); +int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta); + +void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta); #endif /* STA_INFO_H */ diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index 78269bb7ae..358662d832 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -18,6 +18,7 @@ #include "hostapd.h" #include "rsn_supp/wpa.h" #include "ap/ap_config.h" +#include "ap/sta_info.h" #include "common/wpa_common.h" #include "crypto/aes_wrap.h" @@ -29,6 +30,7 @@ #include "esp_wifi_driver.h" #include "esp_wifi.h" #include "esp_private/wifi.h" +#include "esp_wpas_glue.h" #define STATE_MACHINE_DATA struct wpa_state_machine #define STATE_MACHINE_DEBUG_PREFIX "WPA" @@ -183,22 +185,7 @@ static inline int wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *data, size_t data_len, int encrypt) { - void *buffer = os_malloc(data_len + sizeof(struct l2_ethhdr)); - struct l2_ethhdr *eth = buffer; - - if (!buffer){ - wpa_printf( MSG_DEBUG, "send_eapol, buffer=%p\n", buffer); - return -1; - } - - memcpy(eth->h_dest, addr, ETH_ALEN); - memcpy(eth->h_source, wpa_auth->addr, ETH_ALEN); - eth->h_proto = host_to_be16(ETH_P_EAPOL); - - memcpy((char *)buffer + sizeof(struct l2_ethhdr), data, data_len); - esp_wifi_internal_tx(1, buffer, sizeof(struct l2_ethhdr) + data_len); - os_free(buffer); - return 0; + return hostapd_send_eapol(wpa_auth->addr, addr, data, data_len); } int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, @@ -2406,11 +2393,12 @@ bool wpa_ap_join(void** sm, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len, bool wpa_ap_remove(void* sm) { - struct wpa_state_machine *wpa_sm; - if (!sm) return false; + struct hostapd_data *hapd = hostapd_get_hapd_data(); + if (!sm || !hapd) { + return false; + } - wpa_sm = (struct wpa_state_machine*)sm; - wpa_auth_sta_deinit(wpa_sm); + ap_free_sta(hapd, sm); return true; } diff --git a/components/wpa_supplicant/src/ap/wps_hostapd.c b/components/wpa_supplicant/src/ap/wps_hostapd.c new file mode 100644 index 0000000000..a03b91b8ac --- /dev/null +++ b/components/wpa_supplicant/src/ap/wps_hostapd.c @@ -0,0 +1,586 @@ +/* + * hostapd / WPS integration + * Copyright (c) 2008-2016, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/uuid.h" +#include "common/wpa_ctrl.h" +#include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" +#include "wps/wps.h" +#include "wps/wps_defs.h" +#include "wps/wps_dev_attr.h" +#include "wps/wps_attr_parse.h" +#include "hostapd.h" +#include "ap_config.h" +#include "wpa_auth.h" +#include "wpa_auth_i.h" +#include "sta_info.h" +#include "wps/wps_i.h" +#include "wps_hostapd.h" +#include "eap_server/eap_methods.h" +#include "ieee802_1x.h" +#include "esp_wps_i.h" + +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); + +static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, + struct wpabuf *probe_resp_ie) +{ + int ret; + + wpa_printf(MSG_DEBUG, "WPS: Updating beacon IEs(%d) to driver", beacon_ie->used); + ret = esp_wifi_set_appie_internal(WIFI_APPIE_RAM_BEACON, + (uint8_t *)wpabuf_head(beacon_ie), beacon_ie->used, 0); + if (ret != ESP_OK) { + wpa_printf(MSG_ERROR, "WPS: Failed to update beacon IEs"); + goto cleanup; + } + wpa_printf(MSG_DEBUG, "WPS: Updating probe IEs(%d) to driver", probe_resp_ie->used); + ret = esp_wifi_set_appie_internal(WIFI_APPIE_RAM_PROBE_RSP, + (uint8_t *)wpabuf_head(probe_resp_ie), probe_resp_ie->used, 0); + +cleanup: + wpabuf_free(beacon_ie); + wpabuf_free(probe_resp_ie); + + return ret; +} + +struct wps_stop_reg_data { + struct hostapd_data *current_hapd; + const u8 *uuid_e; + const u8 *dev_pw; + size_t dev_pw_len; +}; + +static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx) +{ + struct wps_stop_reg_data *data = ctx; + if (hapd != data->current_hapd && hapd->wps != NULL) + wps_registrar_complete(hapd->wps->registrar, data->uuid_e, + data->dev_pw, data->dev_pw_len); + return 0; +} + +void hostapd_wps_eap_completed(struct hostapd_data *hapd) +{ +} + +static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, + const u8 *uuid_e, const u8 *dev_pw, + size_t dev_pw_len) +{ + struct hostapd_data *hapd = ctx; + char uuid[40]; + struct wps_stop_reg_data data; + if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) + return; + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", + MAC2STR(mac_addr), uuid); + data.current_hapd = hapd; + data.uuid_e = uuid_e; + data.dev_pw = dev_pw; + data.dev_pw_len = dev_pw_len; + wps_stop_registrar(hapd, &data); + wps_set_status(WPS_STATUS_DISABLE); + + /* TODO add callback event for freeRTOS */ +} + + +static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + if (hapd->conf->ap_setup_locked) + return; + if (hapd->ap_pin_failures_consecutive >= 10) + return; + + wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); +} + + +static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) +{ + struct wps_event_pwd_auth_fail *data = ctx; + + if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) + return 0; + + /* + * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup + * for some time if this happens multiple times to slow down brute + * force attacks. + */ + hapd->ap_pin_failures++; + hapd->ap_pin_failures_consecutive++; + wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u " + "(%u consecutive)", + hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); + if (hapd->ap_pin_failures < 3) + return 0; + + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); + hapd->wps->ap_setup_locked = 1; + + wps_registrar_update_ie(hapd->wps->registrar); + + if (!hapd->conf->ap_setup_locked && + hapd->ap_pin_failures_consecutive >= 10) { + /* + * In indefinite lockdown - disable automatic AP PIN + * reenablement. + */ + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely"); + } else if (!hapd->conf->ap_setup_locked) { + if (hapd->ap_pin_lockout_time == 0) + hapd->ap_pin_lockout_time = 60; + else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && + (hapd->ap_pin_failures % 3) == 0) + hapd->ap_pin_lockout_time *= 2; + + wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", + hapd->ap_pin_lockout_time); + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_register_timeout(hapd->ap_pin_lockout_time, 0, + hostapd_wps_reenable_ap_pin, hapd, + NULL); + } + + return 0; +} + + +static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, + struct wps_event_pwd_auth_fail *data) +{ + /* Update WPS Status - Authentication Failure */ + wpa_printf(MSG_DEBUG, "WPS: Authentication failure update"); + hapd->wps_stats.status = WPS_FAILURE_STATUS; + os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN); + + wps_pwd_auth_fail(hapd, data); +} + + +static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx) +{ + if (hapd->conf->ap_pin == NULL || hapd->wps == NULL) + return 0; + + if (hapd->ap_pin_failures_consecutive == 0) + return 0; + + wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter " + "- total validation failures %u (%u consecutive)", + hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive); + hapd->ap_pin_failures_consecutive = 0; + + return 0; +} + + +static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd) +{ + wps_ap_pin_success(hapd, NULL); +} + + +static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd) +{ + /* Update WPS Status - PBC Overlap */ + hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP; +} + + +static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd) +{ + /* Update WPS PBC Status:PBC Timeout */ + hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT; +} + + +static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd) +{ + /* Update WPS PBC status - Active */ + hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE; +} + + +static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd) +{ + /* Update WPS PBC status - Active */ + hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; +} + + +static void hostapd_wps_event_success(struct hostapd_data *hapd, + struct wps_event_success *success) +{ + /* Update WPS status - Success */ + hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE; + hapd->wps_stats.status = WPS_SUCCESS_STATUS; + os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN); +} + + +static void hostapd_wps_event_fail(struct hostapd_data *hapd, + struct wps_event_fail *fail) +{ + /* Update WPS status - Failure */ + hapd->wps_stats.status = WPS_FAILURE_STATUS; + os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN); + + if (fail->error_indication > 0 && + fail->error_indication < NUM_WPS_EI_VALUES) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", + fail->msg, fail->config_error, fail->error_indication, + wps_ei_str(fail->error_indication)); + } else { + wpa_msg(hapd->msg_ctx, MSG_INFO, + WPS_EVENT_FAIL "msg=%d config_error=%d", + fail->msg, fail->config_error); + } +} + + +static void hostapd_wps_event_cb(void *ctx, enum wps_event event, + union wps_event_data *data) +{ + struct hostapd_data *hapd = ctx; + + switch (event) { + case WPS_EV_M2D: + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D); + break; + case WPS_EV_FAIL: + hostapd_wps_event_fail(hapd, &data->fail); + break; + case WPS_EV_SUCCESS: + hostapd_wps_event_success(hapd, &data->success); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS); + break; + case WPS_EV_PWD_AUTH_FAIL: + hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); + break; + case WPS_EV_PBC_OVERLAP: + hostapd_wps_event_pbc_overlap(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP); + break; + case WPS_EV_PBC_TIMEOUT: + hostapd_wps_event_pbc_timeout(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT); + break; + case WPS_EV_PBC_ACTIVE: + hostapd_wps_event_pbc_active(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE); + break; + case WPS_EV_PBC_DISABLE: + hostapd_wps_event_pbc_disable(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE); + break; + case WPS_EV_ER_AP_ADD: + break; + case WPS_EV_ER_AP_REMOVE: + break; + case WPS_EV_ER_ENROLLEE_ADD: + break; + case WPS_EV_ER_ENROLLEE_REMOVE: + break; + case WPS_EV_ER_AP_SETTINGS: + break; + case WPS_EV_ER_SET_SELECTED_REGISTRAR: + break; + case WPS_EV_AP_PIN_SUCCESS: + hostapd_wps_ap_pin_success(hapd); + break; + } + if (hapd->wps_event_cb) + hapd->wps_event_cb(hapd, event, data); +} + + +static int hostapd_wps_rf_band_cb(void *ctx) +{ + return WPS_RF_24GHZ; +} + + +static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only) +{ + esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_BEACON); + esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_PROBE_RSP); +} + +static void hostapd_free_wps(struct wps_context *wps) +{ + int i; + + for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) + wpabuf_free(wps->dev.vendor_ext[i]); + wps_device_data_free(&wps->dev); + os_free(wps->network_key); + wpabuf_free(wps->dh_pubkey); + wpabuf_free(wps->dh_privkey); + os_free(wps); +} + +int hostapd_init_wps(struct hostapd_data *hapd, struct wps_data *wps_data, struct wps_context *wps) +{ + struct wps_registrar_config cfg; + + wps->event_cb = hostapd_wps_event_cb; + wps->rf_band_cb = hostapd_wps_rf_band_cb; + wps->cb_ctx = hapd; + + wps->wps_state = WPS_STATE_CONFIGURED; + wps->ap_setup_locked = 0; + wps->ap = 1; + + /* build credentials to be given */ + hostapd_wps_config_ap(hapd, wps_data); + + os_memset(&cfg, 0, sizeof(cfg)); + cfg.set_ie_cb = hostapd_wps_set_ie_cb; + cfg.reg_success_cb = hostapd_wps_reg_success_cb; + cfg.cb_ctx = hapd; + cfg.disable_auto_conf = 1; + + wps->registrar = wps_registrar_init(wps, &cfg); + if (wps->registrar == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); + goto fail; + } + + hapd->wps = wps; + + eap_server_identity_register(); + if (eap_server_wsc_register() < 0) { + wpa_printf(MSG_ERROR, "Failed to register for wsc server"); + } + if (ieee802_1x_init(hapd) < 0) { + return 0; + } + return 0; + +fail: + hostapd_free_wps(wps); + return -1; +} + + +void hostapd_deinit_wps(struct hostapd_data *hapd) +{ + eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + if (hapd->wps == NULL) { + hostapd_wps_clear_ies(hapd, 1); + return; + } + wps_registrar_deinit(hapd->wps->registrar); + hostapd_free_wps(hapd->wps); + hapd->wps = NULL; + hostapd_wps_clear_ies(hapd, 1); +} + + +void hostapd_update_wps(struct hostapd_data *hapd) +{ + struct wps_context *wps = hapd->wps; + struct hostapd_bss_config *conf = hapd->conf; + + if (!wps) + return; + + os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len); + wps->ssid_len = conf->ssid.ssid_len; + + /* Clear WPS settings, then fill them again */ + hostapd_wps_config_ap(hapd, NULL); + + wps_registrar_update_ie(wps->registrar); +} + +int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *pin) +{ + int ret; + + if (hapd->wps == NULL) + return 0; + ret = wps_registrar_add_pin(hapd->wps->registrar, NULL, + NULL, pin, 8, 120); + return ret; +} + +int hostapd_wps_button_pushed(struct hostapd_data *hapd, + const u8 *p2p_dev_addr) +{ + if (hapd->wps) { + return wps_registrar_button_pushed(hapd->wps->registrar, + p2p_dev_addr); + } + return 0; +} + + +static int wps_cancel(struct hostapd_data *hapd) +{ + if (hapd->wps) { + wps_registrar_wps_cancel(hapd->wps->registrar); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_CANCEL); + } + + return 0; +} + + +int hostapd_wps_cancel(struct hostapd_data *hapd) +{ + int ret; + + ret = wps_cancel(hapd); + return ret; +} + + +static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); + hostapd_wps_ap_pin_disable(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED); +} + + +static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) +{ + wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); + hapd->ap_pin_failures = 0; + hapd->ap_pin_failures_consecutive = 0; + hapd->conf->ap_setup_locked = 0; + if (hapd->wps->ap_setup_locked) { + wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); + hapd->wps->ap_setup_locked = 0; + wps_registrar_update_ie(hapd->wps->registrar); + } + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + if (timeout > 0) + eloop_register_timeout(timeout, 0, + hostapd_wps_ap_pin_timeout, hapd, NULL); +} + +static int wps_ap_pin_disable(struct hostapd_data *hapd) +{ + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = NULL; + eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + return 0; +} + + +void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); + wps_ap_pin_disable(hapd); +} + + +struct wps_ap_pin_data { + char pin_txt[9]; + int timeout; +}; + + +static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) +{ + struct wps_ap_pin_data *data = ctx; + + if (!hapd->wps) + return 0; + + os_free(hapd->conf->ap_pin); + hapd->conf->ap_pin = os_strdup(data->pin_txt); + hostapd_wps_ap_pin_enable(hapd, data->timeout); + return 0; +} + + +const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) +{ + unsigned int pin; + struct wps_ap_pin_data data; + + if (wps_generate_pin(&pin) < 0) + return NULL; + os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin); + data.timeout = timeout; + wps_ap_pin_set(hapd, &data); + return hapd->conf->ap_pin; +} + +const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) +{ + return hapd->conf->ap_pin; +} + + +int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, + int timeout) +{ + struct wps_ap_pin_data data; + int ret; + + ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); + if (os_snprintf_error(sizeof(data.pin_txt), ret)) + return -1; + data.timeout = timeout; + return wps_ap_pin_set(hapd, &data); +} + + +int hostapd_wps_config_ap(struct hostapd_data *hapd, struct wps_data *wps_data) +{ + struct wps_credential cred = {0}; + + os_memcpy(cred.ssid, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); + cred.ssid_len = hapd->conf->ssid.ssid_len; + cred.encr_type = WPS_ENCR_NONE; + cred.auth_type = WPS_AUTH_OPEN; + + if (hapd->wpa_auth->conf.wpa == WPA_PROTO_WPA) { + cred.auth_type = WPS_AUTH_WPAPSK; + cred.encr_type = WPS_ENCR_TKIP; + } else if (hapd->wpa_auth->conf.wpa == WPA_PROTO_RSN) { + cred.auth_type = WPS_AUTH_WPA2PSK; + cred.encr_type = WPS_ENCR_AES; + } else if (hapd->wpa_auth->conf.wpa == (WPA_PROTO_RSN | WPA_PROTO_WPA)) { + cred.auth_type = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; + cred.encr_type = WPS_ENCR_AES; + } + + if (hapd->conf->ssid.wpa_passphrase) { + cred.key_len = os_strlen(hapd->conf->ssid.wpa_passphrase); + memcpy(cred.key, hapd->conf->ssid.wpa_passphrase, cred.key_len); + } + wps_data->use_cred = os_malloc(sizeof(struct wps_credential)); + if (!wps_data->use_cred) { + wpa_printf(MSG_ERROR, "WPS: Disabling AP PIN"); + return -1; + } + os_memcpy(wps_data->use_cred, &cred, sizeof(struct wps_credential)); + return 0; +} diff --git a/components/wpa_supplicant/src/ap/wps_hostapd.h b/components/wpa_supplicant/src/ap/wps_hostapd.h index 204bd820a5..8c4b584a39 100644 --- a/components/wpa_supplicant/src/ap/wps_hostapd.h +++ b/components/wpa_supplicant/src/ap/wps_hostapd.h @@ -11,14 +11,12 @@ #ifdef CONFIG_WPS -int hostapd_init_wps(struct hostapd_data *hapd, - struct hostapd_bss_config *conf); +int hostapd_init_wps(struct hostapd_data *hapd, struct wps_data *wps_data, struct wps_context *wps); int hostapd_init_wps_complete(struct hostapd_data *hapd); void hostapd_deinit_wps(struct hostapd_data *hapd); void hostapd_update_wps(struct hostapd_data *hapd); void hostapd_wps_eap_completed(struct hostapd_data *hapd); -int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, - const char *uuid, const char *pin, int timeout); +int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *pin); int hostapd_wps_button_pushed(struct hostapd_data *hapd, const u8 *p2p_dev_addr); int hostapd_wps_cancel(struct hostapd_data *hapd); @@ -30,24 +28,12 @@ const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd); int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, int timeout); void hostapd_wps_update_ie(struct hostapd_data *hapd); -int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, - const char *auth, const char *encr, const char *key); +int hostapd_wps_config_ap(struct hostapd_data *hapd, struct wps_data *wps_data); int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd, const struct wpabuf *data); -struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd, - int ndef); -struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef); -int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd, - const struct wpabuf *req, - const struct wpabuf *sel); -struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef); -int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd); -void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd); - #else /* CONFIG_WPS */ -static inline int hostapd_init_wps(struct hostapd_data *hapd, - struct hostapd_bss_config *conf) +static inline int hostapd_init_wps(struct hostapd_data *hapd, struct wps_data *wps_data, struct wps_context *wps) { return 0; } diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.c b/components/wpa_supplicant/src/common/ieee802_11_common.c index 8c1af162b3..ea67cff967 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.c +++ b/components/wpa_supplicant/src/common/ieee802_11_common.c @@ -228,6 +228,39 @@ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t return 0; } +struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, + u32 oui_type) +{ + struct wpabuf *buf; + const struct element *elem, *found = NULL; + + for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { + if (elem->datalen >= 4 && + WPA_GET_BE32(elem->data) == oui_type) { + found = elem; + break; + } + } + + if (!found) + return NULL; /* No specified vendor IE found */ + + buf = wpabuf_alloc(ies_len); + if (buf == NULL) + return NULL; + + /* + * There may be multiple vendor IEs in the message, so need to + * concatenate their data fields. + */ + for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) { + if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type) + wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4); + } + + return buf; +} + int ieee802_11_ext_capab(const u8 *ie, unsigned int capab) { if (!ie || ie[1] <= capab / 8) diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.h b/components/wpa_supplicant/src/common/ieee802_11_common.h index c210562c44..aa150fbf6a 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_common.h +++ b/components/wpa_supplicant/src/common/ieee802_11_common.h @@ -43,4 +43,6 @@ const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); u8 get_operating_class(u8 chan, int sec_channel); int ieee802_11_ie_count(const u8 *ies, size_t ies_len); +struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, + u32 oui_type); #endif /* IEEE802_11_COMMON_H */ diff --git a/components/wpa_supplicant/src/eap_peer/eap_defs.h b/components/wpa_supplicant/src/eap_peer/eap_defs.h index 10995d3868..da5f549c72 100644 --- a/components/wpa_supplicant/src/eap_peer/eap_defs.h +++ b/components/wpa_supplicant/src/eap_peer/eap_defs.h @@ -1,6 +1,6 @@ /* * EAP server/peer: Shared EAP definitions - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -22,22 +22,49 @@ struct eap_hdr { /* followed by length-4 octets of data */ } STRUCT_PACKED; - #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, - EAP_CODE_FAILURE = 4 }; + EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 }; /* EAP Request and Response data begins with one octet Type. Success and * Failure do not have additional data. */ +/* Type field in EAP-Initiate and EAP-Finish messages */ +enum eap_erp_type { + EAP_ERP_TYPE_REAUTH_START = 1, + EAP_ERP_TYPE_REAUTH = 2, +}; + +/* ERP TV/TLV types */ +enum eap_erp_tlv_type { + EAP_ERP_TLV_KEYNAME_NAI = 1, + EAP_ERP_TV_RRK_LIFETIME = 2, + EAP_ERP_TV_RMSK_LIFETIME = 3, + EAP_ERP_TLV_DOMAIN_NAME = 4, + EAP_ERP_TLV_CRYPTOSUITES = 5, + EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6, + EAP_ERP_TLV_CALLED_STATION_ID = 128, + EAP_ERP_TLV_CALLING_STATION_ID = 129, + EAP_ERP_TLV_NAS_IDENTIFIER = 130, + EAP_ERP_TLV_NAS_IP_ADDRESS = 131, + EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132, +}; + +/* ERP Cryptosuite */ +enum eap_erp_cryptosuite { + EAP_ERP_CS_HMAC_SHA256_64 = 1, + EAP_ERP_CS_HMAC_SHA256_128 = 2, + EAP_ERP_CS_HMAC_SHA256_256 = 3, +}; + /* * EAP Method Types as allocated by IANA: * http://www.iana.org/assignments/eap-numbers */ -typedef enum { +typedef enum eap_type { EAP_TYPE_NONE = 0, EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, @@ -65,6 +92,7 @@ typedef enum { EAP_TYPE_GPSK = 51 /* RFC 5433 */, EAP_TYPE_PWD = 52 /* RFC 5931 */, EAP_TYPE_EKE = 53 /* RFC 6124 */, + EAP_TYPE_TEAP = 55 /* RFC 7170 */, EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ } EapType; @@ -73,8 +101,9 @@ typedef enum { enum { EAP_VENDOR_IETF = 0, EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, - EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */, - EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */ + EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */, + EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */, + EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */ }; struct eap_expand { @@ -86,7 +115,11 @@ struct eap_expand { #define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP #define EAP_VENDOR_TYPE_UNAUTH_TLS 1 +#define EAP_VENDOR_WFA_UNAUTH_TLS 13 + #define EAP_MSK_LEN 64 #define EAP_EMSK_LEN 64 +#define EAP_EMSK_NAME_LEN 8 +#define ERP_MAX_KEY_LEN 64 #endif /* EAP_DEFS_H */ diff --git a/components/wpa_supplicant/src/eap_server/eap.h b/components/wpa_supplicant/src/eap_server/eap.h index 61032cc016..5d18ea51b3 100644 --- a/components/wpa_supplicant/src/eap_server/eap.h +++ b/components/wpa_supplicant/src/eap_server/eap.h @@ -11,9 +11,9 @@ #include "common/defs.h" #include "utils/list.h" -#include "eap_common/eap_defs.h" +#include "eap_peer/eap_defs.h" #include "eap_server/eap_methods.h" -#include "wpabuf.h" +#include "utils/wpabuf.h" struct eap_sm; @@ -66,6 +66,7 @@ struct eap_eapol_interface { size_t eapSessionIdLen; bool eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */ +#ifndef ESP_SUPPLICANT /* AAA interface to full authenticator variables */ bool aaaEapReq; bool aaaEapNoReq; @@ -82,6 +83,7 @@ struct eap_eapol_interface { struct wpabuf *aaaEapRespData; /* aaaIdentity -> eap_get_identity() */ bool aaaTimeout; +#endif }; struct eap_server_erp_key { diff --git a/components/wpa_supplicant/src/eap_server/eap_i.h b/components/wpa_supplicant/src/eap_server/eap_i.h index 28bb564e93..016c481893 100644 --- a/components/wpa_supplicant/src/eap_server/eap_i.h +++ b/components/wpa_supplicant/src/eap_server/eap_i.h @@ -9,9 +9,9 @@ #ifndef EAP_I_H #define EAP_I_H -#include "wpabuf.h" +#include "utils/wpabuf.h" #include "eap_server/eap.h" -#include "eap_common/eap_common.h" +#include "eap_peer/eap_common.h" /* RFC 4137 - EAP Standalone Authenticator */ diff --git a/components/wpa_supplicant/src/eap_server/eap_methods.h b/components/wpa_supplicant/src/eap_server/eap_methods.h index ad60700fa5..d3c2142199 100644 --- a/components/wpa_supplicant/src/eap_server/eap_methods.h +++ b/components/wpa_supplicant/src/eap_server/eap_methods.h @@ -9,7 +9,7 @@ #ifndef EAP_SERVER_METHODS_H #define EAP_SERVER_METHODS_H -#include "eap_common/eap_defs.h" +#include "eap_peer/eap_defs.h" const struct eap_method * eap_server_get_eap_method(int vendor, enum eap_type method); diff --git a/components/wpa_supplicant/src/eap_server/eap_server.c b/components/wpa_supplicant/src/eap_server/eap_server.c index 0b7a5b98cf..a0aaf8e652 100644 --- a/components/wpa_supplicant/src/eap_server/eap_server.c +++ b/components/wpa_supplicant/src/eap_server/eap_server.c @@ -29,7 +29,9 @@ static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, int eapSRTT, int eapRTTVAR, int methodTimeout); static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); +#ifndef ESP_SUPPLICANT static int eap_sm_getId(const struct wpabuf *data); +#endif static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); static int eap_sm_nextId(struct eap_sm *sm, int id); @@ -43,8 +45,6 @@ static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method); static int eap_get_erp_send_reauth_start(struct eap_sm *sm) { - if (sm->eapol_cb->get_erp_send_reauth_start) - return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx); return 0; } @@ -120,6 +120,7 @@ static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) } +#ifndef ESP_SUPPLICANT static int eap_copy_data(u8 **dst, size_t *dst_len, const u8 *src, size_t src_len) { @@ -137,6 +138,7 @@ static int eap_copy_data(u8 **dst, size_t *dst_len, return -1; } } +#endif #define EAP_COPY(dst, src) \ eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) @@ -994,6 +996,7 @@ fail: #endif /* CONFIG_ERP */ +#ifndef ESP_SUPPLICANT SM_STATE(EAP, INITIALIZE_PASSTHROUGH) { SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); @@ -1161,6 +1164,7 @@ SM_STATE(EAP, SUCCESS2) wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR, MAC2STR(sm->peer_addr)); } +#endif SM_STEP(EAP) @@ -1346,8 +1350,10 @@ SM_STEP(EAP) SM_ENTER(EAP, FAILURE); else if (sm->decision == DECISION_SUCCESS) SM_ENTER(EAP, SUCCESS); +#ifndef ESP_SUPPLICANT else if (sm->decision == DECISION_PASSTHROUGH) SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); +#endif else if (sm->decision == DECISION_INITIATE_REAUTH_START) SM_ENTER(EAP, INITIATE_REAUTH_START); #ifdef CONFIG_ERP @@ -1370,7 +1376,7 @@ SM_STEP(EAP) break; case EAP_SUCCESS: break; - +#ifndef ESP_SUPPLICANT case EAP_INITIALIZE_PASSTHROUGH: if (sm->currentId == -1) SM_ENTER(EAP, AAA_IDLE); @@ -1423,6 +1429,10 @@ SM_STEP(EAP) break; case EAP_SUCCESS2: break; +#else + default: + break; +#endif } } @@ -1545,6 +1555,7 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) } +#ifndef ESP_SUPPLICANT static int eap_sm_getId(const struct wpabuf *data) { const struct eap_hdr *hdr; @@ -1556,7 +1567,7 @@ static int eap_sm_getId(const struct wpabuf *data) wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); return hdr->identifier; } - +#endif static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) { @@ -1873,6 +1884,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx, #ifdef CONFIG_TESTING_OPTIONS sm->tls_test_flags = sess->tls_test_flags; #endif /* CONFIG_TESTING_OPTIONS */ + sm->eap_if.portEnabled = 1; wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); @@ -1901,9 +1913,11 @@ void eap_server_sm_deinit(struct eap_sm *sm) wpabuf_free(sm->eap_if.eapRespData); os_free(sm->identity); os_free(sm->serial_num); +#ifndef ESP_SUPPLICANT wpabuf_free(sm->eap_if.aaaEapReqData); wpabuf_free(sm->eap_if.aaaEapRespData); bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen); +#endif eap_user_free(sm->user); wpabuf_free(sm->assoc_wps_ie); wpabuf_free(sm->assoc_p2p_ie); diff --git a/components/wpa_supplicant/src/eap_server/eap_server_identity.c b/components/wpa_supplicant/src/eap_server/eap_server_identity.c index 813e1d6de5..0f707c482c 100644 --- a/components/wpa_supplicant/src/eap_server/eap_server_identity.c +++ b/components/wpa_supplicant/src/eap_server/eap_server_identity.c @@ -123,7 +123,7 @@ static void eap_identity_process(struct eap_sm *sm, void *priv, buf = os_malloc(len * 4 + 1); if (buf) { printf_encode(buf, len * 4 + 1, pos, len); - eap_log_msg(sm, "EAP-Response/Identity '%s'", buf); + wpa_printf(MSG_DEBUG, "EAP-Response/Identity '%s'", buf); os_free(buf); } if (sm->identity) diff --git a/components/wpa_supplicant/src/eap_server/eap_server_wsc.c b/components/wpa_supplicant/src/eap_server/eap_server_wsc.c index a162deb9ef..861d97ab9c 100644 --- a/components/wpa_supplicant/src/eap_server/eap_server_wsc.c +++ b/components/wpa_supplicant/src/eap_server/eap_server_wsc.c @@ -12,12 +12,12 @@ #include "eloop.h" #include "eap_i.h" #include "eap_common/eap_wsc_common.h" -#include "p2p/p2p.h" #include "wps/wps.h" +#include "esp_wps_i.h" struct eap_wsc_data { - enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; + enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, WSC_FAIL } state; int registrar; struct wpabuf *in_buf; struct wpabuf *out_buf; @@ -28,8 +28,7 @@ struct eap_wsc_data { int ext_reg_timeout; }; - -#ifndef CONFIG_NO_STDOUT_DEBUG +#ifdef DEBUG_PRINT static const char * eap_wsc_state_txt(int state) { switch (state) { @@ -43,14 +42,13 @@ static const char * eap_wsc_state_txt(int state) return "WAIT_FRAG_ACK"; case DONE: return "DONE"; - case FAIL: + case WSC_FAIL: return "FAIL"; default: return "?"; } } -#endif /* CONFIG_NO_STDOUT_DEBUG */ - +#endif static void eap_wsc_state(struct eap_wsc_data *data, int state) { @@ -61,26 +59,10 @@ static void eap_wsc_state(struct eap_wsc_data *data, int state) } -static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct eap_sm *sm = eloop_ctx; - struct eap_wsc_data *data = timeout_ctx; - - if (sm->method_pending != METHOD_PENDING_WAIT) - return; - - wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " - "Registrar"); - data->ext_reg_timeout = 1; - eap_sm_pending_cb(sm); -} - - static void * eap_wsc_init(struct eap_sm *sm) { struct eap_wsc_data *data; int registrar; - struct wps_config cfg; if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == @@ -102,52 +84,13 @@ static void * eap_wsc_init(struct eap_sm *sm) data->state = registrar ? START : MESG; data->registrar = registrar; - os_memset(&cfg, 0, sizeof(cfg)); - cfg.wps = sm->cfg->wps; - cfg.registrar = registrar; - if (registrar) { - if (!sm->cfg->wps || !sm->cfg->wps->registrar) { - wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " - "initialized"); - os_free(data); - return NULL; - } - } else { - if (sm->user == NULL || sm->user->password == NULL) { - /* - * In theory, this should not really be needed, but - * Windows 7 uses Registrar mode to probe AP's WPS - * capabilities before trying to use Enrollee and fails - * if the AP does not allow that probing to happen.. - */ - wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " - "configured for Enrollee functionality - " - "allow for probing capabilities (M1)"); - } else { - cfg.pin = sm->user->password; - cfg.pin_len = sm->user->password_len; - } - } - cfg.assoc_wps_ie = sm->assoc_wps_ie; - cfg.peer_addr = sm->peer_addr; -#ifdef CONFIG_P2P - if (sm->assoc_p2p_ie) { - if (!sm->cfg->wps->use_passphrase) { - wpa_printf(MSG_DEBUG, - "EAP-WSC: Prefer PSK format for non-6 GHz P2P client"); - cfg.use_psk_key = 1; - } - cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); - } -#endif /* CONFIG_P2P */ - cfg.pbc_in_m1 = sm->cfg->pbc_in_m1; - data->wps = wps_init(&cfg); + struct wps_sm *wps_sm = wps_sm_get(); + data->wps = wps_sm->wps; if (data->wps == NULL) { os_free(data); return NULL; } - data->fragment_size = sm->cfg->fragment_size > 0 ? - sm->cfg->fragment_size : WSC_FRAGMENT_SIZE; + data->fragment_size = WSC_FRAGMENT_SIZE; return data; } @@ -156,7 +99,6 @@ static void * eap_wsc_init(struct eap_sm *sm) static void eap_wsc_reset(struct eap_sm *sm, void *priv) { struct eap_wsc_data *data = priv; - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); wpabuf_free(data->in_buf); wpabuf_free(data->out_buf); wps_deinit(data->wps); @@ -297,13 +239,13 @@ static int eap_wsc_process_cont(struct eap_wsc_data *data, wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " "fragment (expected %d)", op_code, data->in_op_code); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return -1; } if (len > wpabuf_tailroom(data->in_buf)) { wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return -1; } @@ -358,9 +300,8 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, enum wps_process_res res; struct wpabuf tmpbuf; - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); if (data->ext_reg_timeout) { - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return; } @@ -397,7 +338,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, if (op_code != WSC_FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " "in WAIT_FRAG_ACK state", op_code); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); @@ -409,13 +350,13 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, op_code != WSC_Done) { wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", op_code); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return; } if (data->in_buf && eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); return; } @@ -423,7 +364,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, if (eap_wsc_process_fragment(data, flags, op_code, message_length, pos, end - pos) < 0) - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); else eap_wsc_state(data, FRAG_ACK); return; @@ -440,21 +381,20 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, case WPS_DONE: wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " "successfully - report EAP failure"); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); break; case WPS_CONTINUE: eap_wsc_state(data, MESG); break; case WPS_FAILURE: wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); - eap_wsc_state(data, FAIL); + eap_wsc_state(data, WSC_FAIL); break; case WPS_PENDING: eap_wsc_state(data, MESG); sm->method_pending = METHOD_PENDING_WAIT; - eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); - eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, - sm, data); + break; + default: break; } @@ -467,7 +407,7 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv, static bool eap_wsc_isDone(struct eap_sm *sm, void *priv) { struct eap_wsc_data *data = priv; - return data->state == FAIL; + return data->state == WSC_FAIL; } diff --git a/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm.c b/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm.c index 1c11cb613b..c77f40b00e 100644 --- a/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm.c +++ b/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm.c @@ -12,8 +12,8 @@ #include "eloop.h" #include "state_machine.h" #include "common/eapol_common.h" -#include "eap_common/eap_defs.h" -#include "eap_common/eap_common.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" #include "eap_server/eap.h" #include "eapol_auth_sm.h" #include "eapol_auth_sm_i.h" @@ -45,7 +45,7 @@ static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx); static void eapol_auth_initialize(struct eapol_state_machine *sm); static void eapol_auth_conf_free(struct eapol_auth_config *conf); - +#ifndef ESP_SUPPLICANT static void eapol_auth_logger(struct eapol_authenticator *eapol, const u8 *addr, eapol_logger_level level, const char *txt) @@ -81,7 +81,11 @@ static void eapol_auth_vlogger(struct eapol_authenticator *eapol, os_free(format); } +#else +#define eapol_auth_logger(...) do {} while(0) +#define eapol_auth_vlogger(...) do {} while (0) +#endif static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm, int success) @@ -297,8 +301,6 @@ SM_STATE(AUTH_PAE, HELD) SM_STATE(AUTH_PAE, AUTHENTICATED) { - char *extra = ""; - if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess) sm->authAuthSuccessesWhileAuthenticating++; @@ -307,15 +309,6 @@ SM_STATE(AUTH_PAE, AUTHENTICATED) sm->authPortStatus = Authorized; setPortAuthorized(); sm->reAuthCount = 0; - if (sm->flags & EAPOL_SM_PREAUTH) - extra = " (pre-authentication)"; - else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE) - extra = " (PMKSA cache)"; - eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, - "authenticated - EAP type: %d (%s)%s", - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - extra); sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, sm->flags & EAPOL_SM_PREAUTH, sm->remediation); } @@ -849,11 +842,11 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, if (sm->identity) sm->identity_len = os_strlen(identity); } +#ifndef CONFIG_NO_RADIUS if (radius_cui) sm->radius_cui = wpabuf_alloc_copy(radius_cui, os_strlen(radius_cui)); -#ifndef CONFIG_NO_RADIUS if (radius_gen_session_id((u8 *) &sm->acct_multi_session_id, sizeof(sm->acct_multi_session_id)) < 0) { eapol_auth_free(sm); @@ -875,7 +868,9 @@ void eapol_auth_free(struct eapol_state_machine *sm) if (sm->eap) eap_server_sm_deinit(sm->eap); +#ifndef CONFIG_NO_RADIUS wpabuf_free(sm->radius_cui); +#endif /* CONFIG_NO_RADIUS */ os_free(sm->identity); os_free(sm); } @@ -948,6 +943,7 @@ restart: return; } +#ifndef ESP_SUPPLICANT /* TODO: find a better location for this */ if (sm->eap_if->aaaEapResp) { sm->eap_if->aaaEapResp = false; @@ -961,6 +957,7 @@ restart: wpabuf_head(sm->eap_if->aaaEapRespData), wpabuf_len(sm->eap_if->aaaEapRespData)); } +#endif } if (eapol_sm_sta_entry_alive(eapol, addr)) diff --git a/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm_i.h b/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm_i.h index 3c68983102..a8a5850c96 100644 --- a/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm_i.h +++ b/components/wpa_supplicant/src/eapol_auth/eapol_auth_sm_i.h @@ -10,7 +10,6 @@ #define EAPOL_AUTH_SM_I_H #include "common/defs.h" -#include "radius/radius.h" /* IEEE Std 802.1X-2004, Ch. 8.2 */ @@ -156,8 +155,9 @@ struct eapol_state_machine { u8 eap_type_authsrv; /* EAP type of the last EAP packet from * Authentication server */ u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */ - struct radius_class_data radius_class; +#ifndef CONFIG_NO_RADIUS struct wpabuf *radius_cui; /* Chargeable-User-Identity */ +#endif struct eap_sm *eap; diff --git a/components/wpa_supplicant/src/wps/wps.c b/components/wpa_supplicant/src/wps/wps.c index 9265c2436a..bb46ef3996 100644 --- a/components/wpa_supplicant/src/wps/wps.c +++ b/components/wpa_supplicant/src/wps/wps.c @@ -49,7 +49,7 @@ struct wps_data * wps_init(const struct wps_config *cfg) os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); } - if (cfg->pin) { + if (cfg->pbc == 0 && cfg->pin_len) { data->dev_pw_id = cfg->dev_pw_id; data->dev_password = os_memdup(cfg->pin, cfg->pin_len); if (data->dev_password == NULL) { @@ -226,10 +226,7 @@ enum wps_process_res wps_process_msg(struct wps_data *wps, */ struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) { - if (wps->registrar) return wps_registrar_get_msg(wps, op_code); - else - return wps_enrollee_get_msg(wps, op_code); } diff --git a/components/wpa_supplicant/src/wps/wps.h b/components/wpa_supplicant/src/wps/wps.h index aaf45cfc40..a77622fb0e 100644 --- a/components/wpa_supplicant/src/wps/wps.h +++ b/components/wpa_supplicant/src/wps/wps.h @@ -121,7 +121,7 @@ struct wps_config { /** * pin - Enrollee Device Password (%NULL for Registrar or PBC) */ - const u8 *pin; + const u8 pin[9]; /** * pin_len - Length on pin in octets @@ -132,7 +132,7 @@ struct wps_config { * pbc - Whether this is protocol run uses PBC */ int pbc; -#ifndef ESP_SUPPLICANT +#ifdef CONFIG_WPS_REGISTRAR /** * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP) */ @@ -161,7 +161,6 @@ struct wps_config { * struct wpa_context::psk. */ int use_psk_key; - #endif /** * dev_pw_id - Device Password ID for Enrollee when PIN is used @@ -228,7 +227,6 @@ enum wps_process_res { * event (e.g., UPnP message from an external Registrar) */ WPS_PENDING, - WPS_IGNORE, /* snake, ignore the re-packge */ WPS_FRAGMENT /* Tim, send wsc fragment ack */ }; diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c index 59e128d5c3..6f53d907c6 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -152,11 +152,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) wps_build_wps_state(wps, msg) || wps_build_device_attrs(&wps->wps->dev, msg) || wps_build_rf_bands(&wps->wps->dev, msg, -#ifdef ESP_SUPPLICANT - wps->wps->dev.rf_bands) || -#else wps->wps->rf_band_cb(wps->wps->cb_ctx)) || -#endif wps_build_assoc_state(wps, msg) || wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_config_error(msg, WPS_CFG_NO_ERROR) || @@ -245,6 +241,7 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps) } +#ifndef ESP_SUPPLICANT static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg) { wpa_printf(MSG_DEBUG, "WPS: * SSID"); @@ -351,13 +348,12 @@ static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg) wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN); return 0; } - +#endif static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain) { -#ifdef DEBUG_PRINT +#ifndef ESP_SUPPLICANT const u8 *start, *end; -#endif int ret; if (wps->wps->ap_settings) { @@ -368,22 +364,21 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain) } wpa_printf(MSG_DEBUG, "WPS: * AP Settings based on current configuration"); -#ifdef DEBUG_PRINT start = wpabuf_put(plain, 0); -#endif ret = wps_build_cred_ssid(wps, plain) || wps_build_cred_mac_addr(wps, plain) || wps_build_cred_auth_type(wps, plain) || wps_build_cred_encr_type(wps, plain) || wps_build_cred_network_key(wps, plain); -#ifdef DEBUG_PRINT end = wpabuf_put(plain, 0); wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings", start, end - start); -#endif return ret; +#else + return 0; +#endif } diff --git a/components/wpa_supplicant/src/wps/wps_registrar.c b/components/wpa_supplicant/src/wps/wps_registrar.c index 14c9072a05..d16210b830 100644 --- a/components/wpa_supplicant/src/wps/wps_registrar.c +++ b/components/wpa_supplicant/src/wps/wps_registrar.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "utils/base64.h" +#include "utils/eloop.h" #include "utils/uuid.h" #include "utils/list.h" #include "crypto/crypto.h" @@ -699,6 +700,7 @@ wps_registrar_init(struct wps_context *wps, reg->dualband = cfg->dualband; reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk; +#ifndef ESP_SUPPLICANT if (cfg->multi_ap_backhaul_ssid) { os_memcpy(reg->multi_ap_backhaul_ssid, cfg->multi_ap_backhaul_ssid, @@ -714,6 +716,7 @@ wps_registrar_init(struct wps_context *wps, reg->multi_ap_backhaul_network_key_len = cfg->multi_ap_backhaul_network_key_len; } +#endif if (wps_set_ie(reg)) { wps_registrar_deinit(reg); @@ -1291,6 +1294,7 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg) } +#ifndef ESP_SUPPLICANT static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr, const u8 **psk) { @@ -1298,7 +1302,7 @@ static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr, return 0; return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk); } - +#endif static int wps_set_ie(struct wps_registrar *reg) { @@ -1619,9 +1623,11 @@ int wps_build_credential_wrap(struct wpabuf *msg, int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *cred; +#ifndef ESP_SUPPLICANT struct wps_registrar *reg = wps->wps->registrar; const u8 *pskfile_psk; char hex[65]; +#endif if (wps->wps->registrar->skip_cred_build) goto skip_cred_build; @@ -1631,6 +1637,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred)); goto use_provided; } +#ifndef ESP_SUPPLICANT os_memset(&wps->cred, 0, sizeof(wps->cred)); if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA && @@ -1741,12 +1748,23 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->new_psk, wps->new_psk_len); os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len); wps->cred.key_len = wps->new_psk_len; - } else if (wps->use_psk_key && wps->wps->psk_set) { - char hex[65] = {0}; - wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); - os_memcpy(wps->cred.key, hex, 32 * 2); - wps->cred.key_len = 32 * 2; - } else if (wps->wps->network_key) { + } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) { + wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file", + pskfile_psk, PMK_LEN); + wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN); + os_memcpy(wps->cred.key, hex, PMK_LEN * 2); + wps->cred.key_len = PMK_LEN * 2; + } else if (!wps->wps->registrar->force_per_enrollee_psk && + wps->use_psk_key && wps->wps->psk_set) { + wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); + wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN); + os_memcpy(wps->cred.key, hex, PMK_LEN * 2); + wps->cred.key_len = PMK_LEN * 2; + } else + if ((!wps->wps->registrar->force_per_enrollee_psk || + wps->wps->use_passphrase) && wps->wps->network_key) { + wpa_printf(MSG_DEBUG, + "WPS: Use passphrase format for Network key"); os_memcpy(wps->cred.key, wps->wps->network_key, wps->wps->network_key_len); wps->cred.key_len = wps->wps->network_key_len; @@ -1772,6 +1790,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2); wps->cred.key_len = wps->new_psk_len * 2; } +#endif use_provided: #ifdef CONFIG_WPS_TESTING @@ -1836,6 +1855,7 @@ static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg) } +#ifndef ESP_SUPPLICANT static struct wpabuf * wps_build_ap_cred(struct wps_data *wps) { struct wpabuf *msg, *plain; @@ -1863,6 +1883,7 @@ static struct wpabuf * wps_build_ap_cred(struct wps_data *wps) return msg; } +#endif static struct wpabuf * wps_build_m2(struct wps_data *wps) @@ -2563,32 +2584,22 @@ static int wps_process_wps_state(struct wps_data *wps, const u8 *state) static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc) { - u16 a; - if (assoc == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Association State received"); return -1; } - a = WPA_GET_BE16(assoc); - wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a); - return 0; } static int wps_process_config_error(struct wps_data *wps, const u8 *err) { - u16 e; - if (err == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received"); return -1; } - e = WPA_GET_BE16(err); - wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e); - return 0; } @@ -2863,6 +2874,7 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps, } +#ifndef ESP_SUPPLICANT static void wps_sta_cred_cb(struct wps_data *wps) { /* @@ -2949,8 +2961,15 @@ static int wps_process_ap_settings_r(struct wps_data *wps, return 1; } + return 0; } - +#else +static int wps_process_ap_settings_r(struct wps_data *wps, + struct wps_parse_attr *attr) +{ + return 0; +} +#endif static enum wps_process_res wps_process_m7(struct wps_data *wps, const struct wpabuf *msg, @@ -3301,6 +3320,7 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, } wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully"); +#ifndef ESP_SUPPLICANT wps_device_store(wps->wps->registrar, &wps->peer_dev, wps->uuid_e); @@ -3349,6 +3369,7 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, wps->new_psk = NULL; } +#endif wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e, wps->dev_password, wps->dev_password_len);