mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/11kv_roaming' into 'master'
esp_wifi: 11kv support for network assisted roaming Closes WIFI-2471 See merge request espressif/esp-idf!9474
This commit is contained in:
commit
a139bceb0a
@ -52,6 +52,9 @@ static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id)
|
||||
case WIFI_EVENT_STA_AUTHMODE_CHANGE:
|
||||
return SYSTEM_EVENT_STA_AUTHMODE_CHANGE;
|
||||
|
||||
case WIFI_EVENT_STA_BSS_RSSI_LOW:
|
||||
return SYSTEM_EVENT_STA_BSS_RSSI_LOW;
|
||||
|
||||
case WIFI_EVENT_STA_WPS_ER_SUCCESS:
|
||||
return SYSTEM_EVENT_STA_WPS_ER_SUCCESS;
|
||||
|
||||
|
@ -36,6 +36,7 @@ typedef enum {
|
||||
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /*!< the auth mode of AP connected by ESP32 station changed */
|
||||
SYSTEM_EVENT_STA_GOT_IP, /*!< ESP32 station got IP from connected AP */
|
||||
SYSTEM_EVENT_STA_LOST_IP, /*!< ESP32 station lost IP and the IP is reset to 0 */
|
||||
SYSTEM_EVENT_STA_BSS_RSSI_LOW, /*!< ESP32 station connected BSS rssi goes below threshold */
|
||||
SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /*!< ESP32 station wps succeeds in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_FAILED, /*!< ESP32 station wps fails in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /*!< ESP32 station wps timeout in enrollee mode */
|
||||
|
@ -229,7 +229,7 @@ extern uint64_t g_wifi_feature_caps;
|
||||
* @attention 2. Always use WIFI_INIT_CONFIG_DEFAULT macro to init the config to default values, this can
|
||||
* guarantee all the fields got correct value when more fields are added into wifi_init_config_t
|
||||
* in future release. If you want to set your owner initial values, overwrite the default values
|
||||
* which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field 'magic' of
|
||||
* which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field 'magic' of
|
||||
* wifi_init_config_t should always be WIFI_INIT_CONFIG_MAGIC!
|
||||
*
|
||||
* @param config pointer to WiFi init configuration structure; can point to a temporary variable.
|
||||
@ -247,7 +247,7 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config);
|
||||
*
|
||||
* @attention 1. This API should be called if you want to remove WiFi driver from the system
|
||||
*
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
*/
|
||||
@ -332,11 +332,11 @@ esp_err_t esp_wifi_restore(void);
|
||||
* @attention 3. The scanning triggered by esp_wifi_start_scan() will not be effective until connection between ESP32 and the AP is established.
|
||||
* If ESP32 is scanning and connecting at the same time, ESP32 will abort scanning and return a warning message and error
|
||||
* number ESP_ERR_WIFI_STATE.
|
||||
* If you want to do reconnection after ESP32 received disconnect event, remember to add the maximum retry time, otherwise the called
|
||||
* If you want to do reconnection after ESP32 received disconnect event, remember to add the maximum retry time, otherwise the called
|
||||
* scan will not work. This is especially true when the AP doesn't exist, and you still try reconnection after ESP32 received disconnect
|
||||
* event with the reason code WIFI_REASON_NO_AP_FOUND.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
* - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start
|
||||
@ -431,7 +431,7 @@ esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number);
|
||||
/**
|
||||
* @brief Get AP list found in last scan
|
||||
*
|
||||
* @param[inout] number As input param, it stores max AP number ap_records can hold.
|
||||
* @param[inout] number As input param, it stores max AP number ap_records can hold.
|
||||
* As output param, it receives the actual AP number this API returns.
|
||||
* @param ap_records wifi_ap_record_t array to hold the found APs
|
||||
*
|
||||
@ -456,7 +456,7 @@ esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_re
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_CONN: The station interface don't initialized
|
||||
* - ESP_ERR_WIFI_NOT_CONNECT: The station is in disconnect status
|
||||
* - ESP_ERR_WIFI_NOT_CONNECT: The station is in disconnect status
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info);
|
||||
|
||||
@ -554,7 +554,7 @@ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
|
||||
* @attention 1. This API should be called after esp_wifi_start()
|
||||
* @attention 2. When ESP32 is in STA mode, this API should not be called when STA is scanning or connecting to an external AP
|
||||
* @attention 3. When ESP32 is in softAP mode, this API should not be called when softAP has connected to external STAs
|
||||
* @attention 4. When ESP32 is in STA+softAP mode, this API should not be called when in the scenarios described above
|
||||
* @attention 4. When ESP32 is in STA+softAP mode, this API should not be called when in the scenarios described above
|
||||
*
|
||||
* @param primary for HT20, primary is the channel number, for HT40, primary is the primary channel
|
||||
* @param second for HT20, second is ignored, for HT40, second is the second channel
|
||||
@ -596,7 +596,7 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
|
||||
* @attention 4. When the country info is changed because of configuration or because the station connects to a different
|
||||
* external AP, the country IE in probe response/beacon of the soft-AP is changed also.
|
||||
* @attention 5. The country configuration is stored into flash.
|
||||
* @attention 6. This API doesn't validate the per-country rules, it's up to the user to fill in all fields according to
|
||||
* @attention 6. This API doesn't validate the per-country rules, it's up to the user to fill in all fields according to
|
||||
* local regulations.
|
||||
* @attention 7. When this API is called, the PHY init data will switch to the PHY init data type corresponding to the
|
||||
* country info.
|
||||
@ -660,7 +660,7 @@ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, const uint8_t mac[6]);
|
||||
esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
|
||||
|
||||
/**
|
||||
* @brief The RX callback function in the promiscuous mode.
|
||||
* @brief The RX callback function in the promiscuous mode.
|
||||
* Each time a packet is received, the callback function will be called.
|
||||
*
|
||||
* @param buf Data received. Type of data in buffer (wifi_promiscuous_pkt_t or wifi_pkt_rx_ctrl_t) indicated by 'type' parameter.
|
||||
@ -972,14 +972,14 @@ esp_err_t esp_wifi_get_event_mask(uint32_t *mask);
|
||||
*
|
||||
* @attention Currently only support for sending beacon/probe request/probe response/action and non-QoS
|
||||
* data frame
|
||||
*
|
||||
*
|
||||
* @param ifx interface if the Wi-Fi mode is Station, the ifx should be WIFI_IF_STA. If the Wi-Fi
|
||||
* mode is SoftAP, the ifx should be WIFI_IF_AP. If the Wi-Fi mode is Station+SoftAP, the
|
||||
* mode is SoftAP, the ifx should be WIFI_IF_AP. If the Wi-Fi mode is Station+SoftAP, the
|
||||
* ifx should be WIFI_IF_STA or WIFI_IF_AP. If the ifx is wrong, the API returns ESP_ERR_WIFI_IF.
|
||||
* @param buffer raw ieee80211 buffer
|
||||
* @param len the length of raw buffer, the len must be <= 1500 Bytes and >= 24 Bytes
|
||||
* @param en_sys_seq indicate whether use the internal sequence number. If en_sys_seq is false, the
|
||||
* sequence in raw buffer is unchanged, otherwise it will be overwritten by WiFi driver with
|
||||
* @param en_sys_seq indicate whether use the internal sequence number. If en_sys_seq is false, the
|
||||
* sequence in raw buffer is unchanged, otherwise it will be overwritten by WiFi driver with
|
||||
* the system sequence number.
|
||||
* Generally, if esp_wifi_80211_tx is called before the Wi-Fi connection has been set up, both
|
||||
* en_sys_seq==true and en_sys_seq==false are fine. However, if the API is called after the Wi-Fi
|
||||
@ -995,12 +995,12 @@ esp_err_t esp_wifi_get_event_mask(uint32_t *mask);
|
||||
esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, bool en_sys_seq);
|
||||
|
||||
/**
|
||||
* @brief The RX callback function of Channel State Information(CSI) data.
|
||||
* @brief The RX callback function of Channel State Information(CSI) data.
|
||||
*
|
||||
* Each time a CSI data is received, the callback function will be called.
|
||||
*
|
||||
* @param ctx context argument, passed to esp_wifi_set_csi_rx_cb() when registering callback function.
|
||||
* @param data CSI data received. The memory that it points to will be deallocated after callback function returns.
|
||||
* @param ctx context argument, passed to esp_wifi_set_csi_rx_cb() when registering callback function.
|
||||
* @param data CSI data received. The memory that it points to will be deallocated after callback function returns.
|
||||
*
|
||||
*/
|
||||
typedef void (* wifi_csi_cb_t)(void *ctx, wifi_csi_info_t *data);
|
||||
@ -1025,7 +1025,7 @@ esp_err_t esp_wifi_set_csi_rx_cb(wifi_csi_cb_t cb, void *ctx);
|
||||
* @brief Set CSI data configuration
|
||||
*
|
||||
* @param config configuration
|
||||
*
|
||||
*
|
||||
* return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
@ -1153,6 +1153,20 @@ esp_err_t esp_wifi_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);
|
||||
*/
|
||||
esp_err_t esp_wifi_statis_dump(uint32_t modules);
|
||||
|
||||
/**
|
||||
* @brief Set RSSI threshold below which APP will get an event
|
||||
*
|
||||
* @attention This API needs to be called every time after WIFI_EVENT_STA_BSS_RSSI_LOW event is received.
|
||||
*
|
||||
* @param rssi threshold value in dbm between -100 to 0
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
|
||||
* - ESP_ERR_WIFI_ARG: invalid argument
|
||||
*/
|
||||
esp_err_t esp_wifi_set_rssi_threshold(int32_t rssi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -95,6 +95,7 @@ typedef enum {
|
||||
WIFI_REASON_HANDSHAKE_TIMEOUT = 204,
|
||||
WIFI_REASON_CONNECTION_FAIL = 205,
|
||||
WIFI_REASON_AP_TSF_RESET = 206,
|
||||
WIFI_REASON_ROAMING = 207,
|
||||
} wifi_err_reason_t;
|
||||
|
||||
typedef enum {
|
||||
@ -235,6 +236,9 @@ typedef struct {
|
||||
wifi_sort_method_t sort_method; /**< sort the connect AP in the list by rssi or security mode */
|
||||
wifi_scan_threshold_t threshold; /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
|
||||
wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */
|
||||
uint32_t rm_enabled:1; /**< Whether Radio Measurements are enabled for the connection */
|
||||
uint32_t btm_enabled:1; /**< Whether BSS Transition Management is enabled for the connection */
|
||||
uint32_t reserved:30; /**< Reserved for future feature set */
|
||||
} wifi_sta_config_t;
|
||||
|
||||
/** @brief Configuration data for ESP32 AP or STA.
|
||||
@ -541,6 +545,9 @@ typedef enum {
|
||||
|
||||
WIFI_EVENT_FTM_REPORT, /**< Receive report of FTM procedure */
|
||||
|
||||
/* Add next events after this only */
|
||||
WIFI_EVENT_STA_BSS_RSSI_LOW, /**< AP's RSSI crossed configured threshold */
|
||||
|
||||
WIFI_EVENT_MAX, /**< Invalid WiFi event ID */
|
||||
} wifi_event_t;
|
||||
|
||||
@ -622,6 +629,11 @@ typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station which send probe request */
|
||||
} wifi_event_ap_probe_req_rx_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_BSS_RSSI_LOW event */
|
||||
typedef struct {
|
||||
int32_t rssi; /**< RSSI value of bss */
|
||||
} wifi_event_bss_rssi_low_t;
|
||||
|
||||
#define WIFI_STATIS_BUFFER (1<<0)
|
||||
#define WIFI_STATIS_RXTX (1<<1)
|
||||
#define WIFI_STATIS_HW (1<<2)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 57db56bfeae0423a446f4d72f166fe044ee8c3ab
|
||||
Subproject commit 34f1262375795c34dca8520ffd042f0e104843b7
|
@ -6,6 +6,7 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/common/sae.c"
|
||||
"src/common/wpa_common.c"
|
||||
"src/common/dpp.c"
|
||||
"src/utils/bitfield.c"
|
||||
"src/crypto/aes-ctr.c"
|
||||
"src/crypto/aes-siv.c"
|
||||
"src/crypto/sha256-kdf.c"
|
||||
@ -106,7 +107,21 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}" "${tls_src}"
|
||||
if(CONFIG_WPA_11KV_SUPPORT)
|
||||
set(roaming_src
|
||||
"src/common/rrm.c"
|
||||
"src/common/wnm_sta.c"
|
||||
"src/common/bss.c"
|
||||
"src/common/scan.c"
|
||||
"src/common/ieee802_11_common.c"
|
||||
"src/esp_supplicant/esp_common.c"
|
||||
"src/esp_supplicant/esp_scan.c"
|
||||
)
|
||||
else()
|
||||
set(roaming_src "")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}" "${tls_src}" "${roaming_src}"
|
||||
INCLUDE_DIRS include port/include include/esp_supplicant
|
||||
PRIV_INCLUDE_DIRS src
|
||||
PRIV_REQUIRES mbedtls esp_timer)
|
||||
@ -132,6 +147,7 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
CONFIG_WPA3_SAE
|
||||
CONFIG_SHA256
|
||||
CONFIG_DPP
|
||||
CONFIG_WNM
|
||||
)
|
||||
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
|
||||
|
@ -42,4 +42,28 @@ menu "Supplicant"
|
||||
button bit without setting virtual/phycial display/button bit which
|
||||
will cause M2 validation fail, bypassing WPS-Config method validation.
|
||||
|
||||
menuconfig WPA_11KV_SUPPORT
|
||||
bool "Enable 802.11k, 802.11v APIs handling in supplicant"
|
||||
default n
|
||||
help
|
||||
Select this option to enable 802.11k 802.11v APIs(RRM and BTM support).
|
||||
Only APIs which are helpful for network assisted roaming
|
||||
are supported for now.
|
||||
Enable this option with BTM and RRM enabled in sta config
|
||||
to make device ready for network assisted roaming.
|
||||
BTM: BSS transition management enables an AP to request a station to transition
|
||||
to a specific AP, or to indicate to a station a set of preferred APs.
|
||||
RRM: Radio measurements enable STAs to understand the radio environment,
|
||||
it enables STAs to observe and gather data on radio link performance
|
||||
and on the radio environment. Current implementation adds beacon report,
|
||||
link measurement, neighbor report.
|
||||
|
||||
if WPA_11KV_SUPPORT
|
||||
config WPA_SCAN_CACHE
|
||||
bool "Keep scan results in cache"
|
||||
default n
|
||||
help
|
||||
Keep scan results in cache, if not enabled, those
|
||||
will be flushed immediately.
|
||||
endif
|
||||
endmenu
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS := src
|
||||
COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps
|
||||
COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
|
||||
COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant src/utils
|
||||
|
||||
ifeq ($(CONFIG_WPA_MBEDTLS_CRYPTO), y)
|
||||
COMPONENT_OBJEXCLUDE := src/tls/asn1.o \
|
||||
COMPONENT_OBJEXCLUDE += src/tls/asn1.o \
|
||||
src/tls/bignum.o \
|
||||
src/tls/pkcs1.o \
|
||||
src/tls/pkcs5.o \
|
||||
@ -25,5 +25,14 @@ ifeq ($(CONFIG_WPA_MBEDTLS_CRYPTO), y)
|
||||
else
|
||||
COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
|
||||
endif
|
||||
ifneq ($(CONFIG_WPA_11KV_SUPPORT), y)
|
||||
COMPONENT_OBJEXCLUDE += src/common/rrm.o \
|
||||
src/common/wnm_sta.o \
|
||||
src/common/bss.o \
|
||||
src/common/scan.o \
|
||||
src/common/ieee802_11_common.o \
|
||||
src/esp_supplicant/esp_common.o \
|
||||
src/esp_supplicant/esp_scan.o
|
||||
endif
|
||||
|
||||
CFLAGS += -DCONFIG_DPP -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
|
||||
CFLAGS += -DCONFIG_DPP -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -DCONFIG_WNM -D__ets__ -Wno-strict-aliasing
|
||||
|
52
components/wpa_supplicant/include/esp_supplicant/esp_rrm.h
Normal file
52
components/wpa_supplicant/include/esp_supplicant/esp_rrm.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_RRM_H
|
||||
#define _ESP_RRM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Callback function type to get neighbor report
|
||||
*
|
||||
* @param ctx: neighbor report context
|
||||
* @param report: neighbor report
|
||||
* @param report_len: neighbor report length
|
||||
*
|
||||
* @return
|
||||
* - void
|
||||
*/
|
||||
typedef void (*neighbor_rep_request_cb)(void *ctx, const uint8_t *report, size_t report_len);
|
||||
|
||||
/**
|
||||
* @brief Send Radio measurement neighbor report request to connected AP
|
||||
*
|
||||
* @param cb: callback function for neighbor report
|
||||
* @param cb_ctx: callback context
|
||||
*
|
||||
* @return
|
||||
* - 0: success else failure
|
||||
*/
|
||||
int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
|
||||
void *cb_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
56
components/wpa_supplicant/include/esp_supplicant/esp_wnm.h
Normal file
56
components/wpa_supplicant/include/esp_supplicant/esp_wnm.h
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _ESP_WNM_H
|
||||
#define _ESP_WNM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum btm_query_reason: Reason code for sending btm query
|
||||
*/
|
||||
enum btm_query_reason {
|
||||
REASON_UNSPECIFIED = 0,
|
||||
REASON_FRAME_LOSS = 1,
|
||||
REASON_DELAY = 2,
|
||||
REASON_QOS_CAPACITY = 3,
|
||||
REASON_FIRST_ASSOC = 4,
|
||||
REASON_LOAD_BALALNCE = 5,
|
||||
REASON_BETTER_AP = 6,
|
||||
REASON_CURRENT_DEAUTH = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Send bss transition query to connected AP
|
||||
*
|
||||
* @param query_reason: reason for sending query
|
||||
* @param btm_candidates: btm candidates list if available
|
||||
* @param cand_list: whether candidate list to be included from scan results available in supplicant's cache.
|
||||
*
|
||||
* @return
|
||||
* - 0: success else failure
|
||||
*/
|
||||
int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
|
||||
const char *btm_candidates,
|
||||
int cand_list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "wpabuf.h"
|
||||
#include "esp_log.h"
|
||||
#include "supplicant_opt.h"
|
||||
|
||||
#ifdef ESPRESSIF_USE
|
||||
|
||||
@ -60,6 +61,7 @@ void wpa_debug_print_timestamp(void);
|
||||
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||
*/
|
||||
#define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args)
|
||||
#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 u8 *buf, size_t len)
|
||||
@ -153,6 +155,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
|
||||
#define wpa_hexdump_buf_key(...) do {} while(0)
|
||||
#define wpa_hexdump_ascii(...) do {} while(0)
|
||||
#define wpa_hexdump_ascii_key(...) do {} while(0)
|
||||
#define wpa_dbg(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
#define wpa_auth_logger
|
||||
|
@ -34,6 +34,8 @@ struct os_time {
|
||||
suseconds_t usec;
|
||||
};
|
||||
|
||||
#define os_reltime os_time
|
||||
|
||||
struct os_tm {
|
||||
int sec; /* 0..59 or 60 for leap seconds */
|
||||
int min; /* 0..59 */
|
||||
@ -49,7 +51,7 @@ struct os_tm {
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int os_get_time(struct os_time *t);
|
||||
|
||||
#define os_get_reltime os_get_time
|
||||
|
||||
/* Helper macros for handling struct os_time */
|
||||
|
||||
@ -57,6 +59,7 @@ int os_get_time(struct os_time *t);
|
||||
((a)->sec < (b)->sec || \
|
||||
((a)->sec == (b)->sec && (a)->usec < (b)->usec))
|
||||
|
||||
#define os_reltime_before os_time_before
|
||||
#define os_time_sub(a, b, res) do { \
|
||||
(res)->sec = (a)->sec - (b)->sec; \
|
||||
(res)->usec = (a)->usec - (b)->usec; \
|
||||
@ -65,6 +68,7 @@ int os_get_time(struct os_time *t);
|
||||
(res)->usec += 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#define os_reltime_sub os_time_sub
|
||||
|
||||
/**
|
||||
* os_mktime - Convert broken-down time into seconds since 1970-01-01
|
||||
@ -207,6 +211,10 @@ char * os_readfile(const char *name, size_t *len);
|
||||
#ifndef os_zalloc
|
||||
#define os_zalloc(s) calloc(1, (s))
|
||||
#endif
|
||||
#ifndef os_calloc
|
||||
#define os_calloc(p, s) calloc((p), (s))
|
||||
#endif
|
||||
|
||||
#ifndef os_free
|
||||
#define os_free(p) free((p))
|
||||
#endif
|
||||
@ -293,4 +301,11 @@ static inline int os_snprintf_error(size_t size, int res)
|
||||
{
|
||||
return res < 0 || (unsigned int) res >= size;
|
||||
}
|
||||
|
||||
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
if (size && nmemb > (~(size_t) 0) / size)
|
||||
return NULL;
|
||||
return os_realloc(ptr, nmemb * size);
|
||||
}
|
||||
#endif /* OS_H */
|
||||
|
@ -28,4 +28,12 @@
|
||||
#define DEBUG_PRINT
|
||||
#endif
|
||||
|
||||
#if CONFIG_WPA_11KV_SUPPORT
|
||||
#define ROAMING_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#if CONFIG_WPA_SCAN_CACHE
|
||||
#define SCAN_CACHE_SUPPORTED
|
||||
#endif
|
||||
|
||||
#endif /* _SUPPLICANT_OPT_H */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "os.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "esp_system.h"
|
||||
#include "utils/common.h"
|
||||
@ -48,3 +49,13 @@ int os_get_random(unsigned char *buf, size_t len)
|
||||
esp_fill_random(buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_sleep(os_time_t sec, os_time_t usec)
|
||||
{
|
||||
if (sec) {
|
||||
sleep(sec);
|
||||
}
|
||||
if (usec) {
|
||||
usleep(usec);
|
||||
}
|
||||
}
|
||||
|
@ -2177,7 +2177,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
/* update GTK when exiting WNM-Sleep Mode */
|
||||
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
|
||||
{
|
||||
@ -2254,7 +2254,7 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
|
||||
return pos - start;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
|
||||
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
|
||||
|
476
components/wpa_supplicant/src/common/bss.c
Normal file
476
components/wpa_supplicant/src/common/bss.c
Normal file
@ -0,0 +1,476 @@
|
||||
/*
|
||||
* BSS table
|
||||
* Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "eap_peer/eap.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "config.h"
|
||||
#include "scan.h"
|
||||
#include "bss.h"
|
||||
#ifdef ESP_SUPPLICANT
|
||||
#include "esp_supplicant/esp_wifi_driver.h"
|
||||
#endif
|
||||
|
||||
#define MAX_BSS_COUNT 20
|
||||
|
||||
void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
const char *reason)
|
||||
{
|
||||
if (wpa_s->last_scan_res) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
|
||||
if (wpa_s->last_scan_res[i] == bss) {
|
||||
os_memmove(&wpa_s->last_scan_res[i],
|
||||
&wpa_s->last_scan_res[i + 1],
|
||||
(wpa_s->last_scan_res_used - i - 1)
|
||||
* sizeof(struct wpa_bss *));
|
||||
wpa_s->last_scan_res_used--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dl_list_del(&bss->list);
|
||||
dl_list_del(&bss->list_id);
|
||||
wpa_s->num_bss--;
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
|
||||
" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
|
||||
wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
|
||||
os_free(bss);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @bssid: BSSID
|
||||
* @ssid: SSID
|
||||
* @ssid_len: Length of @ssid
|
||||
* Returns: Pointer to the BSS entry or %NULL if not found
|
||||
*/
|
||||
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
|
||||
bss->ssid_len == ssid_len &&
|
||||
os_memcmp(bss->ssid, ssid, ssid_len) == 0)
|
||||
return bss;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void calculate_update_time(const struct os_reltime *fetch_time,
|
||||
unsigned int age_ms,
|
||||
struct os_reltime *update_time)
|
||||
{
|
||||
os_time_t usec;
|
||||
|
||||
update_time->sec = fetch_time->sec;
|
||||
update_time->usec = fetch_time->usec;
|
||||
update_time->sec -= age_ms / 1000;
|
||||
usec = (age_ms % 1000) * 1000;
|
||||
if (update_time->usec < usec) {
|
||||
update_time->sec--;
|
||||
update_time->usec += 1000000;
|
||||
}
|
||||
update_time->usec -= usec;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
|
||||
struct os_reltime *fetch_time)
|
||||
{
|
||||
dst->flags = src->flags;
|
||||
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
|
||||
dst->channel = src->chan;
|
||||
dst->beacon_int = src->beacon_int;
|
||||
dst->caps = src->caps;
|
||||
dst->noise = src->noise;
|
||||
dst->level = src->level;
|
||||
dst->tsf = src->tsf;
|
||||
dst->parent_tsf = src->parent_tsf;
|
||||
|
||||
calculate_update_time(fetch_time, src->age, &dst->last_update);
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
||||
{
|
||||
struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
|
||||
|
||||
if (ssid->ssid == NULL || ssid->len == 0)
|
||||
return 0;
|
||||
if (ssid->len == bss->ssid_len &&
|
||||
os_memcmp(ssid->ssid, bss->ssid, ssid->len) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
||||
{
|
||||
if (bss == wpa_s->current_bss)
|
||||
return 1;
|
||||
|
||||
if (wpa_s->current_bss &&
|
||||
(bss->ssid_len != wpa_s->current_bss->ssid_len ||
|
||||
os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
|
||||
bss->ssid_len) != 0))
|
||||
return 0; /* SSID has changed */
|
||||
|
||||
return !is_zero_ether_addr(bss->bssid) && wpa_s->current_bss->bssid &&
|
||||
(os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0);
|
||||
}
|
||||
|
||||
static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (!wpa_bss_known(wpa_s, bss)) {
|
||||
wpa_bss_remove(wpa_s, bss, __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
|
||||
/*
|
||||
* Remove the oldest entry that does not match with any configured
|
||||
* network.
|
||||
*/
|
||||
if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Remove the oldest entry that isn't currently in use.
|
||||
*/
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (!wpa_bss_in_use(wpa_s, bss)) {
|
||||
wpa_bss_remove(wpa_s, bss, __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct wpa_scan_res *res,
|
||||
struct os_reltime *fetch_time)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
|
||||
if ((wpa_s->num_bss + 1 > MAX_BSS_COUNT) &&
|
||||
(wpa_bss_remove_oldest(wpa_s) < 0)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to clean older entries, rejecting scan result");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
|
||||
if (bss == NULL)
|
||||
return NULL;
|
||||
bss->id = wpa_s->bss_next_id++;
|
||||
bss->last_update_idx = wpa_s->bss_update_idx;
|
||||
wpa_bss_copy_res(bss, res, fetch_time);
|
||||
os_memcpy(bss->ssid, ssid, ssid_len);
|
||||
bss->ssid_len = ssid_len;
|
||||
bss->ie_len = res->ie_len;
|
||||
bss->beacon_ie_len = res->beacon_ie_len;
|
||||
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
|
||||
|
||||
dl_list_add_tail(&wpa_s->bss, &bss->list);
|
||||
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
|
||||
wpa_s->num_bss++;
|
||||
wpa_dbg(wpa_s, MSG_INFO, "BSS: Add new id %u BSSID " MACSTR
|
||||
" SSID '%s' chan %d",
|
||||
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
|
||||
bss->channel);
|
||||
return bss;
|
||||
}
|
||||
|
||||
static struct wpa_bss *
|
||||
wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
struct wpa_scan_res *res, struct os_reltime *fetch_time)
|
||||
{
|
||||
if (bss->last_update_idx == wpa_s->bss_update_idx) {
|
||||
struct os_reltime update_time;
|
||||
|
||||
/*
|
||||
* Some drivers (e.g., cfg80211) include multiple BSS entries
|
||||
* for the same BSS if that BSS's channel changes. The BSS list
|
||||
* implementation in wpa_supplicant does not do that and we need
|
||||
* to filter out the obsolete results here to make sure only the
|
||||
* most current BSS information remains in the table.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "BSS: " MACSTR
|
||||
" has multiple entries in the scan results - select the most current one",
|
||||
MAC2STR(bss->bssid));
|
||||
calculate_update_time(fetch_time, res->age, &update_time);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Accept this BSS entry since it looks more current than the previous update");
|
||||
}
|
||||
|
||||
bss->last_update_idx = wpa_s->bss_update_idx;
|
||||
wpa_bss_copy_res(bss, res, fetch_time);
|
||||
/* Move the entry to the end of the list */
|
||||
dl_list_del(&bss->list);
|
||||
if (bss->ie_len + bss->beacon_ie_len >=
|
||||
res->ie_len + res->beacon_ie_len) {
|
||||
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
|
||||
bss->ie_len = res->ie_len;
|
||||
bss->beacon_ie_len = res->beacon_ie_len;
|
||||
} else {
|
||||
struct wpa_bss *nbss;
|
||||
struct dl_list *prev = bss->list_id.prev;
|
||||
dl_list_del(&bss->list_id);
|
||||
nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
|
||||
res->beacon_ie_len);
|
||||
if (nbss) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
|
||||
if (wpa_s->last_scan_res[i] == bss) {
|
||||
wpa_s->last_scan_res[i] = nbss;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wpa_s->current_bss == bss)
|
||||
wpa_s->current_bss = nbss;
|
||||
bss = nbss;
|
||||
os_memcpy(bss + 1, res + 1,
|
||||
res->ie_len + res->beacon_ie_len);
|
||||
bss->ie_len = res->ie_len;
|
||||
bss->beacon_ie_len = res->beacon_ie_len;
|
||||
}
|
||||
dl_list_add(prev, &bss->list_id);
|
||||
}
|
||||
dl_list_add_tail(&wpa_s->bss, &bss->list);
|
||||
|
||||
return bss;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_update_start - Start a BSS table update from scan results
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
*
|
||||
* This function is called at the start of each BSS table update round for new
|
||||
* scan results. The actual scan result entries are indicated with calls to
|
||||
* wpa_bss_update_scan_res() and the update round is finished with a call to
|
||||
* wpa_bss_update_end().
|
||||
*/
|
||||
void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_s->bss_update_idx++;
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
|
||||
wpa_s->bss_update_idx);
|
||||
wpa_s->last_scan_res_used = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @res: Scan result
|
||||
* @fetch_time: Time when the result was fetched from the driver
|
||||
*
|
||||
* This function updates a BSS table entry (or adds one) based on a scan result.
|
||||
* This is called separately for each scan result between the calls to
|
||||
* wpa_bss_update_start() and wpa_bss_update_end().
|
||||
*/
|
||||
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_scan_res *res,
|
||||
struct os_reltime *fetch_time)
|
||||
{
|
||||
const u8 *ssid;
|
||||
struct wpa_bss *bss;
|
||||
|
||||
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
|
||||
if (ssid == NULL) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
|
||||
MACSTR, MAC2STR(res->bssid));
|
||||
return;
|
||||
}
|
||||
if (ssid[1] > SSID_MAX_LEN) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
|
||||
MACSTR, MAC2STR(res->bssid));
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: add option for ignoring BSSes we are not interested in
|
||||
* (to save memory) */
|
||||
|
||||
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
|
||||
if (bss == NULL)
|
||||
bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
|
||||
else {
|
||||
bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
|
||||
if (wpa_s->last_scan_res) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
|
||||
if (bss == wpa_s->last_scan_res[i]) {
|
||||
/* Already in the list */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bss == NULL)
|
||||
return;
|
||||
if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
|
||||
struct wpa_bss **n;
|
||||
unsigned int siz;
|
||||
if (wpa_s->last_scan_res_size == 0)
|
||||
siz = 32;
|
||||
else
|
||||
siz = wpa_s->last_scan_res_size * 2;
|
||||
n = os_realloc_array(wpa_s->last_scan_res, siz,
|
||||
sizeof(struct wpa_bss *));
|
||||
if (n == NULL)
|
||||
return;
|
||||
wpa_s->last_scan_res = n;
|
||||
wpa_s->last_scan_res_size = siz;
|
||||
}
|
||||
|
||||
if (wpa_s->last_scan_res)
|
||||
wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_update_end - End a BSS table update from scan results
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @info: Information about scan parameters
|
||||
* @new_scan: Whether this update round was based on a new scan
|
||||
*
|
||||
* This function is called at the end of each BSS table update round for new
|
||||
* scan results. The start of the update was indicated with a call to
|
||||
* wpa_bss_update_start().
|
||||
*/
|
||||
void wpa_bss_update_end(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
os_get_reltime(&wpa_s->last_scan);
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_bss_init - Initialize BSS table
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This prepares BSS table lists and timer for periodic updates. The BSS table
|
||||
* is deinitialized with wpa_bss_deinit() once not needed anymore.
|
||||
*/
|
||||
int wpa_bss_init(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
dl_list_init(&wpa_s->bss);
|
||||
dl_list_init(&wpa_s->bss_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_flush - Flush all unused BSS entries
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
*/
|
||||
void wpa_bss_flush(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss, *n;
|
||||
|
||||
if (wpa_s->bss.next == NULL)
|
||||
return; /* BSS table not yet initialized */
|
||||
|
||||
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (wpa_bss_in_use(wpa_s, bss))
|
||||
continue;
|
||||
wpa_bss_remove(wpa_s, bss, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_deinit - Deinitialize BSS table
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
*/
|
||||
void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_bss_flush(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @bssid: BSSID
|
||||
* Returns: Pointer to the BSS entry or %NULL if not found
|
||||
*/
|
||||
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
|
||||
const u8 *bssid)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
|
||||
return bss;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_bss_get_next_bss - Fetch a next BSS table entry from the list
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @bss: BSS
|
||||
* Returns: Pointer to the BSS entry or %NULL if not found
|
||||
*/
|
||||
struct wpa_bss * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *prev_bss)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
|
||||
if (!prev_bss)
|
||||
return dl_list_first(&wpa_s->bss, struct wpa_bss, list);
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (os_memcmp(bss->bssid, prev_bss->bssid, ETH_ALEN) == 0)
|
||||
return dl_list_entry(bss->list.next, struct wpa_bss, list);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_bss_get_ie - Fetch a specified information element from a BSS entry
|
||||
* @bss: BSS table entry
|
||||
* @ie: Information element identitifier (WLAN_EID_*)
|
||||
* Returns: Pointer to the information element (id field) or %NULL if not found
|
||||
*
|
||||
* This function returns the first matching information element in the BSS
|
||||
* entry.
|
||||
*/
|
||||
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
|
||||
{
|
||||
return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
|
||||
}
|
||||
|
||||
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
|
||||
{
|
||||
return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
|
||||
capab);
|
||||
}
|
86
components/wpa_supplicant/src/common/bss.h
Normal file
86
components/wpa_supplicant/src/common/bss.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* BSS table
|
||||
* Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef BSS_H
|
||||
#define BSS_H
|
||||
|
||||
struct wpa_scan_res;
|
||||
|
||||
/**
|
||||
* struct wpa_bss - BSS table
|
||||
*
|
||||
* This structure is used to store information about neighboring BSSes in
|
||||
* generic format. It is mainly updated based on scan results from the driver.
|
||||
*/
|
||||
struct wpa_bss {
|
||||
/** List entry for struct wpa_supplicant::bss */
|
||||
struct dl_list list;
|
||||
/** List entry for struct wpa_supplicant::bss_id */
|
||||
struct dl_list list_id;
|
||||
/** Unique identifier for this BSS entry */
|
||||
unsigned int id;
|
||||
/** Index of the last scan update */
|
||||
unsigned int last_update_idx;
|
||||
/** Information flags about the BSS/IBSS (WPA_BSS_*) */
|
||||
unsigned int flags;
|
||||
/** BSSID */
|
||||
u8 bssid[ETH_ALEN];
|
||||
/** SSID */
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
/** Length of SSID */
|
||||
size_t ssid_len;
|
||||
/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
|
||||
int channel;
|
||||
/** Beacon interval in TUs (host byte order) */
|
||||
u16 beacon_int;
|
||||
/** Capability information field in host byte order */
|
||||
u16 caps;
|
||||
/** Signal quality */
|
||||
int qual;
|
||||
/** Noise level */
|
||||
int noise;
|
||||
/** Signal level */
|
||||
int level;
|
||||
/** Timestamp of last Beacon/Probe Response frame */
|
||||
u64 tsf;
|
||||
/** Timestamp of parent aganist which it was taken */
|
||||
u64 parent_tsf;
|
||||
/** Time of the last update (i.e., Beacon or Probe Response RX) */
|
||||
struct os_reltime last_update;
|
||||
/** Length of the following IE field in octets (from Probe Response) */
|
||||
size_t ie_len;
|
||||
/** Length of the following Beacon IE field in octets */
|
||||
size_t beacon_ie_len;
|
||||
/* followed by ie_len octets of IEs */
|
||||
/* followed by beacon_ie_len octets of IEs */
|
||||
};
|
||||
|
||||
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
|
||||
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_scan_res *res,
|
||||
struct os_reltime *fetch_time);
|
||||
void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
const char *reason);
|
||||
void wpa_bss_update_end(struct wpa_supplicant *wpa_s);
|
||||
int wpa_bss_init(struct wpa_supplicant *wpa_s);
|
||||
void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
|
||||
void wpa_bss_flush(struct wpa_supplicant *wpa_s);
|
||||
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len);
|
||||
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
|
||||
const u8 *bssid);
|
||||
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
|
||||
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
|
||||
struct wpa_bss * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *prev_bss);
|
||||
|
||||
void calculate_update_time(const struct os_reltime *fetch_time,
|
||||
unsigned int age_ms,
|
||||
struct os_reltime *update_time);
|
||||
|
||||
#endif /* BSS_H */
|
198
components/wpa_supplicant/src/common/ieee802_11_common.c
Normal file
198
components/wpa_supplicant/src/common/ieee802_11_common.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "defs.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "ieee802_11_common.h"
|
||||
#include "common/wpa_supplicant_i.h"
|
||||
|
||||
/**
|
||||
* get_ie - Fetch a specified information element from IEs buffer
|
||||
* @ies: Information elements buffer
|
||||
* @len: Information elements buffer length
|
||||
* @eid: Information element identifier (WLAN_EID_*)
|
||||
* Returns: Pointer to the information element (id field) or %NULL if not found
|
||||
*
|
||||
* This function returns the first matching information element in the IEs
|
||||
* buffer or %NULL in case the element is not found.
|
||||
*/
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
{
|
||||
const struct element *elem;
|
||||
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
for_each_element_id(elem, eid, ies, len)
|
||||
return &elem->id;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len)
|
||||
{
|
||||
u8 *nei_pos = nei_rep;
|
||||
const char *end;
|
||||
|
||||
/*
|
||||
* BSS Transition Candidate List Entries - Neighbor Report elements
|
||||
* neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
|
||||
* <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
|
||||
*/
|
||||
while (pos) {
|
||||
u8 *nei_start;
|
||||
long int val;
|
||||
char *endptr, *tmp;
|
||||
|
||||
pos = os_strstr(pos, " neighbor=");
|
||||
if (!pos)
|
||||
break;
|
||||
if (nei_pos + 15 > nei_rep + nei_rep_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Not enough room for additional neighbor");
|
||||
return -1;
|
||||
}
|
||||
pos += 10;
|
||||
|
||||
nei_start = nei_pos;
|
||||
*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
|
||||
nei_pos++; /* length to be filled in */
|
||||
|
||||
if (hwaddr_aton2(pos, nei_pos) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid BSSID");
|
||||
return -1;
|
||||
}
|
||||
nei_pos += ETH_ALEN;
|
||||
pos += 17;
|
||||
if (*pos != ',') {
|
||||
wpa_printf(MSG_DEBUG, "Missing BSSID Information");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
val = strtol(pos, &endptr, 0);
|
||||
WPA_PUT_LE32(nei_pos, val);
|
||||
nei_pos += 4;
|
||||
if (*endptr != ',') {
|
||||
wpa_printf(MSG_DEBUG, "Missing Operating Class");
|
||||
return -1;
|
||||
}
|
||||
pos = endptr + 1;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* Operating Class */
|
||||
pos = os_strchr(pos, ',');
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Missing Channel Number");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* Channel Number */
|
||||
pos = os_strchr(pos, ',');
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Missing PHY Type");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
*nei_pos++ = atoi(pos); /* PHY Type */
|
||||
end = os_strchr(pos, ' ');
|
||||
tmp = os_strchr(pos, ',');
|
||||
if (tmp && (!end || tmp < end)) {
|
||||
/* Optional Subelements (hexdump) */
|
||||
size_t len;
|
||||
|
||||
pos = tmp + 1;
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Not enough room for neighbor subelements");
|
||||
return -1;
|
||||
}
|
||||
if (len & 0x01 ||
|
||||
hexstr2bin(pos, nei_pos, len / 2) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Invalid neighbor subelement info");
|
||||
return -1;
|
||||
}
|
||||
nei_pos += len / 2;
|
||||
pos = end;
|
||||
}
|
||||
|
||||
nei_start[1] = nei_pos - nei_start - 2;
|
||||
}
|
||||
|
||||
return nei_pos - nei_rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee802_11_parse_elems - Parse information elements in management frames
|
||||
* @start: Pointer to the start of IEs
|
||||
* @len: Length of IE buffer in octets
|
||||
* @elems: Data structure for parsed elements
|
||||
* @show_errors: Whether to show parsing errors in debug log
|
||||
* Returns: Parsing result
|
||||
*/
|
||||
int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len)
|
||||
{
|
||||
const struct element *elem;
|
||||
|
||||
if (!start)
|
||||
return 0;
|
||||
|
||||
for_each_element(elem, start, len) {
|
||||
u8 id = elem->id;
|
||||
const u8 *pos = elem->data;
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_RRM_ENABLED_CAPABILITIES:
|
||||
os_memcpy(wpa_s->rrm_ie, pos, 5);
|
||||
wpa_s->rrm.rrm_used = true;
|
||||
break;
|
||||
case WLAN_EID_EXT_CAPAB:
|
||||
/* extended caps can go beyond 8 octacts but we aren't using them now */
|
||||
os_memcpy(wpa_s->extend_caps, pos, 5);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
|
||||
{
|
||||
if (!ie || ie[1] <= capab / 8)
|
||||
return 0;
|
||||
return !!(ie[2 + capab / 8] & BIT(capab % 8));
|
||||
}
|
||||
|
||||
u8 get_operating_class(u8 chan, int sec_channel)
|
||||
{
|
||||
u8 op_class;
|
||||
|
||||
if (chan < 1 || chan > 14)
|
||||
return 0;
|
||||
if (sec_channel == 1)
|
||||
op_class = 83;
|
||||
else if (sec_channel == -1)
|
||||
op_class = 84;
|
||||
else
|
||||
op_class = 81;
|
||||
|
||||
return op_class;
|
||||
}
|
42
components/wpa_supplicant/src/common/ieee802_11_common.h
Normal file
42
components/wpa_supplicant/src/common/ieee802_11_common.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_COMMON_H
|
||||
#define IEEE802_11_COMMON_H
|
||||
|
||||
#include "defs.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
struct element {
|
||||
u8 id;
|
||||
u8 datalen;
|
||||
u8 data[];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* element iteration helpers */
|
||||
#define for_each_element(_elem, _data, _datalen) \
|
||||
for (_elem = (const struct element *) (_data); \
|
||||
(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
|
||||
(int) sizeof(*_elem) && \
|
||||
(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
|
||||
(int) sizeof(*_elem) + _elem->datalen; \
|
||||
_elem = (const struct element *) (_elem->data + _elem->datalen))
|
||||
|
||||
#define for_each_element_id(element, _id, data, datalen) \
|
||||
for_each_element(element, data, datalen) \
|
||||
if (element->id == (_id))
|
||||
|
||||
struct wpa_supplicant;
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len);
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
||||
int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len);
|
||||
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
|
||||
u8 get_operating_class(u8 chan, int sec_channel);
|
||||
#endif /* IEEE802_11_COMMON_H */
|
@ -1,21 +1,17 @@
|
||||
/*
|
||||
* IEEE 802.11 Frame type definitions
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_DEFS_H
|
||||
#define IEEE802_11_DEFS_H
|
||||
|
||||
#include <utils/common.h>
|
||||
|
||||
/* IEEE 802.11 defines */
|
||||
|
||||
#define WLAN_FC_PVER 0x0003
|
||||
@ -89,10 +85,15 @@
|
||||
#define WLAN_CAPABILITY_PBCC BIT(6)
|
||||
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
|
||||
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
|
||||
#define WLAN_CAPABILITY_QOS BIT(9)
|
||||
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
|
||||
#define WLAN_CAPABILITY_APSD BIT(11)
|
||||
#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12)
|
||||
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
|
||||
#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
|
||||
#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
|
||||
|
||||
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
|
||||
/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */
|
||||
#define WLAN_STATUS_SUCCESS 0
|
||||
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
|
||||
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
|
||||
@ -104,26 +105,23 @@
|
||||
#define WLAN_STATUS_AUTH_TIMEOUT 16
|
||||
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
|
||||
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
|
||||
/* IEEE 802.11b */
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
|
||||
/* IEEE 802.11h */
|
||||
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
|
||||
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
|
||||
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
|
||||
/* IEEE 802.11g */
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
|
||||
#define WLAN_STATUS_R0KH_UNREACHABLE 28
|
||||
/* IEEE 802.11w */
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
|
||||
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
|
||||
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
|
||||
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
|
||||
#define WLAN_STATUS_DENIED_INSUFFICIENT_BANDWIDTH 33
|
||||
#define WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS 34
|
||||
#define WLAN_STATUS_DENIED_QOS_NOT_SUPPORTED 35
|
||||
#define WLAN_STATUS_REQUEST_DECLINED 37
|
||||
#define WLAN_STATUS_INVALID_PARAMETERS 38
|
||||
/* IEEE 802.11i */
|
||||
#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39
|
||||
#define WLAN_STATUS_INVALID_IE 40
|
||||
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
|
||||
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
|
||||
@ -136,7 +134,6 @@
|
||||
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
|
||||
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
|
||||
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
|
||||
/* IEEE 802.11r */
|
||||
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
|
||||
#define WLAN_STATUS_INVALID_PMKID 53
|
||||
#define WLAN_STATUS_INVALID_MDIE 54
|
||||
@ -161,7 +158,7 @@
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
|
||||
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
|
||||
|
||||
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
|
||||
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
|
||||
#define WLAN_REASON_UNSPECIFIED 1
|
||||
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
|
||||
#define WLAN_REASON_DEAUTH_LEAVING 3
|
||||
@ -171,10 +168,9 @@
|
||||
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
|
||||
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
|
||||
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
|
||||
/* IEEE 802.11h */
|
||||
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
|
||||
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
|
||||
/* IEEE 802.11i */
|
||||
#define WLAN_REASON_BSS_TRANSITION_DISASSOC 12
|
||||
#define WLAN_REASON_INVALID_IE 13
|
||||
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
|
||||
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
|
||||
@ -188,18 +184,15 @@
|
||||
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
|
||||
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
|
||||
|
||||
|
||||
/* Information Element IDs */
|
||||
/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */
|
||||
#define WLAN_EID_SSID 0
|
||||
#define WLAN_EID_SUPP_RATES 1
|
||||
#define WLAN_EID_FH_PARAMS 2
|
||||
#define WLAN_EID_DS_PARAMS 3
|
||||
#define WLAN_EID_CF_PARAMS 4
|
||||
#define WLAN_EID_TIM 5
|
||||
#define WLAN_EID_IBSS_PARAMS 6
|
||||
#define WLAN_EID_COUNTRY 7
|
||||
#define WLAN_EID_CHALLENGE 16
|
||||
/* EIDs defined by IEEE 802.11h - START */
|
||||
#define WLAN_EID_PWR_CONSTRAINT 32
|
||||
#define WLAN_EID_PWR_CAPABILITY 33
|
||||
#define WLAN_EID_TPC_REQUEST 34
|
||||
@ -208,23 +201,25 @@
|
||||
#define WLAN_EID_CHANNEL_SWITCH 37
|
||||
#define WLAN_EID_MEASURE_REQUEST 38
|
||||
#define WLAN_EID_MEASURE_REPORT 39
|
||||
#define WLAN_EID_QUITE 40
|
||||
#define WLAN_EID_QUIET 40
|
||||
#define WLAN_EID_IBSS_DFS 41
|
||||
/* EIDs defined by IEEE 802.11h - END */
|
||||
#define WLAN_EID_ERP_INFO 42
|
||||
#define WLAN_EID_HT_CAP 45
|
||||
#define WLAN_EID_RSN 48
|
||||
#define WLAN_EID_EXT_SUPP_RATES 50
|
||||
#define WLAN_EID_NEIGHBOR_REPORT 52
|
||||
#define WLAN_EID_MOBILITY_DOMAIN 54
|
||||
#define WLAN_EID_FAST_BSS_TRANSITION 55
|
||||
#define WLAN_EID_TIMEOUT_INTERVAL 56
|
||||
#define WLAN_EID_RIC_DATA 57
|
||||
#define WLAN_EID_HT_OPERATION 61
|
||||
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
|
||||
#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
|
||||
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
|
||||
#define WLAN_EID_20_40_BSS_INTOLERANT 73
|
||||
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
|
||||
#define WLAN_EID_MMIE 76
|
||||
#define WLAN_EID_EXT_CAPAB 127
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
#define WLAN_EID_CAG_NUMBER 237
|
||||
#define WLAN_EID_AP_CSN 239
|
||||
@ -241,7 +236,7 @@
|
||||
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
|
||||
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
|
||||
#define WLAN_EID_EXT_KEY_DELIVERY 7
|
||||
#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
|
||||
#define WLAN_EID_EXT_WRAPPED_DATA 8
|
||||
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
|
||||
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
|
||||
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
|
||||
@ -253,8 +248,7 @@
|
||||
#define WLAN_EID_EXT_HE_CAPABILITIES 35
|
||||
#define WLAN_EID_EXT_HE_OPERATION 36
|
||||
|
||||
|
||||
/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
|
||||
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
|
||||
#define WLAN_ACTION_SPECTRUM_MGMT 0
|
||||
#define WLAN_ACTION_QOS 1
|
||||
#define WLAN_ACTION_DLS 2
|
||||
@ -264,6 +258,8 @@
|
||||
#define WLAN_ACTION_FT 6
|
||||
#define WLAN_ACTION_HT 7
|
||||
#define WLAN_ACTION_SA_QUERY 8
|
||||
#define WLAN_ACTION_WNM 10
|
||||
#define WLAN_ACTION_UNPROTECTED_WNM 11
|
||||
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
|
||||
|
||||
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
|
||||
@ -300,6 +296,51 @@ struct ieee80211_hdr {
|
||||
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
|
||||
|
||||
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
|
||||
/* Radio Measurement Action codes */
|
||||
#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
|
||||
#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
|
||||
#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
|
||||
#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
|
||||
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
|
||||
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
|
||||
|
||||
/* Radio Measurement capabilities (from RM Enabled Capabilities element)
|
||||
* IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
|
||||
/* byte 1 (out of 5) */
|
||||
#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
|
||||
#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
|
||||
#define WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE BIT(4)
|
||||
#define WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE BIT(5)
|
||||
#define WLAN_RRM_CAPS_BEACON_REPORT_TABLE BIT(6)
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
|
||||
* measurement requests
|
||||
*/
|
||||
enum measure_type {
|
||||
MEASURE_TYPE_RPI_HIST = 2,
|
||||
MEASURE_TYPE_BEACON = 5,
|
||||
MEASURE_TYPE_LCI = 8,
|
||||
MEASURE_TYPE_LOCATION_CIVIC = 11,
|
||||
MEASURE_TYPE_MEASURE_PAUSE = 255,
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
|
||||
enum location_subject {
|
||||
LOCATION_SUBJECT_LOCAL = 0,
|
||||
LOCATION_SUBJECT_REMOTE = 1,
|
||||
LOCATION_SUBJECT_3RD_PARTY = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
|
||||
*/
|
||||
enum lci_req_subelem {
|
||||
LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
|
||||
LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
|
||||
LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
|
||||
LCI_REQ_SUBELEM_MAX_AGE = 4,
|
||||
};
|
||||
|
||||
struct ieee80211_mgmt {
|
||||
le16 frame_control;
|
||||
@ -406,6 +447,7 @@ struct ieee80211_mgmt {
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
#define IEEE80211_MAX_MMPDU_SIZE 2304
|
||||
struct ieee80211_ht_capabilities {
|
||||
le16 ht_capabilities_info;
|
||||
u8 a_mpdu_params;
|
||||
@ -416,12 +458,14 @@ struct ieee80211_ht_capabilities {
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
/* HT Operation element */
|
||||
struct ieee80211_ht_operation {
|
||||
u8 control_chan;
|
||||
u8 ht_param;
|
||||
le16 operation_mode;
|
||||
le16 stbc_param;
|
||||
u8 basic_set[16];
|
||||
u8 primary_chan;
|
||||
/* Five octets of HT Operation Information */
|
||||
u8 ht_param; /* B0..B7 */
|
||||
le16 operation_mode; /* B8..B23 */
|
||||
le16 param; /* B24..B39 */
|
||||
u8 basic_mcs_set[16];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -432,7 +476,9 @@ struct ieee80211_ht_operation {
|
||||
#define ERP_INFO_USE_PROTECTION BIT(1)
|
||||
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
|
||||
|
||||
#define OVERLAPPING_BSS_TRANS_DELAY_FACTOR 5
|
||||
|
||||
/* HT Capabilities Info field within HT Capabilities element */
|
||||
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
|
||||
#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1))
|
||||
#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3)))
|
||||
@ -450,79 +496,86 @@ struct ieee80211_ht_operation {
|
||||
#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10))
|
||||
#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11))
|
||||
#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12))
|
||||
#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13))
|
||||
/* B13 - Reserved (was PSMP support during P802.11n development) */
|
||||
#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14))
|
||||
#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15))
|
||||
|
||||
|
||||
/* HT Extended Capabilities field within HT Capabilities element */
|
||||
#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0))
|
||||
#define EXT_HT_CAP_INFO_PCO_TRANS_TIME_MASK ((u16) (BIT(1) | BIT(2)))
|
||||
#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1
|
||||
/* B3..B7 - Reserved */
|
||||
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_MASK ((u16) (BIT(8) | BIT(9)))
|
||||
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8
|
||||
#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10))
|
||||
#define EXT_HT_CAP_INFO_HTC_SUPPORT ((u16) BIT(10))
|
||||
#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11))
|
||||
/* B12..B15 - Reserved */
|
||||
|
||||
/* Transmit Beanforming Capabilities within HT Capabilities element */
|
||||
#define TX_BF_CAP_IMPLICIT_TXBF_RX_CAP ((u32) BIT(0))
|
||||
#define TX_BF_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
|
||||
#define TX_BF_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
|
||||
#define TX_BF_CAP_RX_NDP_CAP ((u32) BIT(3))
|
||||
#define TX_BF_CAP_TX_NDP_CAP ((u32) BIT(4))
|
||||
#define TX_BF_CAP_IMPLICIT_TX_BF_CAP ((u32) BIT(5))
|
||||
#define TX_BF_CAP_CALIBRATION_MASK ((u32) (BIT(6) | BIT(7))
|
||||
#define TX_BF_CAP_CALIB_OFFSET 6
|
||||
#define TX_BF_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
|
||||
#define TX_BF_CAP_EXPLICIT_NONCOMPR_STEERING_CAP ((u32) BIT(9))
|
||||
#define TX_BF_CAP_EXPLICIT_COMPR_STEERING_CAP ((u32) BIT(10))
|
||||
#define TX_BF_CAP_EXPLICIT_TX_BF_CSI_FEEDBACK_MASK ((u32) (BIT(10) | BIT(11)))
|
||||
#define TX_BF_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
|
||||
#define TX_BF_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
|
||||
#define TX_BF_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
|
||||
#define TX_BF_CAP_MINIMAL_GROUPING_OFFSET 17
|
||||
#define TX_BF_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
|
||||
#define TX_BF_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
|
||||
#define TX_BF_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
|
||||
#define TX_BF_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
|
||||
#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_MASK ((u32) (BIT(27) | BIT(28)))
|
||||
#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_OFFSET 27
|
||||
/* B29..B31 - Reserved */
|
||||
|
||||
#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
|
||||
#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
|
||||
#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
|
||||
#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
|
||||
#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
|
||||
#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
|
||||
#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
|
||||
#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
|
||||
#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
|
||||
#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
|
||||
#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
|
||||
#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
|
||||
|
||||
|
||||
#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
|
||||
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
|
||||
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
|
||||
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
|
||||
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
|
||||
#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
|
||||
#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
|
||||
/* ASEL Capability field within HT Capabilities element */
|
||||
#define ASEL_CAP_ASEL_CAPABLE ((u8) BIT(0))
|
||||
#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
|
||||
#define ASEL_CAP_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
|
||||
#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
|
||||
#define ASEL_CAP_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
|
||||
#define ASEL_CAP_RX_AS_CAP ((u8) BIT(5))
|
||||
#define ASEL_CAP_TX_SOUNDING_PPDUS_CAP ((u8) BIT(6))
|
||||
/* B7 - Reserved */
|
||||
|
||||
/* First octet of HT Operation Information within HT Operation element */
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
|
||||
#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
|
||||
#define HT_INFO_HT_PARAM_STA_CHNL_WIDTH ((u8) BIT(2))
|
||||
#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
|
||||
#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
|
||||
#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
|
||||
/* B4..B7 - Reserved */
|
||||
|
||||
/* HT Protection (B8..B9 of HT Operation Information) */
|
||||
#define HT_PROT_NO_PROTECTION 0
|
||||
#define HT_PROT_NONMEMBER_PROTECTION 1
|
||||
#define HT_PROT_20MHZ_PROTECTION 2
|
||||
#define HT_PROT_NON_HT_MIXED 3
|
||||
/* Bits within ieee80211_ht_operation::operation_mode (BIT(0) maps to B8 in
|
||||
* HT Operation Information) */
|
||||
#define HT_OPER_OP_MODE_HT_PROT_MASK ((u16) (BIT(0) | BIT(1))) /* B8..B9 */
|
||||
#define HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT ((u16) BIT(2)) /* B10 */
|
||||
/* BIT(3), i.e., B11 in HT Operation Information field - Reserved */
|
||||
#define HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT ((u16) BIT(4)) /* B12 */
|
||||
/* BIT(5)..BIT(15), i.e., B13..B23 - Reserved */
|
||||
|
||||
#define OP_MODE_PURE 0
|
||||
#define OP_MODE_MAY_BE_LEGACY_STAS 1
|
||||
#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
|
||||
#define OP_MODE_MIXED 3
|
||||
|
||||
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
|
||||
((le16) (0x0001 | 0x0002))
|
||||
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
|
||||
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
|
||||
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
|
||||
#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
|
||||
|
||||
#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
|
||||
#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
|
||||
#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8))
|
||||
#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
|
||||
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
|
||||
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
|
||||
|
||||
|
||||
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
|
||||
* 00:50:F2 */
|
||||
#define WPA_IE_VENDOR_TYPE 0x0050f201
|
||||
#define WPS_IE_VENDOR_TYPE 0x0050f204
|
||||
/* Last two octets of HT Operation Information (BIT(0) = B24) */
|
||||
/* B24..B29 - Reserved */
|
||||
#define HT_OPER_PARAM_DUAL_BEACON ((u16) BIT(6))
|
||||
#define HT_OPER_PARAM_DUAL_CTS_PROTECTION ((u16) BIT(7))
|
||||
#define HT_OPER_PARAM_STBC_BEACON ((u16) BIT(8))
|
||||
#define HT_OPER_PARAM_LSIG_TXOP_PROT_FULL_SUPP ((u16) BIT(9))
|
||||
#define HT_OPER_PARAM_PCO_ACTIVE ((u16) BIT(10))
|
||||
#define HT_OPER_PARAM_PCO_PHASE ((u16) BIT(11))
|
||||
/* B36..B39 - Reserved */
|
||||
|
||||
#define WMM_OUI_TYPE 2
|
||||
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
@ -589,7 +642,7 @@ struct wmm_parameter_element {
|
||||
u8 oui_type; /* 2 */
|
||||
u8 oui_subtype; /* 1 */
|
||||
u8 version; /* 1 for WMM version 1.0 */
|
||||
u8 qos_info; /* AP/STA specif QoS info */
|
||||
u8 qos_info; /* AP/STA specific QoS info */
|
||||
u8 reserved; /* 0 */
|
||||
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
|
||||
|
||||
@ -624,29 +677,260 @@ struct wmm_tspec_element {
|
||||
|
||||
|
||||
/* Access Categories / ACI to AC coding */
|
||||
enum {
|
||||
enum wmm_ac {
|
||||
WMM_AC_BE = 0 /* Best Effort */,
|
||||
WMM_AC_BK = 1 /* Background */,
|
||||
WMM_AC_VI = 2 /* Video */,
|
||||
WMM_AC_VO = 3 /* Voice */
|
||||
WMM_AC_VO = 3 /* Voice */,
|
||||
WMM_AC_NUM = 4
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
|
||||
/* Table 4-21: Transition Rejection Reason Code Field Values */
|
||||
enum mbo_transition_reject_reason {
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0,
|
||||
MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1,
|
||||
MBO_TRANSITION_REJECT_REASON_DELAY = 2,
|
||||
MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3,
|
||||
MBO_TRANSITION_REJECT_REASON_RSSI = 4,
|
||||
MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5,
|
||||
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
|
||||
};
|
||||
|
||||
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
|
||||
/* IEEE 802.11v - WNM Action field values */
|
||||
enum wnm_action {
|
||||
WNM_EVENT_REQ = 0,
|
||||
WNM_EVENT_REPORT = 1,
|
||||
WNM_DIAGNOSTIC_REQ = 2,
|
||||
WNM_DIAGNOSTIC_REPORT = 3,
|
||||
WNM_LOCATION_CFG_REQ = 4,
|
||||
WNM_LOCATION_CFG_RESP = 5,
|
||||
WNM_BSS_TRANS_MGMT_QUERY = 6,
|
||||
WNM_BSS_TRANS_MGMT_REQ = 7,
|
||||
WNM_BSS_TRANS_MGMT_RESP = 8,
|
||||
WNM_FMS_REQ = 9,
|
||||
WNM_FMS_RESP = 10,
|
||||
WNM_COLLOCATED_INTERFERENCE_REQ = 11,
|
||||
WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
|
||||
WNM_TFS_REQ = 13,
|
||||
WNM_TFS_RESP = 14,
|
||||
WNM_TFS_NOTIFY = 15,
|
||||
WNM_SLEEP_MODE_REQ = 16,
|
||||
WNM_SLEEP_MODE_RESP = 17,
|
||||
WNM_TIM_BROADCAST_REQ = 18,
|
||||
WNM_TIM_BROADCAST_RESP = 19,
|
||||
WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
|
||||
WNM_CHANNEL_USAGE_REQ = 21,
|
||||
WNM_CHANNEL_USAGE_RESP = 22,
|
||||
WNM_DMS_REQ = 23,
|
||||
WNM_DMS_RESP = 24,
|
||||
WNM_TIMING_MEASUREMENT_REQ = 25,
|
||||
WNM_NOTIFICATION_REQ = 26,
|
||||
WNM_NOTIFICATION_RESP = 27
|
||||
};
|
||||
|
||||
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
|
||||
/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
|
||||
#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
|
||||
#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
|
||||
#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
|
||||
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
|
||||
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
|
||||
|
||||
/* cipher suite selectors */
|
||||
#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
|
||||
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
|
||||
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
|
||||
/* reserved: 0x000FAC03 */
|
||||
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
|
||||
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
|
||||
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
|
||||
/* IEEE Std 802.11-2012 - Table 8-253 */
|
||||
enum bss_trans_mgmt_status_code {
|
||||
WNM_BSS_TM_ACCEPT = 0,
|
||||
WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
|
||||
WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
|
||||
WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
|
||||
WNM_BSS_TM_REJECT_UNDESIRED = 4,
|
||||
WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
|
||||
WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
|
||||
WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
|
||||
WNM_BSS_TM_REJECT_LEAVING_ESS = 8
|
||||
};
|
||||
|
||||
/* AKM suite selectors */
|
||||
#define WLAN_AKM_SUITE_8021X 0x000FAC01
|
||||
#define WLAN_AKM_SUITE_PSK 0x000FAC02
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
|
||||
* neighbor report
|
||||
*/
|
||||
#define WNM_NEIGHBOR_TSF 1
|
||||
#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
|
||||
#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
|
||||
#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
|
||||
#define WNM_NEIGHBOR_BEARING 5
|
||||
#define WNM_NEIGHBOR_MEASUREMENT_REPORT 39
|
||||
#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
|
||||
#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
|
||||
#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
|
||||
|
||||
struct tpc_report {
|
||||
u8 eid;
|
||||
u8 len;
|
||||
u8 tx_power;
|
||||
u8 link_margin;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define RRM_CAPABILITIES_IE_LEN 5
|
||||
|
||||
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
|
||||
struct rrm_link_measurement_request {
|
||||
u8 dialog_token;
|
||||
s8 tx_power;
|
||||
s8 max_tp;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
|
||||
struct rrm_link_measurement_report {
|
||||
u8 dialog_token;
|
||||
struct tpc_report tpc;
|
||||
u8 rx_ant_id;
|
||||
u8 tx_ant_id;
|
||||
u8 rcpi;
|
||||
u8 rsni;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */
|
||||
struct rrm_measurement_request_element {
|
||||
u8 eid; /* Element ID */
|
||||
u8 len; /* Length */
|
||||
u8 token; /* Measurement Token */
|
||||
u8 mode; /* Measurement Request Mode */
|
||||
u8 type; /* Measurement Type */
|
||||
u8 variable[0]; /* Measurement Request */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */
|
||||
#define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0)
|
||||
#define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1)
|
||||
#define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2)
|
||||
#define MEASUREMENT_REQUEST_MODE_REPORT BIT(3)
|
||||
#define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4)
|
||||
|
||||
/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */
|
||||
struct rrm_measurement_beacon_request {
|
||||
u8 oper_class; /* Operating Class */
|
||||
u8 channel; /* Channel Number */
|
||||
le16 rand_interval; /* Randomization Interval (in TUs) */
|
||||
le16 duration; /* Measurement Duration (in TUs) */
|
||||
u8 mode; /* Measurement Mode */
|
||||
u8 bssid[ETH_ALEN]; /* BSSID */
|
||||
u8 variable[0]; /* Optional Subelements */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/*
|
||||
* IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon
|
||||
* request
|
||||
*/
|
||||
enum beacon_report_mode {
|
||||
BEACON_REPORT_MODE_PASSIVE = 0,
|
||||
BEACON_REPORT_MODE_ACTIVE = 1,
|
||||
BEACON_REPORT_MODE_TABLE = 2,
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
|
||||
* Beacon request */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_SSID 0
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221
|
||||
|
||||
/*
|
||||
* IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values
|
||||
*/
|
||||
enum beacon_report_detail {
|
||||
/* No fixed-length fields or elements */
|
||||
BEACON_REPORT_DETAIL_NONE = 0,
|
||||
/* All fixed-length fields and any requested elements in the Request
|
||||
* element if present */
|
||||
BEACON_REPORT_DETAIL_REQUESTED_ONLY = 1,
|
||||
/* All fixed-length fields and elements (default, used when Reporting
|
||||
* Detail subelement is not included in a Beacon request) */
|
||||
BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2,
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */
|
||||
struct rrm_measurement_report_element {
|
||||
u8 eid; /* Element ID */
|
||||
u8 len; /* Length */
|
||||
u8 token; /* Measurement Token */
|
||||
u8 mode; /* Measurement Report Mode */
|
||||
u8 type; /* Measurement Type */
|
||||
u8 variable[0]; /* Measurement Report */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */
|
||||
#define MEASUREMENT_REPORT_MODE_ACCEPT 0
|
||||
#define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0)
|
||||
#define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1)
|
||||
#define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2)
|
||||
|
||||
/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */
|
||||
struct rrm_measurement_beacon_report {
|
||||
u8 op_class; /* Operating Class */
|
||||
u8 channel; /* Channel Number */
|
||||
le64 start_time; /* Actual Measurement Start Time
|
||||
* (in TSF of the BSS requesting the measurement) */
|
||||
le16 duration; /* in TUs */
|
||||
u8 report_info; /* Reported Frame Information */
|
||||
u8 rcpi; /* RCPI */
|
||||
u8 rsni; /* RSNI */
|
||||
u8 bssid[ETH_ALEN]; /* BSSID */
|
||||
u8 antenna_id; /* Antenna ID */
|
||||
le32 parent_tsf; /* Parent TSF */
|
||||
u8 variable[0]; /* Optional Subelements */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
|
||||
* Beacon report */
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164
|
||||
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
|
||||
* Reported Frame Body Fragment ID subelement */
|
||||
#define REPORTED_FRAME_BODY_SUBELEM_LEN 4
|
||||
#define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7)
|
||||
|
||||
/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */
|
||||
#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3
|
||||
|
||||
/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */
|
||||
enum phy_type {
|
||||
PHY_TYPE_UNSPECIFIED = 0,
|
||||
PHY_TYPE_FHSS = 1,
|
||||
PHY_TYPE_DSSS = 2,
|
||||
PHY_TYPE_IRBASEBAND = 3,
|
||||
PHY_TYPE_OFDM = 4,
|
||||
PHY_TYPE_HRDSSS = 5,
|
||||
PHY_TYPE_ERP = 6,
|
||||
PHY_TYPE_HT = 7,
|
||||
PHY_TYPE_DMG = 8,
|
||||
PHY_TYPE_VHT = 9,
|
||||
};
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
|
||||
/* BSSID Information Field */
|
||||
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
|
||||
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
|
||||
#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1))
|
||||
#define NEI_REP_BSSID_INFO_SECURITY BIT(2)
|
||||
#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3)
|
||||
#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4)
|
||||
#define NEI_REP_BSSID_INFO_QOS BIT(5)
|
||||
#define NEI_REP_BSSID_INFO_APSD BIT(6)
|
||||
#define NEI_REP_BSSID_INFO_RM BIT(7)
|
||||
#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8)
|
||||
#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
|
||||
#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
|
||||
#define NEI_REP_BSSID_INFO_HT BIT(11)
|
||||
#define NEI_REP_BSSID_INFO_VHT BIT(12)
|
||||
#define NEI_REP_BSSID_INFO_FTM BIT(13)
|
||||
|
||||
#endif /* IEEE802_11_DEFS_H */
|
||||
|
1162
components/wpa_supplicant/src/common/rrm.c
Normal file
1162
components/wpa_supplicant/src/common/rrm.c
Normal file
File diff suppressed because it is too large
Load Diff
30
components/wpa_supplicant/src/common/rrm.h
Normal file
30
components/wpa_supplicant/src/common/rrm.h
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef RRM_H
|
||||
#define RRM_H
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "utils/list.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
|
||||
|
||||
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
|
||||
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
|
||||
const u8 *report, size_t report_len);
|
||||
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
int lci, int civic,
|
||||
void (*cb)(void *ctx,
|
||||
const u8 *neighbor_rep, size_t len),
|
||||
void *cb_ctx);
|
||||
void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
|
||||
const u8 *src, const u8 *dst,
|
||||
const u8 *frame, size_t len);
|
||||
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
|
||||
const u8 *src,
|
||||
const u8 *frame, size_t len,
|
||||
int rssi);
|
||||
int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
|
||||
u64 scan_start_tsf);
|
||||
void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
|
||||
|
||||
#endif
|
95
components/wpa_supplicant/src/common/scan.c
Normal file
95
components/wpa_supplicant/src/common/scan.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* WPA Supplicant - Scanning
|
||||
* Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "common/ieee802_11_defs.h"
|
||||
#include "config.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "bss.h"
|
||||
#include "scan.h"
|
||||
|
||||
/**
|
||||
* wpa_supplicant_req_scan - Schedule a scan for neighboring access points
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @sec: Number of seconds after which to scan
|
||||
* @usec: Number of microseconds after which to scan
|
||||
*
|
||||
* This function is used to schedule a scan for neighboring access points after
|
||||
* the specified time.
|
||||
*/
|
||||
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
|
||||
{
|
||||
int ret;
|
||||
struct wpa_driver_scan_params *params;
|
||||
|
||||
os_sleep(sec, usec);
|
||||
|
||||
if (wpa_s->scanning) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Return");
|
||||
return;
|
||||
}
|
||||
params = os_zalloc(sizeof(*params));
|
||||
|
||||
if (wpa_s->wnm_mode) {
|
||||
/* Use the same memory */
|
||||
params->ssids[0].ssid = wpa_s->current_bss->ssid;
|
||||
params->ssids[0].ssid_len = wpa_s->current_bss->ssid_len;
|
||||
params->num_ssids = 1;
|
||||
}
|
||||
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
|
||||
/* Use the same memory */
|
||||
params->bssid = wpa_s->next_scan_bssid;
|
||||
}
|
||||
|
||||
if (wpa_s->next_scan_chan)
|
||||
params->channel = wpa_s->next_scan_chan;
|
||||
|
||||
wpa_s->scan_reason = REASON_WNM_BSS_TRANS_REQ;
|
||||
ret = wpa_supplicant_trigger_scan(wpa_s, params);
|
||||
|
||||
os_free(params);
|
||||
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to issue scan - Return");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_scan_get_ie - Fetch a specified information element from a scan result
|
||||
* @res: Scan result entry
|
||||
* @ie: Information element identitifier (WLAN_EID_*)
|
||||
* Returns: Pointer to the information element (id field) or %NULL if not found
|
||||
*
|
||||
* This function returns the first matching information element in the scan
|
||||
* result.
|
||||
*/
|
||||
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
|
||||
{
|
||||
size_t ie_len = res->ie_len;
|
||||
|
||||
/* Use the Beacon frame IEs if res->ie_len is not available */
|
||||
if (!ie_len)
|
||||
ie_len = res->beacon_ie_len;
|
||||
|
||||
return get_ie((const u8 *) (res + 1), ie_len, ie);
|
||||
}
|
||||
|
||||
void wpa_scan_free_params(struct wpa_driver_scan_params *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
return;
|
||||
|
||||
os_free((u8 *) params->bssid);
|
||||
|
||||
os_free(params);
|
||||
}
|
25
components/wpa_supplicant/src/common/scan.h
Normal file
25
components/wpa_supplicant/src/common/scan.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* WPA Supplicant - Scanning
|
||||
* Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef SCAN_H
|
||||
#define SCAN_H
|
||||
|
||||
/*
|
||||
* Noise floor values to use when we have signal strength
|
||||
* measurements, but no noise floor measurements. These values were
|
||||
* measured in an office environment with many APs.
|
||||
*/
|
||||
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
|
||||
|
||||
struct wpa_driver_scan_params;
|
||||
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
|
||||
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *params);
|
||||
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
|
||||
void wpa_scan_free_params(struct wpa_driver_scan_params *params);
|
||||
#endif /* SCAN_H */
|
966
components/wpa_supplicant/src/common/wnm_sta.c
Normal file
966
components/wpa_supplicant/src/common/wnm_sta.c
Normal file
@ -0,0 +1,966 @@
|
||||
/*
|
||||
* wpa_supplicant - WNM
|
||||
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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 "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "rsn_supp/wpa.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "scan.h"
|
||||
#include "bss.h"
|
||||
#include "wnm_sta.h"
|
||||
|
||||
#define MAX_TFS_IE_LEN 1024
|
||||
#define WNM_MAX_NEIGHBOR_REPORT 10
|
||||
|
||||
#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
|
||||
|
||||
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
|
||||
os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
|
||||
os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
|
||||
}
|
||||
|
||||
wpa_s->wnm_num_neighbor_report = 0;
|
||||
os_free(wpa_s->wnm_neighbor_report_elements);
|
||||
wpa_s->wnm_neighbor_report_elements = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
|
||||
u8 id, u8 elen, const u8 *pos)
|
||||
{
|
||||
switch (id) {
|
||||
case WNM_NEIGHBOR_TSF:
|
||||
if (elen < 2 + 2) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
|
||||
break;
|
||||
}
|
||||
rep->tsf_offset = WPA_GET_LE16(pos);
|
||||
rep->beacon_int = WPA_GET_LE16(pos + 2);
|
||||
rep->tsf_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
|
||||
if (elen < 2) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
|
||||
"country string");
|
||||
break;
|
||||
}
|
||||
os_memcpy(rep->country, pos, 2);
|
||||
rep->country_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
|
||||
if (elen < 1) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
|
||||
"candidate");
|
||||
break;
|
||||
}
|
||||
rep->preference = pos[0];
|
||||
rep->preference_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
|
||||
if (elen < 10) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Too short BSS termination duration");
|
||||
break;
|
||||
}
|
||||
rep->bss_term_tsf = WPA_GET_LE64(pos);
|
||||
rep->bss_term_dur = WPA_GET_LE16(pos + 8);
|
||||
rep->bss_term_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_BEARING:
|
||||
if (elen < 8) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
|
||||
"bearing");
|
||||
break;
|
||||
}
|
||||
rep->bearing = WPA_GET_LE16(pos);
|
||||
rep->distance = WPA_GET_LE32(pos + 2);
|
||||
rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
|
||||
rep->bearing_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_MEASUREMENT_PILOT:
|
||||
if (elen < 1) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
|
||||
"pilot");
|
||||
break;
|
||||
}
|
||||
os_free(rep->meas_pilot);
|
||||
rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
|
||||
if (rep->meas_pilot == NULL)
|
||||
break;
|
||||
rep->meas_pilot->measurement_pilot = pos[0];
|
||||
rep->meas_pilot->subelem_len = elen - 1;
|
||||
os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
|
||||
break;
|
||||
case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
|
||||
if (elen < 5) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
|
||||
"capabilities");
|
||||
break;
|
||||
}
|
||||
os_memcpy(rep->rm_capab, pos, 5);
|
||||
rep->rm_capab_present = 1;
|
||||
break;
|
||||
case WNM_NEIGHBOR_MULTIPLE_BSSID:
|
||||
if (elen < 1) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
|
||||
break;
|
||||
}
|
||||
os_free(rep->mul_bssid);
|
||||
rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
|
||||
if (rep->mul_bssid == NULL)
|
||||
break;
|
||||
rep->mul_bssid->max_bssid_indicator = pos[0];
|
||||
rep->mul_bssid->subelem_len = elen - 1;
|
||||
os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
|
||||
const u8 *pos, u8 len,
|
||||
struct neighbor_report *rep)
|
||||
{
|
||||
u8 left = len;
|
||||
|
||||
if (left < 13) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(rep->bssid, pos, ETH_ALEN);
|
||||
rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
|
||||
rep->regulatory_class = *(pos + 10);
|
||||
rep->channel_number = *(pos + 11);
|
||||
rep->phy_type = *(pos + 12);
|
||||
|
||||
pos += 13;
|
||||
left -= 13;
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
|
||||
left -= 2;
|
||||
if (elen > left) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Truncated neighbor report subelement");
|
||||
break;
|
||||
}
|
||||
wnm_parse_neighbor_report_elem(rep, id, elen, pos);
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++)
|
||||
wpa_s->wnm_neighbor_report_elements[i].acceptable = 0;
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
unsigned int i;
|
||||
struct neighbor_report *nei;
|
||||
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
|
||||
nei = &wpa_s->wnm_neighbor_report_elements[i];
|
||||
if (nei->acceptable)
|
||||
return wpa_bss_get_bssid(wpa_s, nei->bssid);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* basic function to match candidate profile with current bss */
|
||||
bool wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *current_bss,
|
||||
struct wpa_bss *target_bss)
|
||||
{
|
||||
if (current_bss->ssid_len != target_bss->ssid_len) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: ssid didn't match");
|
||||
return false;
|
||||
}
|
||||
if (os_memcmp(current_bss->ssid, target_bss->ssid, current_bss->ssid_len) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: ssid didn't match");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO security Match */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_bss *
|
||||
compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
|
||||
enum mbo_transition_reject_reason *reason)
|
||||
{
|
||||
u8 i;
|
||||
struct wpa_bss *bss = wpa_s->current_bss;
|
||||
struct wpa_bss *target;
|
||||
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
wnm_clear_acceptable(wpa_s);
|
||||
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
|
||||
struct neighbor_report *nei;
|
||||
|
||||
nei = &wpa_s->wnm_neighbor_report_elements[i];
|
||||
if (nei->preference_present && nei->preference == 0) {
|
||||
wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
|
||||
MAC2STR(nei->bssid));
|
||||
continue;
|
||||
}
|
||||
|
||||
target = wpa_bss_get_bssid(wpa_s, nei->bssid);
|
||||
if (!target) {
|
||||
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
|
||||
" (pref %d) not found in scan results",
|
||||
MAC2STR(nei->bssid),
|
||||
nei->preference_present ? nei->preference :
|
||||
-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (age_secs) {
|
||||
struct os_reltime now;
|
||||
|
||||
if (os_get_reltime(&now) == 0 &&
|
||||
os_time_expired(&now, &target->last_update,
|
||||
age_secs)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Candidate BSS is more than %ld seconds old",
|
||||
age_secs);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bss->ssid_len != target->ssid_len ||
|
||||
os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
|
||||
/*
|
||||
* TODO: Could consider allowing transition to another
|
||||
* ESS if PMF was enabled for the association.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
|
||||
" (pref %d) in different ESS",
|
||||
MAC2STR(nei->bssid),
|
||||
nei->preference_present ? nei->preference :
|
||||
-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wpa_s->current_bss &&
|
||||
!wpa_scan_res_match(wpa_s, wpa_s->current_bss, target)) {
|
||||
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
|
||||
" (pref %d) does not match the current network profile",
|
||||
MAC2STR(nei->bssid),
|
||||
nei->preference_present ? nei->preference :
|
||||
-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target->level < bss->level && target->level < -80) {
|
||||
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
|
||||
" (pref %d) does not have sufficient signal level (%d)",
|
||||
MAC2STR(nei->bssid),
|
||||
nei->preference_present ? nei->preference :
|
||||
-1,
|
||||
target->level);
|
||||
continue;
|
||||
}
|
||||
|
||||
nei->acceptable = 1;
|
||||
}
|
||||
|
||||
target = get_first_acceptable(wpa_s);
|
||||
|
||||
if (target) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Found an acceptable preferred transition candidate BSS "
|
||||
MACSTR " (RSSI %d)",
|
||||
MAC2STR(target->bssid), target->level);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
|
||||
{
|
||||
const u8 *ie_a, *ie_b;
|
||||
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
|
||||
ie_a = wpa_bss_get_ie(a, eid);
|
||||
ie_b = wpa_bss_get_ie(b, eid);
|
||||
|
||||
if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
|
||||
return 0;
|
||||
|
||||
return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
|
||||
}
|
||||
|
||||
|
||||
static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
||||
{
|
||||
u32 info = 0;
|
||||
|
||||
info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
|
||||
|
||||
/*
|
||||
* Leave the security and key scope bits unset to indicate that the
|
||||
* security information is not available.
|
||||
*/
|
||||
|
||||
if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
|
||||
info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
|
||||
if (bss->caps & WLAN_CAPABILITY_QOS)
|
||||
info |= NEI_REP_BSSID_INFO_QOS;
|
||||
if (bss->caps & WLAN_CAPABILITY_APSD)
|
||||
info |= NEI_REP_BSSID_INFO_APSD;
|
||||
if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
|
||||
info |= NEI_REP_BSSID_INFO_RM;
|
||||
if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
|
||||
info |= NEI_REP_BSSID_INFO_DELAYED_BA;
|
||||
if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
|
||||
info |= NEI_REP_BSSID_INFO_IMM_BA;
|
||||
if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
|
||||
info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
|
||||
if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
|
||||
info |= NEI_REP_BSSID_INFO_HT;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid,
|
||||
u32 bss_info, u8 op_class, u8 chan, u8 phy_type,
|
||||
u8 pref)
|
||||
{
|
||||
if (wpabuf_len(*buf) + 18 >
|
||||
IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: No room in frame for Neighbor Report element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpabuf_resize(buf, 18) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Failed to allocate memory for Neighbor Report element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT);
|
||||
/* length: 13 for basic neighbor report + 3 for preference subelement */
|
||||
wpabuf_put_u8(*buf, 16);
|
||||
wpabuf_put_data(*buf, bssid, ETH_ALEN);
|
||||
wpabuf_put_le32(*buf, bss_info);
|
||||
wpabuf_put_u8(*buf, op_class);
|
||||
wpabuf_put_u8(*buf, chan);
|
||||
wpabuf_put_u8(*buf, phy_type);
|
||||
wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE);
|
||||
wpabuf_put_u8(*buf, 1);
|
||||
wpabuf_put_u8(*buf, pref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, struct wpabuf **buf,
|
||||
u8 pref)
|
||||
{
|
||||
const u8 *ie;
|
||||
u8 op_class;
|
||||
int sec_chan = 0;
|
||||
enum phy_type phy_type;
|
||||
u32 info;
|
||||
struct ieee80211_ht_operation *ht_oper = NULL;
|
||||
|
||||
ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
|
||||
if (ie && ie[1] >= 2) {
|
||||
ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
|
||||
|
||||
if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
|
||||
sec_chan = 1;
|
||||
else if (ht_oper->ht_param &
|
||||
HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
|
||||
sec_chan = -1;
|
||||
}
|
||||
|
||||
op_class = get_operating_class(bss->channel, sec_chan);
|
||||
|
||||
phy_type = (sec_chan != 0) ? PHY_TYPE_HT : PHY_TYPE_ERP;
|
||||
|
||||
info = wnm_get_bss_info(wpa_s, bss);
|
||||
|
||||
return wnm_add_nei_rep(buf, bss->bssid, info, op_class, bss->channel, phy_type,
|
||||
pref);
|
||||
}
|
||||
|
||||
|
||||
static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf)
|
||||
{
|
||||
unsigned int i, pref = 255;
|
||||
struct os_reltime now;
|
||||
|
||||
if (!wpa_s->current_bss)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Define when scan results are no longer valid for the candidate
|
||||
* list.
|
||||
*/
|
||||
os_get_reltime(&now);
|
||||
if (os_time_expired(&now, &wpa_s->last_scan, 10))
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Add candidate list to BSS Transition Management Response frame");
|
||||
for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
|
||||
struct wpa_bss *bss = wpa_s->last_scan_res[i];
|
||||
int res;
|
||||
|
||||
if (wpa_scan_res_match(wpa_s, wpa_s->current_bss, bss)) {
|
||||
res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--);
|
||||
if (res == -2)
|
||||
continue; /* could not build entry for BSS */
|
||||
if (res < 0)
|
||||
break; /* no more room for candidates */
|
||||
if (pref == 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_hexdump_buf(MSG_DEBUG,
|
||||
"WNM: BSS Transition Management Response candidate list",
|
||||
*buf);
|
||||
}
|
||||
|
||||
|
||||
#define BTM_RESP_MIN_SIZE 5 + ETH_ALEN
|
||||
|
||||
static void wnm_send_bss_transition_mgmt_resp(
|
||||
struct wpa_supplicant *wpa_s, u8 dialog_token,
|
||||
enum bss_trans_mgmt_status_code status,
|
||||
enum mbo_transition_reject_reason reason,
|
||||
u8 delay, const u8 *target_bssid)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Send BSS Transition Management Response to " MACSTR
|
||||
" dialog_token=%u status=%u reason=%u delay=%d",
|
||||
MAC2STR(wpa_s->current_bss->bssid), dialog_token, status, reason, delay);
|
||||
if (!wpa_s->current_bss) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Current BSS not known - drop response");
|
||||
return;
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(BTM_RESP_MIN_SIZE);
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Failed to allocate memory for BTM response");
|
||||
return;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
|
||||
wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
wpabuf_put_u8(buf, status);
|
||||
wpabuf_put_u8(buf, delay);
|
||||
if (target_bssid) {
|
||||
wpabuf_put_data(buf, target_bssid, ETH_ALEN);
|
||||
} else if (status == WNM_BSS_TM_ACCEPT) {
|
||||
/*
|
||||
* P802.11-REVmc clarifies that the Target BSSID field is always
|
||||
* present when status code is zero, so use a fake value here if
|
||||
* no BSSID is yet known.
|
||||
*/
|
||||
wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN);
|
||||
}
|
||||
|
||||
if (status == WNM_BSS_TM_ACCEPT)
|
||||
wnm_add_cand_list(wpa_s, &buf);
|
||||
|
||||
res = wpa_drv_send_action(wpa_s, 0, 0,
|
||||
wpabuf_head_u8(buf), wpabuf_len(buf), 0);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Failed to send BSS Transition Management Response");
|
||||
}
|
||||
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, char *ssid,
|
||||
int after_new_scan)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Transition to BSS " MACSTR
|
||||
" based on BSS Transition Management Request after_new_scan=%d)",
|
||||
MAC2STR(bss->bssid), after_new_scan);
|
||||
|
||||
/* Send the BSS Management Response - Accept */
|
||||
if (wpa_s->wnm_reply) {
|
||||
wpa_s->wnm_reply = 0;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Sending successful BSS Transition Management Response");
|
||||
wnm_send_bss_transition_mgmt_resp(
|
||||
wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT,
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
|
||||
bss->bssid);
|
||||
}
|
||||
|
||||
if (bss == wpa_s->current_bss) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Already associated with the preferred candidate");
|
||||
wnm_deallocate_memory(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
|
||||
|
||||
wpa_supplicant_connect(wpa_s, bss, ssid);
|
||||
wnm_deallocate_memory(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
|
||||
enum mbo_transition_reject_reason reason =
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
|
||||
|
||||
if (!wpa_s->wnm_neighbor_report_elements)
|
||||
return 0;
|
||||
|
||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||
"WNM: Process scan results for BSS Transition Management");
|
||||
if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
|
||||
&wpa_s->scan_trigger_time)) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
|
||||
wnm_deallocate_memory(wpa_s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare the Neighbor Report and scan results */
|
||||
bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
|
||||
if (!bss) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
|
||||
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
|
||||
goto send_bss_resp_fail;
|
||||
}
|
||||
|
||||
/* Associate to the network */
|
||||
wnm_bss_tm_connect(wpa_s, bss, NULL, 1);
|
||||
return 1;
|
||||
|
||||
send_bss_resp_fail:
|
||||
if (!reply_on_fail)
|
||||
return 0;
|
||||
|
||||
/* Send reject response for all the failures */
|
||||
|
||||
if (wpa_s->wnm_reply) {
|
||||
wpa_s->wnm_reply = 0;
|
||||
wnm_send_bss_transition_mgmt_resp(wpa_s,
|
||||
wpa_s->wnm_dialog_token,
|
||||
status, reason, 0, NULL);
|
||||
}
|
||||
wnm_deallocate_memory(wpa_s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cand_pref_compar(const void *a, const void *b)
|
||||
{
|
||||
const struct neighbor_report *aa = a;
|
||||
const struct neighbor_report *bb = b;
|
||||
|
||||
if (!aa->preference_present && !bb->preference_present)
|
||||
return 0;
|
||||
if (!aa->preference_present)
|
||||
return 1;
|
||||
if (!bb->preference_present)
|
||||
return -1;
|
||||
if (bb->preference > aa->preference)
|
||||
return 1;
|
||||
if (bb->preference < aa->preference)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
if (!wpa_s->wnm_neighbor_report_elements)
|
||||
return;
|
||||
qsort(wpa_s->wnm_neighbor_report_elements,
|
||||
wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
|
||||
cand_pref_compar);
|
||||
}
|
||||
|
||||
|
||||
static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
unsigned int i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
|
||||
if (!wpa_s->wnm_neighbor_report_elements)
|
||||
return;
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
|
||||
struct neighbor_report *nei;
|
||||
|
||||
nei = &wpa_s->wnm_neighbor_report_elements[i];
|
||||
wpa_printf(MSG_DEBUG, "%u: " MACSTR
|
||||
" info=0x%x op_class=%u chan=%u phy=%u pref=%d",
|
||||
i, MAC2STR(nei->bssid), nei->bssid_info,
|
||||
nei->regulatory_class,
|
||||
nei->channel_number, nei->phy_type,
|
||||
nei->preference_present ? nei->preference : -1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
unsigned int i;
|
||||
int num_chan;
|
||||
u8 chan = 0;
|
||||
|
||||
wpa_s->next_scan_chan = 0;
|
||||
if (!wpa_s->wnm_neighbor_report_elements)
|
||||
return;
|
||||
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
|
||||
struct neighbor_report *nei;
|
||||
|
||||
nei = &wpa_s->wnm_neighbor_report_elements[i];
|
||||
if (nei->channel_number <= 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Unknown neighbor operating channel_number for "
|
||||
MACSTR " - scan all channels",
|
||||
MAC2STR(nei->bssid));
|
||||
return;
|
||||
}
|
||||
if (nei->channel_number != chan)
|
||||
num_chan++;
|
||||
}
|
||||
|
||||
if (num_chan == 1) {
|
||||
wpa_s->next_scan_chan = chan;
|
||||
}
|
||||
}
|
||||
|
||||
static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
/* ESP doesn't support this */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
|
||||
const u8 *pos, const u8 *end,
|
||||
int reply)
|
||||
{
|
||||
unsigned int beacon_int;
|
||||
u8 valid_int;
|
||||
|
||||
if (wpa_s->disable_btm)
|
||||
return;
|
||||
|
||||
if (end - pos < 5)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
wpa_s->wnm_mbo_trans_reason_present = 0;
|
||||
wpa_s->wnm_mbo_transition_reason = 0;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
if (wpa_s->current_bss)
|
||||
beacon_int = wpa_s->current_bss->beacon_int;
|
||||
else
|
||||
beacon_int = 100; /* best guess */
|
||||
|
||||
wpa_s->wnm_dialog_token = pos[0];
|
||||
wpa_s->wnm_mode = pos[1];
|
||||
wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
|
||||
valid_int = pos[4];
|
||||
wpa_s->wnm_reply = reply;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
|
||||
"dialog_token=%u request_mode=0x%x "
|
||||
"disassoc_timer=%u validity_interval=%u",
|
||||
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
|
||||
wpa_s->wnm_dissoc_timer, valid_int);
|
||||
|
||||
pos += 5;
|
||||
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
|
||||
if (end - pos < 12) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
|
||||
return;
|
||||
}
|
||||
os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
|
||||
pos += 12; /* BSS Termination Duration */
|
||||
}
|
||||
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
|
||||
char url[256];
|
||||
|
||||
if (end - pos < 1 || 1 + pos[0] > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
|
||||
"Management Request (URL)");
|
||||
return;
|
||||
}
|
||||
os_memcpy(url, pos + 1, pos[0]);
|
||||
url[pos[0]] = '\0';
|
||||
pos += 1 + pos[0];
|
||||
|
||||
wpa_msg(wpa_s, MSG_DEBUG, "ESS_DISASSOC_IMMINENT %u %s",
|
||||
wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
|
||||
}
|
||||
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
|
||||
wpa_msg(wpa_s, MSG_DEBUG, "WNM: Disassociation Imminent - "
|
||||
"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
|
||||
if (wpa_s->wnm_dissoc_timer) {
|
||||
/* TODO: mark current BSS less preferred for
|
||||
* selection */
|
||||
wpa_printf(MSG_DEBUG, "Trying to find another BSS");
|
||||
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
|
||||
if (vendor)
|
||||
wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
|
||||
unsigned int valid_ms;
|
||||
|
||||
wpa_msg(wpa_s, MSG_DEBUG, "WNM: Preferred List Available");
|
||||
wnm_deallocate_memory(wpa_s);
|
||||
wpa_s->wnm_neighbor_report_elements = os_calloc(
|
||||
WNM_MAX_NEIGHBOR_REPORT,
|
||||
sizeof(struct neighbor_report));
|
||||
if (wpa_s->wnm_neighbor_report_elements == NULL)
|
||||
return;
|
||||
|
||||
while (end - pos >= 2 &&
|
||||
wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
|
||||
{
|
||||
u8 tag = *pos++;
|
||||
u8 len = *pos++;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
|
||||
tag);
|
||||
if (len > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "WNM: Truncated request");
|
||||
return;
|
||||
}
|
||||
if (tag == WLAN_EID_NEIGHBOR_REPORT) {
|
||||
struct neighbor_report *rep;
|
||||
rep = &wpa_s->wnm_neighbor_report_elements[
|
||||
wpa_s->wnm_num_neighbor_report];
|
||||
wnm_parse_neighbor_report(wpa_s, pos, len, rep);
|
||||
wpa_s->wnm_num_neighbor_report++;
|
||||
#ifdef CONFIG_MBO
|
||||
if (wpa_s->wnm_mbo_trans_reason_present &&
|
||||
wpa_s->wnm_num_neighbor_report == 1) {
|
||||
rep->is_first = 1;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: First transition candidate is "
|
||||
MACSTR, MAC2STR(rep->bssid));
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
if (!wpa_s->wnm_num_neighbor_report) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Candidate list included bit is set, but no candidates found");
|
||||
wnm_send_bss_transition_mgmt_resp(
|
||||
wpa_s, wpa_s->wnm_dialog_token,
|
||||
WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
wnm_sort_cand_list(wpa_s);
|
||||
wnm_dump_cand_list(wpa_s);
|
||||
valid_ms = valid_int * beacon_int * 128 / 125;
|
||||
wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
|
||||
valid_ms);
|
||||
os_get_reltime(&wpa_s->wnm_cand_valid_until);
|
||||
wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
|
||||
wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
|
||||
wpa_s->wnm_cand_valid_until.sec +=
|
||||
wpa_s->wnm_cand_valid_until.usec / 1000000;
|
||||
wpa_s->wnm_cand_valid_until.usec %= 1000000;
|
||||
|
||||
/*
|
||||
* Fetch the latest scan results from the kernel and check for
|
||||
* candidates based on those results first. This can help in
|
||||
* finding more up-to-date information should the driver has
|
||||
* done some internal scanning operations after the last scan
|
||||
* result update in wpa_supplicant.
|
||||
*/
|
||||
if (wnm_fetch_scan_results(wpa_s) > 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Try to use previously received scan results, if they are
|
||||
* recent enough to use for a connection.
|
||||
*/
|
||||
if (wpa_s->last_scan_res_used > 0) {
|
||||
struct os_reltime now;
|
||||
|
||||
os_get_reltime(&now);
|
||||
if (!os_time_expired(&now, &wpa_s->last_scan, 10)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Try to use recent scan results");
|
||||
if (wnm_scan_process(wpa_s, 0) > 0)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: No match in previous scan results - try a new scan");
|
||||
}
|
||||
}
|
||||
wnm_set_scan_freqs(wpa_s);
|
||||
if (wpa_s->wnm_num_neighbor_report == 1) {
|
||||
os_memcpy(wpa_s->next_scan_bssid,
|
||||
wpa_s->wnm_neighbor_report_elements[0].bssid,
|
||||
ETH_ALEN);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Scan only for a specific BSSID since there is only a single candidate "
|
||||
MACSTR, MAC2STR(wpa_s->next_scan_bssid));
|
||||
}
|
||||
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
||||
} else if (reply) {
|
||||
enum bss_trans_mgmt_status_code status;
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
|
||||
status = WNM_BSS_TM_ACCEPT;
|
||||
else {
|
||||
wpa_msg(wpa_s, MSG_DEBUG, "WNM: BSS Transition Management Request did not include candidates");
|
||||
status = WNM_BSS_TM_REJECT_UNSPECIFIED;
|
||||
}
|
||||
wpa_s->wnm_reply = 0;
|
||||
wnm_send_bss_transition_mgmt_resp(
|
||||
wpa_s, wpa_s->wnm_dialog_token, status,
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define BTM_QUERY_MIN_SIZE 4
|
||||
|
||||
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
|
||||
u8 query_reason,
|
||||
const char *btm_candidates,
|
||||
int cand_list)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int ret;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
|
||||
MACSTR " query_reason=%u%s",
|
||||
MAC2STR(wpa_s->current_bss->bssid), query_reason,
|
||||
cand_list ? " candidate list" : "");
|
||||
|
||||
buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
|
||||
wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY);
|
||||
wpabuf_put_u8(buf, 1);
|
||||
wpabuf_put_u8(buf, query_reason);
|
||||
|
||||
if (cand_list)
|
||||
wnm_add_cand_list(wpa_s, &buf);
|
||||
|
||||
if (btm_candidates) {
|
||||
const size_t max_len = 1000;
|
||||
|
||||
ret = wpabuf_resize(&buf, max_len);
|
||||
if (ret < 0) {
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ieee802_11_parse_candidate_list(btm_candidates,
|
||||
wpabuf_put(buf, 0),
|
||||
max_len);
|
||||
if (ret < 0) {
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wpabuf_put(buf, ret);
|
||||
}
|
||||
|
||||
ret = wpa_drv_send_action(wpa_s, 0, 0,
|
||||
wpabuf_head_u8(buf), wpabuf_len(buf), 0);
|
||||
|
||||
wpabuf_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
|
||||
u8 *sender, u8 *payload, size_t len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 act;
|
||||
|
||||
if (len < 2)
|
||||
return;
|
||||
|
||||
pos = payload;
|
||||
act = *pos++;
|
||||
end = payload + len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
|
||||
act, MAC2STR(sender));
|
||||
|
||||
switch (act) {
|
||||
case WNM_BSS_TRANS_MGMT_REQ:
|
||||
ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
|
||||
!(sender[0] & 0x01));
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_ERROR, "WNM: Unknown request");
|
||||
break;
|
||||
}
|
||||
}
|
70
components/wpa_supplicant/src/common/wnm_sta.h
Normal file
70
components/wpa_supplicant/src/common/wnm_sta.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* IEEE 802.11v WNM related functions and structures
|
||||
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WNM_STA_H
|
||||
#define WNM_STA_H
|
||||
|
||||
struct measurement_pilot {
|
||||
u8 measurement_pilot;
|
||||
u8 subelem_len;
|
||||
u8 subelems[255];
|
||||
};
|
||||
|
||||
struct multiple_bssid {
|
||||
u8 max_bssid_indicator;
|
||||
u8 subelem_len;
|
||||
u8 subelems[255];
|
||||
};
|
||||
|
||||
struct neighbor_report {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u32 bssid_info;
|
||||
u8 regulatory_class;
|
||||
u8 channel_number;
|
||||
u8 phy_type;
|
||||
u8 preference; /* valid if preference_present=1 */
|
||||
u16 tsf_offset; /* valid if tsf_present=1 */
|
||||
u16 beacon_int; /* valid if tsf_present=1 */
|
||||
char country[2]; /* valid if country_present=1 */
|
||||
u8 rm_capab[5]; /* valid if rm_capab_present=1 */
|
||||
u16 bearing; /* valid if bearing_present=1 */
|
||||
u16 rel_height; /* valid if bearing_present=1 */
|
||||
u32 distance; /* valid if bearing_present=1 */
|
||||
u64 bss_term_tsf; /* valid if bss_term_present=1 */
|
||||
u16 bss_term_dur; /* valid if bss_term_present=1 */
|
||||
unsigned int preference_present:1;
|
||||
unsigned int tsf_present:1;
|
||||
unsigned int country_present:1;
|
||||
unsigned int rm_capab_present:1;
|
||||
unsigned int bearing_present:1;
|
||||
unsigned int bss_term_present:1;
|
||||
unsigned int acceptable:1;
|
||||
struct measurement_pilot *meas_pilot;
|
||||
struct multiple_bssid *mul_bssid;
|
||||
int freq;
|
||||
};
|
||||
|
||||
|
||||
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
|
||||
u8 action, u16 intval, struct wpabuf *tfs_req);
|
||||
|
||||
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
|
||||
u8 *sender, u8 *payload, size_t len);
|
||||
|
||||
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
|
||||
u8 query_reason,
|
||||
const char *btm_candidates,
|
||||
int cand_list);
|
||||
|
||||
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
|
||||
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
|
||||
void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, char *ssid,
|
||||
int after_new_scan);
|
||||
|
||||
#endif /* WNM_STA_H */
|
110
components/wpa_supplicant/src/common/wpa_supplicant_i.h
Normal file
110
components/wpa_supplicant/src/common/wpa_supplicant_i.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* wpa_supplicant - Internal definitions
|
||||
* Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_SUPPLICANT_I_H
|
||||
#define WPA_SUPPLICANT_I_H
|
||||
|
||||
|
||||
#include "drivers/driver.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
/*
|
||||
* struct rrm_data - Data used for managing RRM features
|
||||
*/
|
||||
struct rrm_data {
|
||||
/* rrm_used - indication regarding the current connection */
|
||||
unsigned int rrm_used:1;
|
||||
|
||||
/*
|
||||
* notify_neighbor_rep - Callback for notifying report requester
|
||||
*/
|
||||
void (*notify_neighbor_rep)(void *ctx, const u8 *neighbor_rep, size_t len);
|
||||
|
||||
/*
|
||||
* neighbor_rep_cb_ctx - Callback context
|
||||
* Received in the callback registration, and sent to the callback
|
||||
* function as a parameter.
|
||||
*/
|
||||
void *neighbor_rep_cb_ctx;
|
||||
|
||||
/* next_neighbor_rep_token - Next request's dialog token */
|
||||
u8 next_neighbor_rep_token;
|
||||
|
||||
/* token - Dialog token of the current radio measurement */
|
||||
u8 token;
|
||||
|
||||
/* destination address of the current radio measurement request */
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
struct beacon_rep_data {
|
||||
u8 token;
|
||||
u8 last_indication;
|
||||
struct wpa_driver_scan_params scan_params;
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
u8 bssid[ETH_ALEN];
|
||||
enum beacon_report_detail report_detail;
|
||||
struct bitfield *eids;
|
||||
};
|
||||
|
||||
enum scan_trigger_reason {
|
||||
REASON_INVALID,
|
||||
REASON_RRM_BEACON_REPORT,
|
||||
REASON_WNM_BSS_TRANS_REQ,
|
||||
};
|
||||
|
||||
struct wpa_supplicant {
|
||||
int disable_btm;
|
||||
/* rrm ie */
|
||||
uint8_t rrm_ie[5];
|
||||
u8 extend_caps[8];
|
||||
|
||||
int scanning;
|
||||
enum scan_trigger_reason scan_reason;
|
||||
u64 scan_start_tsf;
|
||||
u8 tsf_bssid[ETH_ALEN];
|
||||
struct wpa_bss *current_bss;
|
||||
|
||||
struct dl_list bss; /* struct wpa_bss::list */
|
||||
struct dl_list bss_id; /* struct wpa_bss::list_id */
|
||||
size_t num_bss;
|
||||
unsigned int bss_update_idx;
|
||||
unsigned int bss_next_id;
|
||||
|
||||
/*
|
||||
* Pointers to BSS entries in the order they were in the last scan
|
||||
* results.
|
||||
*/
|
||||
struct wpa_bss **last_scan_res;
|
||||
unsigned int last_scan_res_used;
|
||||
unsigned int last_scan_res_size;
|
||||
struct os_reltime last_scan;
|
||||
|
||||
struct os_reltime scan_trigger_time, scan_start_time;
|
||||
|
||||
u8 next_scan_bssid[ETH_ALEN];
|
||||
/* type and subtype of frames for which supplicant has registered */
|
||||
uint32_t type, subtype;
|
||||
u8 next_scan_chan;
|
||||
#ifdef CONFIG_WNM
|
||||
u8 wnm_dialog_token;
|
||||
u8 wnm_reply;
|
||||
u8 wnm_num_neighbor_report;
|
||||
u8 wnm_mode;
|
||||
u16 wnm_dissoc_timer;
|
||||
u8 wnm_bss_termination_duration[12];
|
||||
struct neighbor_report *wnm_neighbor_report_elements;
|
||||
struct os_reltime wnm_cand_valid_until;
|
||||
#endif /* CONFIG_WNM */
|
||||
struct rrm_data rrm;
|
||||
struct beacon_rep_data beacon_rep_data;
|
||||
struct os_reltime beacon_rep_scan;
|
||||
};
|
||||
|
||||
#endif
|
187
components/wpa_supplicant/src/drivers/driver.h
Normal file
187
components/wpa_supplicant/src/drivers/driver.h
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Driver interface definition
|
||||
* Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* This file defines a driver interface used by both %wpa_supplicant and
|
||||
* hostapd. The first part of the file defines data structures used in various
|
||||
* driver operations. This is followed by the struct wpa_driver_ops that each
|
||||
* driver wrapper will beed to define with callback functions for requesting
|
||||
* driver operations. After this, there are definitions for driver event
|
||||
* reporting with wpa_supplicant_event() and some convenience helper functions
|
||||
* that can be used to report events.
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
#define WPA_SUPPLICANT_DRIVER_VERSION 4
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "utils/list.h"
|
||||
struct wpa_bss;
|
||||
struct wpa_supplicant;
|
||||
/**
|
||||
* struct wpa_scan_res - Scan result for an BSS/IBSS
|
||||
* @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
|
||||
* @bssid: BSSID
|
||||
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
|
||||
* @beacon_int: beacon interval in TUs (host byte order)
|
||||
* @caps: capability information field in host byte order
|
||||
* @qual: signal quality
|
||||
* @noise: noise level
|
||||
* @level: signal level
|
||||
* @tsf: Timestamp
|
||||
* @age: Age of the information in milliseconds (i.e., how many milliseconds
|
||||
* ago the last Beacon or Probe Response frame was received)
|
||||
* @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
|
||||
* @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
|
||||
* of TSF of the BSS specified by %tsf_bssid.
|
||||
* @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
|
||||
* @ie_len: length of the following IE field in octets
|
||||
* @beacon_ie_len: length of the following Beacon IE field in octets
|
||||
*
|
||||
* This structure is used as a generic format for scan results from the
|
||||
* driver. Each driver interface implementation is responsible for converting
|
||||
* the driver or OS specific scan results into this format.
|
||||
*
|
||||
* If the driver does not support reporting all IEs, the IE data structure is
|
||||
* constructed of the IEs that are available. This field will also need to
|
||||
* include SSID in IE format. All drivers are encouraged to be extended to
|
||||
* report all IEs to make it easier to support future additions.
|
||||
*
|
||||
* This structure data is followed by ie_len octets of IEs from Probe Response
|
||||
* frame (or if the driver does not indicate source of IEs, these may also be
|
||||
* from Beacon frame). After the first set of IEs, another set of IEs may follow
|
||||
* (with beacon_ie_len octets of data) if the driver provides both IE sets.
|
||||
*/
|
||||
struct wpa_scan_res {
|
||||
unsigned int flags;
|
||||
u8 bssid[ETH_ALEN];
|
||||
int chan;
|
||||
u16 beacon_int;
|
||||
u16 caps;
|
||||
int noise;
|
||||
int level;
|
||||
u64 tsf;
|
||||
unsigned int age;
|
||||
u64 parent_tsf;
|
||||
u8 tsf_bssid[ETH_ALEN];
|
||||
size_t ie_len;
|
||||
size_t beacon_ie_len;
|
||||
/* Followed by ie_len + beacon_ie_len octets of IE data */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wpa_scan_results - Scan results
|
||||
* @res: Array of pointers to allocated variable length scan result entries
|
||||
* @num: Number of entries in the scan result array
|
||||
* @fetch_time: Time when the results were fetched from the driver
|
||||
*/
|
||||
struct wpa_scan_results {
|
||||
struct wpa_scan_res **res;
|
||||
size_t num;
|
||||
struct os_reltime fetch_time;
|
||||
};
|
||||
|
||||
#define WPAS_MAX_SCAN_SSIDS 1
|
||||
|
||||
/**
|
||||
* struct wpa_driver_scan_ssid - SSIDs to scan for
|
||||
* @ssid - specific SSID to scan for (ProbeReq)
|
||||
* %NULL or zero-length SSID is used to indicate active scan
|
||||
* with wildcard SSID.
|
||||
* @ssid_len - Length of the SSID in octets
|
||||
*/
|
||||
struct wpa_driver_scan_ssid {
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wpa_driver_scan_params - Scan parameters
|
||||
* Data for struct wpa_driver_ops::scan2().
|
||||
*/
|
||||
struct wpa_driver_scan_params {
|
||||
/**
|
||||
* ssids - SSIDs to scan for
|
||||
*/
|
||||
struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
|
||||
|
||||
/**
|
||||
* num_ssids - Number of entries in ssids array
|
||||
* Zero indicates a request for a passive scan.
|
||||
*/
|
||||
size_t num_ssids;
|
||||
|
||||
/**
|
||||
* freqs - Array of frequencies to scan or %NULL for all frequencies
|
||||
*
|
||||
* The frequency is set in MHz. The array is zero-terminated.
|
||||
*/
|
||||
int channel;
|
||||
|
||||
/**
|
||||
* bssid - Specific BSSID to scan for
|
||||
*
|
||||
* This optional parameter can be used to replace the default wildcard
|
||||
* BSSID with a specific BSSID to scan for if results are needed from
|
||||
* only a single BSS.
|
||||
*/
|
||||
const u8 *bssid;
|
||||
|
||||
/**
|
||||
* duration - Dwell time on each channel
|
||||
*
|
||||
* This optional parameter can be used to set the dwell time on each
|
||||
* channel. In TUs.
|
||||
*/
|
||||
u16 duration;
|
||||
|
||||
unsigned int duration_mandatory;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scan_info - Optional data for EVENT_SCAN_RESULTS events
|
||||
* @aborted: Whether the scan was aborted
|
||||
* @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
|
||||
* @num_freqs: Number of entries in freqs array
|
||||
* @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
|
||||
* SSID)
|
||||
* @num_ssids: Number of entries in ssids array
|
||||
* @external_scan: Whether the scan info is for an external scan
|
||||
* @nl_scan_event: 1 if the source of this scan event is a normal scan,
|
||||
* 0 if the source of the scan event is a vendor scan
|
||||
* @scan_start_tsf: Time when the scan started in terms of TSF of the
|
||||
* BSS that the interface that requested the scan is connected to
|
||||
* (if available).
|
||||
* @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
|
||||
* is set.
|
||||
*/
|
||||
struct scan_info {
|
||||
int aborted;
|
||||
const int *freqs;
|
||||
size_t num_freqs;
|
||||
struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
|
||||
size_t num_ssids;
|
||||
int external_scan;
|
||||
int nl_scan_event;
|
||||
u64 scan_start_tsf;
|
||||
u8 scan_start_tsf_bssid[ETH_ALEN];
|
||||
} scan_info;
|
||||
|
||||
|
||||
/* driver_common.c */
|
||||
void wpa_scan_results_free(struct wpa_scan_results *res);
|
||||
|
||||
int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
|
||||
unsigned int chan, unsigned int wait,
|
||||
const u8 *data, size_t data_len, int no_cck);
|
||||
|
||||
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, char *ssid);
|
||||
#endif /* DRIVER_H */
|
403
components/wpa_supplicant/src/esp_supplicant/esp_common.c
Normal file
403
components/wpa_supplicant/src/esp_supplicant/esp_common.c
Normal file
@ -0,0 +1,403 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "esp_wifi_driver.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "common/bss.h"
|
||||
#include "common/rrm.h"
|
||||
#include "common/wnm_sta.h"
|
||||
#include "common/wpa_supplicant_i.h"
|
||||
#include "esp_supplicant/esp_scan_i.h"
|
||||
#include "esp_supplicant/esp_common_i.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "esp_rrm.h"
|
||||
#include "esp_wnm.h"
|
||||
|
||||
struct wpa_supplicant g_wpa_supp;
|
||||
|
||||
static void *s_supplicant_task_hdl = NULL;
|
||||
static void *s_supplicant_evt_queue = NULL;
|
||||
static void *s_supplicant_api_lock = NULL;
|
||||
|
||||
static int esp_handle_action_frm(u8 *frame, size_t len,
|
||||
u8 *sender, u32 rssi, u8 channel)
|
||||
{
|
||||
struct ieee_mgmt_frame *frm = os_malloc(sizeof(struct ieee_mgmt_frame) + len);
|
||||
|
||||
if (!frm) {
|
||||
wpa_printf(MSG_ERROR, "memory allocation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(frm->sender, sender, ETH_ALEN);
|
||||
frm->len = len;
|
||||
frm->channel = channel;
|
||||
frm->rssi = rssi;
|
||||
|
||||
os_memcpy(frm->payload, frame, len);
|
||||
if (esp_supplicant_post_evt(SIG_SUPPLICANT_RX_ACTION, (u32)frm) != 0) {
|
||||
os_free(frm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esp_rx_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
|
||||
u8 *payload, size_t len, u32 rssi)
|
||||
{
|
||||
if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
|
||||
/* neighbor report parsing */
|
||||
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, len - 1);
|
||||
} else if (payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
|
||||
/* Beacon measurement */
|
||||
wpas_rrm_handle_radio_measurement_request(wpa_s, NULL,
|
||||
sender, payload + 1, len - 1);
|
||||
} else if (payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
|
||||
/* Link measurement */
|
||||
wpas_rrm_handle_link_measurement_request(wpa_s, NULL,
|
||||
payload + 1, len - 1, rssi);
|
||||
}
|
||||
}
|
||||
|
||||
static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi)
|
||||
{
|
||||
u8 category;
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
int ret = esp_wifi_get_assoc_bssid_internal(bssid);
|
||||
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_INFO, "STA not associated");
|
||||
return -1;
|
||||
}
|
||||
|
||||
category = *payload++;
|
||||
len--;
|
||||
if (category == WLAN_ACTION_WNM) {
|
||||
ieee802_11_rx_wnm_action(wpa_s, sender, payload, len);
|
||||
} else if (category == WLAN_ACTION_RADIO_MEASUREMENT) {
|
||||
esp_rx_rrm_frame(wpa_s, sender, payload, len, rssi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esp_btm_rrm_task(void *pvParameters)
|
||||
{
|
||||
supplicant_event_t *evt;
|
||||
bool task_del = false;
|
||||
|
||||
while(1) {
|
||||
if (xQueueReceive(s_supplicant_evt_queue, &evt, portMAX_DELAY) != pdTRUE)
|
||||
continue;
|
||||
|
||||
/* event validation failed */
|
||||
if (evt->id >= SIG_SUPPLICANT_MAX) {
|
||||
os_free(evt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get lock */
|
||||
SUPPLICANT_API_LOCK();
|
||||
|
||||
switch (evt->id) {
|
||||
case SIG_SUPPLICANT_RX_ACTION:
|
||||
{
|
||||
struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data;
|
||||
esp_mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi);
|
||||
os_free(frm);
|
||||
break;
|
||||
}
|
||||
|
||||
case SIG_SUPPLICANT_SCAN_DONE:
|
||||
esp_supplicant_handle_scan_done_evt();
|
||||
break;
|
||||
case SIG_SUPPLICANT_DEL_TASK:
|
||||
task_del = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
os_free(evt);
|
||||
SUPPLICANT_API_UNLOCK();
|
||||
|
||||
if (task_del)
|
||||
break;
|
||||
}
|
||||
|
||||
vQueueDelete(s_supplicant_evt_queue);
|
||||
s_supplicant_evt_queue = NULL;
|
||||
|
||||
if (s_supplicant_api_lock) {
|
||||
vSemaphoreDelete(s_supplicant_api_lock);
|
||||
s_supplicant_api_lock = NULL;
|
||||
}
|
||||
|
||||
/* At this point, we completed */
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wifi_config_t *config;
|
||||
|
||||
/* Reset only if btm is enabled */
|
||||
if (esp_wifi_is_btm_enabled_internal(ESP_IF_WIFI_STA) == false)
|
||||
return;
|
||||
|
||||
config = os_zalloc(sizeof(wifi_config_t));
|
||||
|
||||
if (!config) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_wifi_get_config(ESP_IF_WIFI_STA, config);
|
||||
config->sta.bssid_set = 0;
|
||||
esp_wifi_set_config(ESP_IF_WIFI_STA, config);
|
||||
os_free(config);
|
||||
wpa_printf(MSG_DEBUG, "cleared bssid flag");
|
||||
}
|
||||
|
||||
static void esp_register_action_frame(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_s->type &= ~WLAN_FC_STYPE_ACTION;
|
||||
/* subtype is defined only for action frame */
|
||||
wpa_s->subtype = 0;
|
||||
|
||||
/* current supported features in supplicant: rrm and btm */
|
||||
if (esp_wifi_is_rm_enabled_internal(ESP_IF_WIFI_STA))
|
||||
wpa_s->subtype = 1 << WLAN_ACTION_RADIO_MEASUREMENT;
|
||||
if (esp_wifi_is_btm_enabled_internal(ESP_IF_WIFI_STA))
|
||||
wpa_s->subtype |= 1 << WLAN_ACTION_WNM;
|
||||
|
||||
if (wpa_s->subtype)
|
||||
wpa_s->type |= 1 << WLAN_FC_STYPE_ACTION;
|
||||
|
||||
esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
|
||||
}
|
||||
|
||||
static void esp_supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 *ie;
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
int ret = esp_wifi_get_assoc_bssid_internal(bssid);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_ERROR, "Not able to get connected bssid");
|
||||
return;
|
||||
}
|
||||
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
|
||||
if (!bss) {
|
||||
wpa_printf(MSG_INFO, "connected bss entry not present in scan cache");
|
||||
return;
|
||||
}
|
||||
wpa_s->current_bss = bss;
|
||||
ie = (u8 *)bss;
|
||||
ie += sizeof(struct wpa_bss);
|
||||
ieee802_11_parse_elems(wpa_s, ie, bss->ie_len);
|
||||
wpa_bss_flush(wpa_s);
|
||||
/* Register for action frames */
|
||||
esp_register_action_frame(wpa_s);
|
||||
/* clear set bssid flag */
|
||||
esp_clear_bssid_flag(wpa_s);
|
||||
}
|
||||
|
||||
static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
wpas_rrm_reset(wpa_s);
|
||||
if (wpa_s->current_bss) {
|
||||
wpa_s->current_bss = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
|
||||
s_supplicant_evt_queue = xQueueCreate(3, sizeof(supplicant_event_t));
|
||||
xTaskCreate(esp_btm_rrm_task, "btm_rrm_t", SUPPLICANT_TASK_STACK_SIZE, NULL, 2, s_supplicant_task_hdl);
|
||||
|
||||
s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex();
|
||||
if (!s_supplicant_api_lock) {
|
||||
wpa_printf(MSG_ERROR, "esp_supplicant_common_init: failed to create Supplicant API lock");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_scan_init(wpa_s);
|
||||
wpas_rrm_reset(wpa_s);
|
||||
wpas_clear_beacon_rep_data(wpa_s);
|
||||
|
||||
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
|
||||
&esp_supplicant_sta_conn_handler, NULL);
|
||||
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
|
||||
&esp_supplicant_sta_disconn_handler, NULL);
|
||||
|
||||
wpa_s->type = 0;
|
||||
wpa_s->subtype = 0;
|
||||
wpa_cb->wpa_sta_rx_mgmt = esp_ieee80211_handle_rx_frm;
|
||||
}
|
||||
|
||||
int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
|
||||
void *cb_ctx)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
struct wpa_ssid_value wpa_ssid = {0};
|
||||
struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
|
||||
os_memcpy(wpa_ssid.ssid, ssid->ssid, ssid->len);
|
||||
wpa_ssid.ssid_len = ssid->len;
|
||||
wpas_rrm_send_neighbor_rep_request(wpa_s, &wpa_ssid, 0, 0, cb, cb_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
|
||||
const char *btm_candidates,
|
||||
int cand_list)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, btm_candidates, cand_list);
|
||||
}
|
||||
|
||||
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, char *ssid)
|
||||
{
|
||||
wifi_config_t *config = os_zalloc(sizeof(wifi_config_t));
|
||||
|
||||
if (!config) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_wifi_get_config(ESP_IF_WIFI_STA, config);
|
||||
/* We only support roaming in same ESS, therefore only bssid setting is needed */
|
||||
os_memcpy(config->sta.bssid, bss->bssid, ETH_ALEN);
|
||||
config->sta.bssid_set = 1;
|
||||
esp_wifi_internal_issue_disconnect(WIFI_REASON_ROAMING);
|
||||
esp_wifi_set_config(ESP_IF_WIFI_STA, config);
|
||||
os_free(config);
|
||||
esp_wifi_connect();
|
||||
}
|
||||
|
||||
void esp_set_rm_enabled_ie(void)
|
||||
{
|
||||
uint8_t rmm_ie[5] = {0};
|
||||
uint8_t rrm_ie_len = 5;
|
||||
uint8_t *pos = rmm_ie;
|
||||
|
||||
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
|
||||
|
||||
*pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
|
||||
#ifdef SCAN_CACHE_SUPPORTED
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_TABLE |
|
||||
#endif
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE;
|
||||
|
||||
/* set rm enabled IE if enabled in driver */
|
||||
if (esp_wifi_is_rm_enabled_internal(ESP_IF_WIFI_STA)) {
|
||||
esp_wifi_set_appie_internal(WIFI_APPIE_RM_ENABLED_CAPS, rmm_ie, rrm_ie_len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_get_tx_power(uint8_t *tx_power)
|
||||
{
|
||||
#define DEFAULT_MAX_TX_POWER 19 /* max tx power is 19.5 dbm */
|
||||
s8 power;
|
||||
/* esp sends management frames at max tx power configured */
|
||||
int ret = esp_wifi_get_max_tx_power(&power);
|
||||
if (ret != 0) {
|
||||
wpa_printf(MSG_ERROR, "failed to get tx power");
|
||||
*tx_power = DEFAULT_MAX_TX_POWER;
|
||||
return;
|
||||
}
|
||||
*tx_power = power/4;
|
||||
#undef DEFAULT_MAX_TX_POWER
|
||||
}
|
||||
|
||||
int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
|
||||
unsigned int channel,
|
||||
unsigned int wait,
|
||||
const u8 *data, size_t data_len,
|
||||
int no_cck)
|
||||
{
|
||||
int ret = 0;
|
||||
wifi_mgmt_frm_req_t *req = os_zalloc(sizeof(*req) + data_len);;
|
||||
if (!req)
|
||||
return -1;
|
||||
|
||||
if (!wpa_s->current_bss) {
|
||||
wpa_printf(MSG_ERROR, "STA not associated, return");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
req->ifx = ESP_IF_WIFI_STA;
|
||||
req->subtype = WLAN_FC_STYPE_ACTION;
|
||||
req->data_len = data_len;
|
||||
os_memcpy(req->data, data, req->data_len);
|
||||
|
||||
if (esp_wifi_send_mgmt_frm_internal(req) != 0) {
|
||||
wpa_printf(MSG_ERROR, "action frame sending failed");
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
wpa_printf(MSG_INFO, "action frame sent");
|
||||
|
||||
cleanup:
|
||||
os_free(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data)
|
||||
{
|
||||
supplicant_event_t *evt = os_zalloc(sizeof(supplicant_event_t));
|
||||
if (evt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
evt->id = evt_id;
|
||||
evt->data = data;
|
||||
|
||||
SUPPLICANT_API_LOCK();
|
||||
if (xQueueSend(s_supplicant_evt_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) {
|
||||
SUPPLICANT_API_UNLOCK();
|
||||
os_free(evt);
|
||||
return -1;
|
||||
}
|
||||
SUPPLICANT_API_UNLOCK();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
u32 rssi, u8 channel, u64 current_tsf)
|
||||
{
|
||||
if (type == WLAN_FC_STYPE_BEACON || type == WLAN_FC_STYPE_PROBE_RESP) {
|
||||
return esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf);
|
||||
} else if (type == WLAN_FC_STYPE_ACTION) {
|
||||
return esp_handle_action_frm(frame, len, sender, rssi, channel);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
80
components/wpa_supplicant/src/esp_supplicant/esp_common_i.h
Normal file
80
components/wpa_supplicant/src/esp_supplicant/esp_common_i.h
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ESP_COMMON_I_H
|
||||
#define ESP_COMMON_I_H
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
struct wpa_funcs;
|
||||
|
||||
#ifdef ROAMING_SUPPORT
|
||||
struct ieee_mgmt_frame {
|
||||
u8 sender[ETH_ALEN];
|
||||
u8 channel;
|
||||
u32 rssi;
|
||||
size_t len;
|
||||
u8 payload[0];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint32_t data;
|
||||
} supplicant_event_t;
|
||||
|
||||
#define SUPPLICANT_API_LOCK() xSemaphoreTakeRecursive(s_supplicant_api_lock, portMAX_DELAY)
|
||||
#define SUPPLICANT_API_UNLOCK() xSemaphoreGiveRecursive(s_supplicant_api_lock)
|
||||
|
||||
#define SUPPLICANT_TASK_STACK_SIZE (6144 + TASK_STACK_SIZE_ADD)
|
||||
enum SIG_SUPPLICANT {
|
||||
SIG_SUPPLICANT_RX_ACTION,
|
||||
SIG_SUPPLICANT_SCAN_DONE,
|
||||
SIG_SUPPLICANT_DEL_TASK,
|
||||
SIG_SUPPLICANT_MAX,
|
||||
};
|
||||
|
||||
int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data);
|
||||
int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
u32 rssi, u8 channel, u64 current_tsf);
|
||||
void esp_set_rm_enabled_ie(void);
|
||||
void esp_get_tx_power(uint8_t *tx_power);
|
||||
void esp_supplicant_common_init(struct wpa_funcs *wpa_cb);
|
||||
#else
|
||||
|
||||
#include "esp_rrm.h"
|
||||
#include "esp_wnm.h"
|
||||
|
||||
static inline void esp_set_rm_enabled_ie(void) {}
|
||||
static inline int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
u32 rssi, u8 channel, u64 current_tsf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
|
||||
void *cb_ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
|
||||
const char *btm_candidates,
|
||||
int cand_list)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
271
components/wpa_supplicant/src/esp_supplicant/esp_scan.c
Normal file
271
components/wpa_supplicant/src/esp_supplicant/esp_scan.c
Normal file
@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_supplicant_i.h"
|
||||
#include "utils/wpa_debug.h"
|
||||
#include "esp_wifi_driver.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "common/scan.h"
|
||||
#include "common/bss.h"
|
||||
#include "common/rrm.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "esp_supplicant/esp_common_i.h"
|
||||
#include "common/wnm_sta.h"
|
||||
|
||||
extern struct wpa_supplicant g_wpa_supp;
|
||||
|
||||
static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
if (!wpa_s->scanning) {
|
||||
/* update last scan time */
|
||||
wpa_s->scan_start_tsf = esp_wifi_get_tsf_time(ESP_IF_WIFI_STA);
|
||||
wpa_printf(MSG_DEBUG, "scan not triggered by supplicant, ignore");
|
||||
return;
|
||||
}
|
||||
wpa_s->type &= ~(1 << WLAN_FC_STYPE_BEACON) & ~(1 << WLAN_FC_STYPE_PROBE_RESP);
|
||||
esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
|
||||
esp_supplicant_post_evt(SIG_SUPPLICANT_SCAN_DONE, 0);
|
||||
|
||||
}
|
||||
|
||||
static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss);
|
||||
|
||||
if (wpa_s->wnm_neighbor_report_elements) {
|
||||
wnm_scan_process(wpa_s, 1);
|
||||
} else if (wpa_s->wnm_dissoc_timer) {
|
||||
if (wpa_s->num_bss == 1) {
|
||||
wpa_printf(MSG_INFO, "not able to find another candidate, do nothing");
|
||||
return;
|
||||
}
|
||||
/* this is a already matched bss */
|
||||
if (bss) {
|
||||
wnm_bss_tm_connect(wpa_s, bss, NULL, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_supp_scan_done_cleanup(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
uint16_t number = 1;
|
||||
wifi_ap_record_t ap_records;
|
||||
|
||||
wpa_s->scanning = 0;
|
||||
wpa_s->scan_reason = 0;
|
||||
/* clean scan list from net80211 */
|
||||
esp_wifi_scan_get_ap_records(&number, &ap_records);
|
||||
}
|
||||
|
||||
void esp_supplicant_handle_scan_done_evt(void)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
|
||||
wpa_printf(MSG_INFO, "scan done received");
|
||||
/* Check which module started this, call the respective function */
|
||||
if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) {
|
||||
wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf);
|
||||
} else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) {
|
||||
esp_supp_handle_wnm_scan_done(wpa_s);
|
||||
}
|
||||
esp_supp_scan_done_cleanup(wpa_s);
|
||||
wpa_bss_update_end(wpa_s);
|
||||
#ifndef SCAN_CACHE_SUPPORTED
|
||||
wpa_bss_flush(wpa_s);
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_scan_init(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_s->scanning = 0;
|
||||
wpa_bss_init(wpa_s);
|
||||
wpa_s->last_scan_res = NULL;
|
||||
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE,
|
||||
&esp_scan_done_event_handler, NULL);
|
||||
}
|
||||
|
||||
void esp_scan_deinit(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_bss_deinit(wpa_s);
|
||||
}
|
||||
|
||||
int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
u32 rssi, u8 channel, u64 current_tsf)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
struct os_reltime now;
|
||||
struct wpa_scan_res *res;
|
||||
u8 *ptr;
|
||||
|
||||
if (len < 12) {
|
||||
wpa_printf(MSG_ERROR, "beacon/probe is having short len=%d\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_zalloc(sizeof(struct wpa_scan_res) + len - 12);
|
||||
if (!res) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = (u8 *)res;
|
||||
os_get_time(&now);
|
||||
os_memcpy(res->bssid, sender, ETH_ALEN);
|
||||
res->tsf = WPA_GET_LE64(frame);
|
||||
frame += 8;
|
||||
len -= 8;
|
||||
|
||||
if ((wpa_s->scan_start_tsf == 0) &&
|
||||
wpa_s->current_bss &&
|
||||
(os_memcmp(wpa_s->current_bss, sender, ETH_ALEN) == 0)) {
|
||||
wpa_s->scan_start_tsf = res->tsf;
|
||||
os_memcpy(wpa_s->tsf_bssid, sender, ETH_ALEN);
|
||||
}
|
||||
res->beacon_int = WPA_GET_LE16(frame);
|
||||
|
||||
frame += 2;
|
||||
len -= 2;
|
||||
res->caps = WPA_GET_LE16(frame);
|
||||
frame += 2;
|
||||
len -= 2;
|
||||
|
||||
res->chan = channel;
|
||||
res->noise = 0;
|
||||
res->level = rssi;
|
||||
os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN);
|
||||
res->parent_tsf = current_tsf - wpa_s->scan_start_tsf;
|
||||
if (type == WLAN_FC_STYPE_PROBE_RESP)
|
||||
res->ie_len = len;
|
||||
else if (type == WLAN_FC_STYPE_BEACON)
|
||||
res->beacon_ie_len = len;
|
||||
|
||||
ptr += sizeof(struct wpa_scan_res);
|
||||
|
||||
/* update rest of the frame */
|
||||
os_memcpy(ptr, frame, len);
|
||||
wpa_bss_update_scan_res(wpa_s, res, &now);
|
||||
os_free(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esp_issue_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *scan_params)
|
||||
{
|
||||
wifi_scan_config_t *params = NULL;
|
||||
int ret = 0;
|
||||
u64 scan_start_tsf = esp_wifi_get_tsf_time(ESP_IF_WIFI_STA);
|
||||
|
||||
/* TODO: Directly try to connect if scan results are recent */
|
||||
if ((scan_start_tsf - wpa_s->scan_start_tsf) > 100000) {
|
||||
wpa_printf(MSG_DEBUG, "flushing old scan cache %llu",
|
||||
(scan_start_tsf - wpa_s->scan_start_tsf));
|
||||
wpa_bss_flush(wpa_s);
|
||||
}
|
||||
|
||||
esp_wifi_get_macaddr_internal(ESP_IF_WIFI_STA, wpa_s->tsf_bssid);
|
||||
|
||||
if (scan_params) {
|
||||
params = os_zalloc(sizeof(wifi_scan_config_t));
|
||||
if (!params) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
if (scan_params->num_ssids) {
|
||||
params->ssid = os_zalloc(scan_params->ssids[0].ssid_len + 1);
|
||||
if (!params->ssid) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len);
|
||||
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
|
||||
} else
|
||||
params->scan_type = WIFI_SCAN_TYPE_PASSIVE;
|
||||
|
||||
if (scan_params->bssid) {
|
||||
params->bssid = os_zalloc(ETH_ALEN);
|
||||
if (!params->bssid) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(params->bssid, scan_params->bssid, ETH_ALEN);
|
||||
}
|
||||
if (scan_params->channel) {
|
||||
params->channel = scan_params->channel;
|
||||
}
|
||||
|
||||
if (scan_params->duration) {
|
||||
params->scan_time.passive = scan_params->duration;
|
||||
params->scan_time.active.min = scan_params->duration;
|
||||
params->scan_time.active.max = scan_params->duration;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_s->scan_start_tsf = scan_start_tsf;
|
||||
/* Register frames to come to supplicant when we park on channel */
|
||||
wpa_s->type |= (1 << WLAN_FC_STYPE_BEACON) | (1 << WLAN_FC_STYPE_PROBE_RESP);
|
||||
esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
|
||||
|
||||
/* issue scan */
|
||||
if (esp_wifi_scan_start(params, false) < 0) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
wpa_s->scanning = 1;
|
||||
wpa_bss_update_start(wpa_s);
|
||||
wpa_printf(MSG_INFO, "scan issued at time=%llu", wpa_s->scan_start_tsf);
|
||||
|
||||
cleanup:
|
||||
if (params->ssid)
|
||||
os_free(params->ssid);
|
||||
if (params->bssid)
|
||||
os_free(params->bssid);
|
||||
os_free(params);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_supplicant_trigger_scan - Request driver to start a scan
|
||||
* @wpa_s: Pointer to wpa_supplicant data
|
||||
* @params: Scan parameters
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *params)
|
||||
{
|
||||
return esp_issue_scan(wpa_s, params);
|
||||
}
|
||||
|
||||
void wpa_scan_results_free(struct wpa_scan_results *res)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (res == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < res->num; i++)
|
||||
os_free(res->res[i]);
|
||||
os_free(res->res);
|
||||
os_free(res);
|
||||
}
|
25
components/wpa_supplicant/src/esp_supplicant/esp_scan_i.h
Normal file
25
components/wpa_supplicant/src/esp_supplicant/esp_scan_i.h
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ESP_SCAN_I_H
|
||||
#define ESP_SCAN_I_H
|
||||
void esp_scan_init(struct wpa_supplicant *wpa_s);
|
||||
void esp_scan_deinit(struct wpa_supplicant *wpa_s);
|
||||
int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
u32 rssi, u8 channel, u64 current_tsf);
|
||||
|
||||
void esp_supplicant_handle_scan_done_evt(void);
|
||||
#endif
|
@ -55,6 +55,12 @@ typedef enum {
|
||||
WIFI_APPIE_MAX,
|
||||
} wifi_appie_t;
|
||||
|
||||
/* wifi_appie_t is in rom code and can't be changed anymore, use wifi_appie_ram_t for new app IEs */
|
||||
typedef enum {
|
||||
WIFI_APPIE_RM_ENABLED_CAPS = WIFI_APPIE_MAX,
|
||||
WIFI_APPIE_RAM_MAX,
|
||||
} wifi_appie_ram_t;
|
||||
|
||||
enum {
|
||||
NONE_AUTH = 0x01,
|
||||
WPA_AUTH_UNSPEC = 0x02,
|
||||
@ -126,6 +132,7 @@ struct wpa_funcs {
|
||||
int (*wpa_michael_mic_failure)(u16 is_unicast);
|
||||
uint8_t *(*wpa3_build_sae_msg)(uint8_t *bssid, uint32_t type, size_t *len);
|
||||
int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status);
|
||||
int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf);
|
||||
};
|
||||
|
||||
struct wpa2_funcs {
|
||||
@ -176,6 +183,13 @@ typedef struct {
|
||||
uint8_t igtk[WPA_IGTK_LEN];
|
||||
} wifi_wpa_igtk_t;
|
||||
|
||||
typedef struct {
|
||||
wifi_interface_t ifx;
|
||||
uint8_t subtype;
|
||||
uint32_t data_len;
|
||||
uint8_t data[0];
|
||||
} wifi_mgmt_frm_req_t;
|
||||
|
||||
uint8_t *esp_wifi_ap_get_prof_pmk_internal(void);
|
||||
struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void);
|
||||
uint8_t esp_wifi_ap_get_prof_authmode_internal(void);
|
||||
@ -237,5 +251,9 @@ wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void);
|
||||
int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk);
|
||||
esp_err_t esp_wifi_internal_issue_disconnect(uint8_t reason_code);
|
||||
bool esp_wifi_skip_supp_pmkcaching(void);
|
||||
bool esp_wifi_is_rm_enabled_internal(uint8_t if_index);
|
||||
bool esp_wifi_is_btm_enabled_internal(uint8_t if_index);
|
||||
esp_err_t esp_wifi_register_mgmt_frame_internal(uint32_t type, uint32_t subtype);
|
||||
esp_err_t esp_wifi_send_mgmt_frm_internal(const wifi_mgmt_frm_req_t *req);
|
||||
|
||||
#endif /* _ESP_WIFI_DRIVER_H_ */
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "esp_private/wifi.h"
|
||||
#include "esp_wpa3_i.h"
|
||||
#include "esp_wpa2.h"
|
||||
#include "esp_common_i.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, int key_entry_valid)
|
||||
@ -103,6 +104,7 @@ void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len)
|
||||
} else {
|
||||
esp_wifi_set_appie_internal(WIFI_APPIE_RSN, assoc_buf, assoc_wpa_ie_len, 1);
|
||||
}
|
||||
esp_set_rm_enabled_ie();
|
||||
}
|
||||
|
||||
void wpa_neg_complete(void)
|
||||
@ -156,6 +158,7 @@ bool wpa_deattach(void)
|
||||
|
||||
void wpa_sta_connect(uint8_t *bssid)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
wpa_config_profile();
|
||||
ret = wpa_config_bss(bssid);
|
||||
@ -200,6 +203,13 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ROAMING_SUPPORT
|
||||
static inline void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
|
||||
{
|
||||
wpa_cb->wpa_sta_rx_mgmt = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int esp_supplicant_init(void)
|
||||
{
|
||||
struct wpa_funcs *wpa_cb;
|
||||
@ -228,6 +238,7 @@ int esp_supplicant_init(void)
|
||||
wpa_cb->wpa_config_bss = NULL;//wpa_config_bss;
|
||||
wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure;
|
||||
esp_wifi_register_wpa3_cb(wpa_cb);
|
||||
esp_supplicant_common_init(wpa_cb);
|
||||
|
||||
esp_wifi_register_wpa_cb_internal(wpa_cb);
|
||||
|
||||
|
89
components/wpa_supplicant/src/utils/bitfield.c
Normal file
89
components/wpa_supplicant/src/utils/bitfield.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Bitfield
|
||||
* Copyright (c) 2013, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "bitfield.h"
|
||||
|
||||
|
||||
struct bitfield {
|
||||
u8 *bits;
|
||||
size_t max_bits;
|
||||
};
|
||||
|
||||
|
||||
struct bitfield * bitfield_alloc(size_t max_bits)
|
||||
{
|
||||
struct bitfield *bf;
|
||||
|
||||
bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
|
||||
if (bf == NULL)
|
||||
return NULL;
|
||||
bf->bits = (u8 *) (bf + 1);
|
||||
bf->max_bits = max_bits;
|
||||
return bf;
|
||||
}
|
||||
|
||||
|
||||
void bitfield_free(struct bitfield *bf)
|
||||
{
|
||||
os_free(bf);
|
||||
}
|
||||
|
||||
|
||||
void bitfield_set(struct bitfield *bf, size_t bit)
|
||||
{
|
||||
if (bit >= bf->max_bits)
|
||||
return;
|
||||
bf->bits[bit / 8] |= BIT(bit % 8);
|
||||
}
|
||||
|
||||
|
||||
void bitfield_clear(struct bitfield *bf, size_t bit)
|
||||
{
|
||||
if (bit >= bf->max_bits)
|
||||
return;
|
||||
bf->bits[bit / 8] &= ~BIT(bit % 8);
|
||||
}
|
||||
|
||||
|
||||
int bitfield_is_set(struct bitfield *bf, size_t bit)
|
||||
{
|
||||
if (bit >= bf->max_bits)
|
||||
return 0;
|
||||
return !!(bf->bits[bit / 8] & BIT(bit % 8));
|
||||
}
|
||||
|
||||
|
||||
static int first_zero(u8 val)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!(val & 0x01))
|
||||
return i;
|
||||
val >>= 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int bitfield_get_first_zero(struct bitfield *bf)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < (bf->max_bits + 7) / 8; i++) {
|
||||
if (bf->bits[i] != 0xff)
|
||||
break;
|
||||
}
|
||||
if (i == (bf->max_bits + 7) / 8)
|
||||
return -1;
|
||||
i = i * 8 + first_zero(bf->bits[i]);
|
||||
if (i >= bf->max_bits)
|
||||
return -1;
|
||||
return i;
|
||||
}
|
21
components/wpa_supplicant/src/utils/bitfield.h
Normal file
21
components/wpa_supplicant/src/utils/bitfield.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Bitfield
|
||||
* Copyright (c) 2013, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef BITFIELD_H
|
||||
#define BITFIELD_H
|
||||
|
||||
struct bitfield;
|
||||
|
||||
struct bitfield * bitfield_alloc(size_t max_bits);
|
||||
void bitfield_free(struct bitfield *bf);
|
||||
void bitfield_set(struct bitfield *bf, size_t bit);
|
||||
void bitfield_clear(struct bitfield *bf, size_t bit);
|
||||
int bitfield_is_set(struct bitfield *bf, size_t bit);
|
||||
int bitfield_get_first_zero(struct bitfield *bf);
|
||||
|
||||
#endif /* BITFIELD_H */
|
@ -491,3 +491,59 @@ int hwaddr_aton2(const char *txt, u8 *addr)
|
||||
|
||||
return pos - txt;
|
||||
}
|
||||
|
||||
static inline int os_reltime_expired(struct os_time *now,
|
||||
struct os_time *ts,
|
||||
os_time_t timeout_secs)
|
||||
{
|
||||
struct os_time age;
|
||||
|
||||
os_time_sub(now, ts, &age);
|
||||
return (age.sec > timeout_secs) ||
|
||||
(age.sec == timeout_secs && age.usec > 0);
|
||||
}
|
||||
|
||||
int os_time_expired(struct os_time *now,
|
||||
struct os_time *ts,
|
||||
os_time_t timeout_secs)
|
||||
{
|
||||
return os_reltime_expired(now, ts, timeout_secs);
|
||||
}
|
||||
|
||||
u8 rssi_to_rcpi(int rssi)
|
||||
{
|
||||
if (!rssi)
|
||||
return 255; /* not available */
|
||||
if (rssi < -110)
|
||||
return 0;
|
||||
if (rssi > 0)
|
||||
return 220;
|
||||
return (rssi + 110) * 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_ssid_txt - Convert SSID to a printable string
|
||||
* @ssid: SSID (32-octet string)
|
||||
* @ssid_len: Length of ssid in octets
|
||||
* Returns: Pointer to a printable string
|
||||
*
|
||||
* This function can be used to convert SSIDs into printable form. In most
|
||||
* cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
|
||||
* does not limit the used character set, so anything could be used in an SSID.
|
||||
*
|
||||
* This function uses a static buffer, so only one call can be used at the
|
||||
* time, i.e., this is not re-entrant and the returned buffer must be used
|
||||
* before calling this again.
|
||||
*/
|
||||
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
static char ssid_txt[SSID_MAX_LEN * 4 + 1];
|
||||
|
||||
if (ssid == NULL) {
|
||||
ssid_txt[0] = '\0';
|
||||
return ssid_txt;
|
||||
}
|
||||
|
||||
printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
|
||||
return ssid_txt;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#endif /* ets */
|
||||
#include "os.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "list.h"
|
||||
|
||||
/* Define platform specific variable type macros */
|
||||
#if defined(ESP_PLATFORM)
|
||||
@ -115,6 +116,12 @@ static inline unsigned int wpa_swap_32(unsigned int v)
|
||||
#define WPA_BYTE_SWAP_DEFINED
|
||||
#endif /* !WPA_BYTE_SWAP_DEFINED */
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
|
||||
struct wpa_ssid_value {
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
};
|
||||
|
||||
/* Macros for handling unaligned memory accesses */
|
||||
|
||||
@ -379,6 +386,10 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
|
||||
size_t len);
|
||||
|
||||
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
|
||||
u8 rssi_to_rcpi(int rssi);
|
||||
int os_time_expired(struct os_time *now,
|
||||
struct os_time *ts,
|
||||
os_time_t timeout_secs);
|
||||
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
void wpa_unicode2ascii_inplace(TCHAR *str);
|
||||
|
@ -12,8 +12,8 @@
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
#ifndef DL_LIST_H
|
||||
#define DL_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@ -100,4 +100,4 @@ static inline unsigned int dl_list_len(struct dl_list *list)
|
||||
#define DEFINE_DL_LIST(name) \
|
||||
struct dl_list name = { &(name), &(name) }
|
||||
|
||||
#endif /* LIST_H */
|
||||
#endif /* DL_LIST_H */
|
||||
|
@ -91,22 +91,22 @@ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
|
||||
size_t i;
|
||||
char output[50];
|
||||
|
||||
if (level < MSG_MSGDUMP)
|
||||
if (level < MSG_ERROR)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s - hexdump(len=%lu):", title, (unsigned long) len);
|
||||
wpa_printf(level, "%s - hexdump(len=%lu):", title, (unsigned long) len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, " [NULL]");
|
||||
wpa_printf(level, " [NULL]");
|
||||
} else {
|
||||
for (i = 0; i < len / 16; i++) {
|
||||
_wpa_snprintf_hex(output, 50, buf + i * 16, 16, 0, 1);
|
||||
wpa_printf(MSG_DEBUG, "%s", output);
|
||||
wpa_printf(level, "%s", output);
|
||||
}
|
||||
if (len % 16) {
|
||||
int bytes_printed = (len / 16) * 16;
|
||||
_wpa_snprintf_hex(output, 50, buf + bytes_printed,
|
||||
len - bytes_printed, 0, 1);
|
||||
wpa_printf(MSG_DEBUG, "%s", output);
|
||||
wpa_printf(level, "%s", output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
9
examples/wifi/roaming/CMakeLists.txt
Normal file
9
examples/wifi/roaming/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
# (Automatically converted from project Makefile by convert_to_cmake.py.)
|
||||
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(roaming)
|
8
examples/wifi/roaming/Makefile
Normal file
8
examples/wifi/roaming/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := roaminng
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
58
examples/wifi/roaming/README.md
Normal file
58
examples/wifi/roaming/README.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Roaming Example
|
||||
|
||||
This example demonstrate a roaming example using 11k and 11v APIs.
|
||||
|
||||
All the logs are taken after debug enabled:
|
||||
|
||||
Beacon request:
|
||||
|
||||
I (11125) wpa: scan issued at time=7579442263
|
||||
I (11125) wpa: BSS: Add new id 1 BSSID b6:fb:e4:4d:6e:22 SSID 'ESPTest' chan 1
|
||||
I (11135) wpa: BSS: Add new id 2 BSSID d6:fb:e4:4d:6e:22 SSID 'ESPDedicated' chan 1
|
||||
I (11165) wpa: BSS: Add new id 3 BSSID c6:fb:e4:4d:6e:22 SSID 'ESPGuestNetwork' chan 1
|
||||
I (11185) wpa: BSS: Add new id 4 BSSID b4:fb:e4:4d:6e:22 SSID 'ESPIndia' chan 1
|
||||
I (11245) wpa: BSS: Add new id 5 BSSID b8:27:eb:3b:4a:59 SSID 'wpa2_enterprise' chan 6
|
||||
I (11365) wpa: BSS: Add new id 6 BSSID 38:94:ed:34:07:66 SSID 'Nighthawk' chan 6
|
||||
I (11365) wpa: BSS: Add new id 7 BSSID 10:da:43:dc:99:20 SSID 'NETGEAR40' chan 6
|
||||
I (12435) wpa: BSS: Add new id 8 BSSID c6:fb:e4:4d:7c:89 SSID 'ESPGuestNetwork' chan 11
|
||||
I (12445) wpa: BSS: Add new id 9 BSSID d6:fb:e4:4d:7c:89 SSID 'ESPDedicated' chan 11
|
||||
I (12455) wpa: BSS: Add new id 10 BSSID b6:fb:e4:4d:7c:89 SSID 'ESPTest' chan 11
|
||||
I (12485) wpa: BSS: Add new id 11 BSSID b4:fb:e4:4d:7c:89 SSID 'ESPIndia' chan 11
|
||||
I (12825) wpa: scan done received
|
||||
I (12845) wpa: action frame sent
|
||||
I (12845) wpa: action frame sent
|
||||
|
||||
Sta's moving from one AP to another on BTM request:
|
||||
|
||||
I (379479) wpa: WNM: RX action 7 from 50:3e:aa:26:35:42
|
||||
I (379479) wpa: WNM: BSS Transition Management Request: dialog_token=1 request_mode=0x1 disassoc_timer=0 validity_interval=1
|
||||
I (379489) wpa: WNM: Neighbor report tag 52
|
||||
I (379499) wpa: WNM: Subelement id=3 len=1
|
||||
I (379499) wpa: WNM: BSS Transition Candidate List
|
||||
I (379509) wpa: 0: b4:e6:2d:eb:1d:76 info=0x0 op_class=81 chan=1 phy=7 pref=255
|
||||
I (379519) wpa: WNM: Candidate list valid for 102 ms
|
||||
I (379519) wpa: WNM: Scan only for a specific BSSID since there is only a single candidate b4:e6:2d:eb:1d:76
|
||||
I (379539) wpa: scan issued at time=9979439869
|
||||
I (379539) wpa: BSS: Add new id 12 BSSID b4:e6:2d:eb:1d:76 SSID 'roaming_test123' chan 6
|
||||
I (381979) wpa: scan done received
|
||||
I (381979) wpa: WNM: Process scan results for BSS Transition Management
|
||||
I (381979) wpa: WNM: Found an acceptable preferred transition candidate BSS b4:e6:2d:eb:1d:76 (RSSI -7)
|
||||
I (381989) wpa: WNM: Transition to BSS b4:e6:2d:eb:1d:76 based on BSS Transition Management Request after_new_scan=1)
|
||||
I (381999) wpa: WNM: Sending successful BSS Transition Management Response
|
||||
I (382009) wpa: WNM: Send BSS Transition Management Response to 50:3e:aa:26:35:42 dialog_token=1 status=0 reason=0 delay=0
|
||||
I (382019) wpa: action frame sent
|
||||
I (382029) wpa: WNM: Issuing connect
|
||||
I (382029) wifi:state: run -> init (0)
|
||||
I (382029) wifi:pm stop, total sleep time: 102136757 us / 109258805 us
|
||||
|
||||
I (382039) wifi:new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (382769) wifi:new:<6,1>, old:<6,0>, ap:<255,255>, sta:<6,1>, prof:1
|
||||
I (384689) wifi:state: init -> auth (b0)
|
||||
I (384699) wifi:state: auth -> assoc (0)
|
||||
I (384709) wifi:state: assoc -> run (10)
|
||||
I (384729) wifi:connected with roaming_test123, aid = 1, channel 6, 40U, bssid = b4:e6:2d:eb:1d:76
|
||||
I (384729) wifi:security: WPA2-PSK, phy: bgn, rssi: -7
|
||||
I (384729) wifi:pm start, type: 1
|
||||
|
||||
I (384789) wifi:AP's beacon interval = 102400 us, DTIM period = 2
|
||||
I (385609) esp_netif_handlers: sta ip: 192.168.4.2, mask: 255.255.255.0, gw: 192.168.4.1
|
3
examples/wifi/roaming/main/CMakeLists.txt
Normal file
3
examples/wifi/roaming/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# Embed CA, certificate & key directly into binary
|
||||
idf_component_register(SRCS "roaming_example.c"
|
||||
INCLUDE_DIRS ".")
|
21
examples/wifi/roaming/main/Kconfig.projbuild
Normal file
21
examples/wifi/roaming/main/Kconfig.projbuild
Normal file
@ -0,0 +1,21 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "roaming_test"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "password"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config EXAMPLE_WIFI_RSSI_THRESHOLD
|
||||
int "WiFi RSSI threshold to trigger roaming"
|
||||
default 0
|
||||
help
|
||||
WiFi RSSI threshold to trigger roaming value in dbm (-100 to 0). 0 denotes feature is disabled.
|
||||
|
||||
endmenu
|
4
examples/wifi/roaming/main/component.mk
Normal file
4
examples/wifi/roaming/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
364
examples/wifi/roaming/main/roaming_example.c
Normal file
364
examples/wifi/roaming/main/roaming_example.c
Normal file
@ -0,0 +1,364 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wnm.h"
|
||||
#include "esp_rrm.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
/* Configuration */
|
||||
#define EXAMPLE_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID
|
||||
#define EXAMPLE_WIFI_PASSWORD CONFIG_EXAMPLE_WIFI_PASSWORD
|
||||
#define EXAMPLE_WIFI_RSSI_THRESHOLD CONFIG_EXAMPLE_WIFI_RSSI_THRESHOLD
|
||||
|
||||
/* rrm ctx */
|
||||
int rrm_ctx = 0;
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
/* esp netif object representing the WIFI station */
|
||||
static esp_netif_t *sta_netif = NULL;
|
||||
|
||||
static const char *TAG = "roaming_example";
|
||||
|
||||
static inline uint32_t WPA_GET_LE32(const uint8_t *a)
|
||||
{
|
||||
return ((uint32_t) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
|
||||
}
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
wifi_event_sta_disconnected_t *disconn = event_data;
|
||||
if (disconn->reason == WIFI_REASON_ROAMING) {
|
||||
ESP_LOGI(TAG, "station roaming, do nothing");
|
||||
} else {
|
||||
esp_wifi_connect();
|
||||
}
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
|
||||
#if EXAMPLE_WIFI_RSSI_THRESHOLD
|
||||
if (EXAMPLE_WIFI_RSSI_THRESHOLD) {
|
||||
ESP_LOGI(TAG, "setting rssi threshold as %d\n", EXAMPLE_WIFI_RSSI_THRESHOLD);
|
||||
esp_wifi_set_rssi_threshold(EXAMPLE_WIFI_RSSI_THRESHOLD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WLAN_EID_MEASURE_REPORT
|
||||
#define WLAN_EID_MEASURE_REPORT 39
|
||||
#endif
|
||||
#ifndef MEASURE_TYPE_LCI
|
||||
#define MEASURE_TYPE_LCI 9
|
||||
#endif
|
||||
#ifndef MEASURE_TYPE_LOCATION_CIVIC
|
||||
#define MEASURE_TYPE_LOCATION_CIVIC 11
|
||||
#endif
|
||||
#ifndef WLAN_EID_NEIGHBOR_REPORT
|
||||
#define WLAN_EID_NEIGHBOR_REPORT 52
|
||||
#endif
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#define MAX_NEIGHBOR_LEN 512
|
||||
#if 1
|
||||
static char * get_btm_neighbor_list(uint8_t *report, size_t report_len)
|
||||
{
|
||||
size_t len = 0;
|
||||
const uint8_t *data;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Neighbor Report element (IEEE P802.11-REVmc/D5.0)
|
||||
* BSSID[6]
|
||||
* BSSID Information[4]
|
||||
* Operating Class[1]
|
||||
* Channel Number[1]
|
||||
* PHY Type[1]
|
||||
* Optional Subelements[variable]
|
||||
*/
|
||||
#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
|
||||
|
||||
if (!report || report_len == 0) {
|
||||
ESP_LOGI(TAG, "RRM neighbor report is not valid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *buf = calloc(1, MAX_NEIGHBOR_LEN);
|
||||
data = report;
|
||||
|
||||
while (report_len >= 2 + NR_IE_MIN_LEN) {
|
||||
const uint8_t *nr;
|
||||
char lci[256 * 2 + 1];
|
||||
char civic[256 * 2 + 1];
|
||||
uint8_t nr_len = data[1];
|
||||
const uint8_t *pos = data, *end;
|
||||
|
||||
if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
|
||||
nr_len < NR_IE_MIN_LEN) {
|
||||
ESP_LOGI(TAG, "CTRL: Invalid Neighbor Report element: id=%u len=%u",
|
||||
data[0], nr_len);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (2U + nr_len > report_len) {
|
||||
ESP_LOGI(TAG, "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
|
||||
data[0], report_len, nr_len);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
pos += 2;
|
||||
end = pos + nr_len;
|
||||
|
||||
nr = pos;
|
||||
pos += NR_IE_MIN_LEN;
|
||||
|
||||
lci[0] = '\0';
|
||||
civic[0] = '\0';
|
||||
while (end - pos > 2) {
|
||||
uint8_t s_id, s_len;
|
||||
|
||||
s_id = *pos++;
|
||||
s_len = *pos++;
|
||||
if (s_len > end - pos) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
|
||||
/* Measurement Token[1] */
|
||||
/* Measurement Report Mode[1] */
|
||||
/* Measurement Type[1] */
|
||||
/* Measurement Report[variable] */
|
||||
switch (pos[2]) {
|
||||
case MEASURE_TYPE_LCI:
|
||||
if (lci[0])
|
||||
break;
|
||||
memcpy(lci, pos, s_len);
|
||||
break;
|
||||
case MEASURE_TYPE_LOCATION_CIVIC:
|
||||
if (civic[0])
|
||||
break;
|
||||
memcpy(civic, pos, s_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pos += s_len;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "RMM neigbor report bssid=" MACSTR
|
||||
" info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
|
||||
MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
|
||||
nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
|
||||
nr[ETH_ALEN + 6],
|
||||
lci[0] ? " lci=" : "", lci,
|
||||
civic[0] ? " civic=" : "", civic);
|
||||
|
||||
/* neighbor start */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, " neighbor=");
|
||||
/* bssid */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, MACSTR, MAC2STR(nr));
|
||||
/* , */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* bssid info */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "0x%04x", WPA_GET_LE32(nr + ETH_ALEN));
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* operating class */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 4]);
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* channel number */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 5]);
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* phy type */
|
||||
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 6]);
|
||||
/* optional elements, skip */
|
||||
|
||||
data = end;
|
||||
report_len -= 2 + nr_len;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ret < 0) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Sample API to create neighbor list */
|
||||
char * get_tmp_neighbor_list(uint8_t *report, size_t report_len)
|
||||
{
|
||||
#define MAC1 "00:01:02:03:04:05"
|
||||
#define MAC2 "00:02:03:04:05:06"
|
||||
|
||||
char * buf = calloc(1, MAX_NEIGHBOR_LEN);
|
||||
size_t len = 0;
|
||||
char *pos;
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
pos = buf;
|
||||
/* create two temp neighbors */
|
||||
/* format for neighbor list : neighbor=11:22:33:44:55:66,0x0000,81,3,7,0301ff */
|
||||
|
||||
/* neighbor1 start */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, " neighbor=");
|
||||
/* bssid */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, MAC1);
|
||||
/* , */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* bssid info */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "0x0000");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* operating class */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "81");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* channel number */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "6");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* phy type */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "7");
|
||||
/* optional elements, skip */
|
||||
|
||||
/* neighbor2 start */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, " neighbor=");
|
||||
/* bssid */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, MAC2);
|
||||
/* , */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* bssid info */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "0x0000");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* operating class */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "81");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* channel number */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "6");
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, ",");
|
||||
/* phy type */
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, "7");
|
||||
/* optional elements, skip */
|
||||
|
||||
len += snprintf(pos + len, MAX_NEIGHBOR_LEN - len, " ");
|
||||
|
||||
#undef MAC1
|
||||
#undef MAC2
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
void neighbor_report_recv_cb(void *ctx, const uint8_t *report, size_t report_len)
|
||||
{
|
||||
int *val = ctx;
|
||||
uint8_t *pos = (uint8_t *)report;
|
||||
int cand_list = 0;
|
||||
|
||||
if (!report) {
|
||||
ESP_LOGE(TAG, "report is null");
|
||||
return;
|
||||
}
|
||||
if (*val != rrm_ctx) {
|
||||
ESP_LOGE(TAG, "rrm_ctx value didn't match, not initiated by us");
|
||||
return;
|
||||
}
|
||||
/* dump report info */
|
||||
ESP_LOGI(TAG, "rrm: neighbor report len=%d", report_len);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, pos, report_len, ESP_LOG_INFO);
|
||||
|
||||
/* create neighbor list */
|
||||
char *neighbor_list = get_btm_neighbor_list(pos + 1, report_len - 1);
|
||||
|
||||
/* In case neighbor list is not present issue a scan and get the list from that */
|
||||
if (!neighbor_list) {
|
||||
/* issue scan */
|
||||
wifi_scan_config_t params;
|
||||
memset(¶ms, 0, sizeof(wifi_scan_config_t));
|
||||
if (esp_wifi_scan_start(¶ms, true) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
/* cleanup from net802.11 */
|
||||
uint16_t number = 1;
|
||||
wifi_ap_record_t ap_records;
|
||||
esp_wifi_scan_get_ap_records(&number, &ap_records);
|
||||
cand_list = 1;
|
||||
}
|
||||
/* send AP btm query, this will cause STA to roam as well */
|
||||
esp_wnm_send_bss_transition_mgmt_query(REASON_FRAME_LOSS, neighbor_list, cand_list);
|
||||
|
||||
cleanup:
|
||||
if (neighbor_list)
|
||||
free(neighbor_list);
|
||||
}
|
||||
|
||||
#if EXAMPLE_WIFI_RSSI_THRESHOLD
|
||||
static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
wifi_event_bss_rssi_low_t *event = event_data;
|
||||
|
||||
ESP_LOGI(TAG, "%s:bss rssi is=%d", __func__, event->rssi);
|
||||
/* Lets check channel conditions */
|
||||
rrm_ctx++;
|
||||
if (esp_rrm_send_neighbor_rep_request(neighbor_report_recv_cb, &rrm_ctx) < 0) {
|
||||
/* failed to send neighbor report request */
|
||||
ESP_LOGI(TAG, "failed to send neighbor report request");
|
||||
if (esp_wnm_send_bss_transition_mgmt_query(REASON_FRAME_LOSS, NULL, 0) < 0) {
|
||||
ESP_LOGI(TAG, "failed to send btm query");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
sta_netif = esp_netif_create_default_wifi_sta();
|
||||
assert(sta_netif);
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
|
||||
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
|
||||
#if EXAMPLE_WIFI_RSSI_THRESHOLD
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_BSS_RSSI_LOW,
|
||||
&esp_bss_rssi_low_handler, NULL));
|
||||
#endif
|
||||
|
||||
|
||||
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = EXAMPLE_WIFI_SSID,
|
||||
.password = EXAMPLE_WIFI_PASSWORD,
|
||||
.rm_enabled =1,
|
||||
.btm_enabled =1,
|
||||
},
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
|
||||
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK( nvs_flash_init() );
|
||||
initialise_wifi();
|
||||
}
|
2
examples/wifi/roaming/sdkconfig.defaults
Normal file
2
examples/wifi/roaming/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_WPA_11KV_SUPPORT=y
|
||||
CONFIG_WPA_SCAN_CACHE=y
|
Loading…
x
Reference in New Issue
Block a user