mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
esp_wifi: Add support for MBO certification
This commit is contained in:
parent
e35a87f723
commit
834afad47e
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2016 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __ESP_WIFI_TYPES_H__
|
||||
@ -80,6 +72,7 @@ typedef enum {
|
||||
WIFI_REASON_ASSOC_NOT_AUTHED = 9,
|
||||
WIFI_REASON_DISASSOC_PWRCAP_BAD = 10,
|
||||
WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11,
|
||||
WIFI_REASON_BSS_TRANSITION_DISASSOC = 12,
|
||||
WIFI_REASON_IE_INVALID = 13,
|
||||
WIFI_REASON_MIC_FAILURE = 14,
|
||||
WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
|
||||
@ -250,7 +243,8 @@ typedef struct {
|
||||
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 */
|
||||
uint32_t mbo_enabled:1; /**< Whether MBO is enabled for the connection */
|
||||
uint32_t reserved:29; /**< Reserved for future feature set */
|
||||
} wifi_sta_config_t;
|
||||
|
||||
/** @brief Configuration data for ESP32 AP or STA.
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 4e1c7a8114fd03b9841f78a218f579799cb61a0a
|
||||
Subproject commit 6f9d2a11850b9fc0d4fd4ce89c492129e06fd77c
|
@ -154,8 +154,13 @@ if(CONFIG_WPA_11KV_SUPPORT)
|
||||
else()
|
||||
set(roaming_src "")
|
||||
endif()
|
||||
if(CONFIG_WPA_MBO_SUPPORT)
|
||||
set(mbo_src "src/common/mbo.c")
|
||||
else()
|
||||
set(mbo_src "")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" "${crypto_src}"
|
||||
idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}" "${crypto_src}" "${mbo_src}"
|
||||
INCLUDE_DIRS include port/include esp_supplicant/include
|
||||
PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src
|
||||
PRIV_REQUIRES mbedtls esp_timer)
|
||||
@ -190,4 +195,7 @@ if(CONFIG_WPA_WPS_STRICT)
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_STRICT)
|
||||
endif()
|
||||
|
||||
if(CONFIG_WPA_MBO_SUPPORT)
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_MBO)
|
||||
endif()
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
|
||||
|
@ -59,12 +59,18 @@ menu "Supplicant"
|
||||
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
|
||||
menuconfig WPA_SCAN_CACHE
|
||||
bool "Keep scan results in cache"
|
||||
depends on WPA_11KV_SUPPORT
|
||||
default n
|
||||
help
|
||||
Keep scan results in cache, if not enabled, those
|
||||
will be flushed immediately.
|
||||
|
||||
menuconfig WPA_MBO_SUPPORT
|
||||
bool "Enable MBO support in supplicant"
|
||||
depends on WPA_11KV_SUPPORT
|
||||
default n
|
||||
help
|
||||
Select this option to enable WiFi Multiband operation certification support.
|
||||
endmenu
|
||||
|
@ -70,6 +70,9 @@ ifneq ($(CONFIG_WPA_11KV_SUPPORT), y)
|
||||
esp_supplicant/src/esp_common.o \
|
||||
esp_supplicant/src/esp_scan.o
|
||||
endif
|
||||
ifneq ($(CONFIG_WPA_MBO_SUPPORT), y)
|
||||
COMPONENT_OBJEXCLUDE += src/common/mbo.o
|
||||
endif
|
||||
|
||||
CFLAGS += -DCONFIG_SHA256 -DCONFIG_DPP -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
|
||||
|
||||
@ -79,3 +82,6 @@ endif
|
||||
ifdef CONFIG_WPA_WPS_STRICT
|
||||
CFLAGS += -DCONFIG_WPS_STRICT
|
||||
endif
|
||||
ifdef CONFIG_WPA_MBO_SUPPORT
|
||||
CFLAGS += -DCONFIG_MBO
|
||||
endif
|
||||
|
64
components/wpa_supplicant/esp_supplicant/include/esp_mbo.h
Normal file
64
components/wpa_supplicant/esp_supplicant/include/esp_mbo.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ESP_MBO_H
|
||||
#define _ESP_MBO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum non_pref_chan_reason: Reason for non preference of channel
|
||||
*/
|
||||
enum non_pref_chan_reason {
|
||||
NON_PREF_CHAN_REASON_UNSPECIFIED = 0,
|
||||
NON_PREF_CHAN_REASON_RSSI = 1,
|
||||
NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2,
|
||||
NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Channel structure for non preferred channel
|
||||
*
|
||||
* @param reason: enum non_pref_chan_reason
|
||||
* @param oper_class: operating class for the channel
|
||||
* @param chan: channel number
|
||||
* @param preference: channel preference
|
||||
*/
|
||||
struct non_pref_chan {
|
||||
enum non_pref_chan_reason reason;
|
||||
uint8_t oper_class;
|
||||
uint8_t chan;
|
||||
uint8_t preference;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Array structure for non preferred channel struct
|
||||
*
|
||||
* @param non_pref_chan_num: channel count
|
||||
* @param chan: array of non_pref_chan type
|
||||
*/
|
||||
struct non_pref_chan_s {
|
||||
size_t non_pref_chan_num;
|
||||
struct non_pref_chan chan[];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Update channel preference for MBO IE
|
||||
*
|
||||
* @param non_pref_chan: Non preference channel list
|
||||
*
|
||||
* @return
|
||||
* - 0: success else failure
|
||||
*/
|
||||
int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -1,17 +1,7 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO 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.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ESP_WNM_H
|
||||
@ -29,11 +19,13 @@ 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,
|
||||
REASON_BANDWIDTH = 3,
|
||||
REASON_LOAD_BALANCE = 4,
|
||||
REASON_RSSI = 5,
|
||||
REASON_RETRANSMISSIONS = 6,
|
||||
REASON_INTERFERENCE = 7,
|
||||
REASON_GRAY_ZONE = 8,
|
||||
REASON_PREMIUM_AP = 9,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,17 +1,7 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO 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.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
@ -37,8 +27,8 @@ 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)
|
||||
static int 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);
|
||||
|
||||
@ -61,7 +51,7 @@ static int esp_handle_action_frm(u8 *frame, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esp_rx_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
|
||||
static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
|
||||
u8 *payload, size_t len, u32 rssi)
|
||||
{
|
||||
if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
|
||||
@ -78,7 +68,7 @@ static void esp_rx_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
|
||||
}
|
||||
}
|
||||
|
||||
static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi)
|
||||
static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi)
|
||||
{
|
||||
u8 category;
|
||||
u8 bssid[ETH_ALEN];
|
||||
@ -95,13 +85,13 @@ static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u
|
||||
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);
|
||||
handle_rrm_frame(wpa_s, sender, payload, len, rssi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esp_btm_rrm_task(void *pvParameters)
|
||||
static void btm_rrm_task(void *pvParameters)
|
||||
{
|
||||
supplicant_event_t *evt;
|
||||
bool task_del = false;
|
||||
@ -120,7 +110,7 @@ static void esp_btm_rrm_task(void *pvParameters)
|
||||
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);
|
||||
mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi);
|
||||
os_free(frm);
|
||||
break;
|
||||
}
|
||||
@ -153,7 +143,7 @@ static void esp_btm_rrm_task(void *pvParameters)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s)
|
||||
static void clear_bssid_flag(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wifi_config_t *config;
|
||||
|
||||
@ -175,7 +165,7 @@ static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s)
|
||||
wpa_printf(MSG_DEBUG, "cleared bssid flag");
|
||||
}
|
||||
|
||||
static void esp_register_action_frame(struct wpa_supplicant *wpa_s)
|
||||
static void register_action_frame(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_s->type &= ~(1 << WLAN_FC_STYPE_ACTION);
|
||||
/* subtype is defined only for action frame */
|
||||
@ -193,8 +183,8 @@ static void esp_register_action_frame(struct wpa_supplicant *wpa_s)
|
||||
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,
|
||||
int32_t event_id, void* event_data)
|
||||
static void supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 *ie;
|
||||
@ -215,13 +205,13 @@ static void esp_supplicant_sta_conn_handler(void* arg, esp_event_base_t event_ba
|
||||
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);
|
||||
register_action_frame(wpa_s);
|
||||
/* clear set bssid flag */
|
||||
esp_clear_bssid_flag(wpa_s);
|
||||
clear_bssid_flag(wpa_s);
|
||||
}
|
||||
|
||||
static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
wpas_rrm_reset(wpa_s);
|
||||
@ -230,12 +220,49 @@ static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event
|
||||
}
|
||||
}
|
||||
|
||||
static int 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 handle_action_frm(frame, len, sender, rssi, channel);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
static bool bss_profile_match(u8 *sender)
|
||||
{
|
||||
/* Incase supplicant wants drivers to skip this BSS, return false */
|
||||
struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, sender);
|
||||
if (!bss) {
|
||||
return true;
|
||||
}
|
||||
const u8 *assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
|
||||
if (assoc_disallow && assoc_disallow[1] >= 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"skip - MBO association disallowed (reason %u)", assoc_disallow[2]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wpa_is_bss_tmp_disallowed(&g_wpa_supp, bss)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"skip - BSS is temporary disallowed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
xTaskCreate(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) {
|
||||
@ -248,13 +275,22 @@ void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
|
||||
wpas_clear_beacon_rep_data(wpa_s);
|
||||
|
||||
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
|
||||
&esp_supplicant_sta_conn_handler, NULL);
|
||||
&supplicant_sta_conn_handler, NULL);
|
||||
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
|
||||
&esp_supplicant_sta_disconn_handler, NULL);
|
||||
&supplicant_sta_disconn_handler, NULL);
|
||||
|
||||
wpa_s->type = 0;
|
||||
wpa_s->subtype = 0;
|
||||
wpa_cb->wpa_sta_rx_mgmt = esp_ieee80211_handle_rx_frm;
|
||||
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);
|
||||
wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm;
|
||||
/* Matching is done only for MBO at the moment, this can be extended for other features*/
|
||||
#ifdef CONFIG_MBO
|
||||
wpa_cb->wpa_sta_profile_match = bss_profile_match;
|
||||
dl_list_init(&wpa_s->bss_tmp_disallowed);
|
||||
#else
|
||||
wpa_cb->wpa_sta_profile_match = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_supplicant_common_deinit(void)
|
||||
@ -268,28 +304,38 @@ void esp_supplicant_common_deinit(void)
|
||||
wpas_rrm_reset(wpa_s);
|
||||
wpas_clear_beacon_rep_data(wpa_s);
|
||||
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
|
||||
&esp_supplicant_sta_conn_handler);
|
||||
&supplicant_sta_conn_handler);
|
||||
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
|
||||
&esp_supplicant_sta_disconn_handler);
|
||||
&supplicant_sta_disconn_handler);
|
||||
}
|
||||
|
||||
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;
|
||||
return wpas_rrm_send_neighbor_rep_request(wpa_s, &wpa_ssid, 0, 0, cb, cb_ctx);
|
||||
|
||||
return wpas_rrm_send_neighbor_rep_request(&g_wpa_supp, &wpa_ssid, 0, 0, cb, cb_ctx);
|
||||
}
|
||||
|
||||
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);
|
||||
return wnm_send_bss_transition_mgmt_query(&g_wpa_supp, query_reason, btm_candidates, cand_list);
|
||||
}
|
||||
|
||||
int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
|
||||
{
|
||||
int ret = wpas_mbo_update_non_pref_chan(&g_wpa_supp, non_pref_chan);
|
||||
if (ret == 0) {
|
||||
esp_set_assoc_ie();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
|
||||
@ -306,18 +352,25 @@ void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
|
||||
/* 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);
|
||||
/* supplicant connect will only be called in case of bss transition(roaming) */
|
||||
esp_wifi_internal_issue_disconnect(WIFI_REASON_BSS_TRANSITION_DISASSOC);
|
||||
esp_wifi_set_config(WIFI_IF_STA, config);
|
||||
os_free(config);
|
||||
esp_wifi_connect();
|
||||
}
|
||||
|
||||
void esp_set_rm_enabled_ie(void)
|
||||
static size_t get_rm_enabled_ie(uint8_t *ie, size_t len)
|
||||
{
|
||||
uint8_t rmm_ie[5] = {0};
|
||||
uint8_t rrm_ie[7] = {0};
|
||||
uint8_t rrm_ie_len = 5;
|
||||
uint8_t *pos = rmm_ie;
|
||||
uint8_t *pos = rrm_ie;
|
||||
|
||||
if (!esp_wifi_is_rm_enabled_internal(WIFI_IF_STA)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
|
||||
*pos++ = rrm_ie_len;
|
||||
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
|
||||
|
||||
*pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
|
||||
@ -326,10 +379,147 @@ void esp_set_rm_enabled_ie(void)
|
||||
#endif
|
||||
WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE;
|
||||
|
||||
/* set rm enabled IE if enabled in driver */
|
||||
if (esp_wifi_is_rm_enabled_internal(WIFI_IF_STA)) {
|
||||
esp_wifi_set_appie_internal(WIFI_APPIE_RM_ENABLED_CAPS, rmm_ie, rrm_ie_len, 0);
|
||||
os_memcpy(ie, rrm_ie, sizeof(rrm_ie));
|
||||
|
||||
return rrm_ie_len + 2;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
static size_t get_mbo_oce_scan_ie(uint8_t *ie, size_t len)
|
||||
{
|
||||
uint8_t mbo_ie[32] = {0};
|
||||
uint8_t mbo_ie_len = 32;
|
||||
|
||||
/* Return if MBO IE is not enabled in driver */
|
||||
if (!esp_wifi_is_mbo_enabled_internal(WIFI_IF_STA)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct wpabuf *default_ies = NULL;
|
||||
if (wpabuf_resize(&default_ies, 18) == 0) {
|
||||
wpas_mbo_scan_ie(&g_wpa_supp, default_ies);
|
||||
os_memcpy(mbo_ie, wpabuf_head_u8(default_ies), wpabuf_len(default_ies));
|
||||
mbo_ie_len = wpabuf_len(default_ies);
|
||||
wpabuf_free(default_ies);
|
||||
}
|
||||
os_memcpy(ie, mbo_ie, mbo_ie_len);
|
||||
return mbo_ie_len;
|
||||
}
|
||||
|
||||
static size_t get_mbo_oce_assoc_ie(uint8_t *ie, size_t len)
|
||||
{
|
||||
uint8_t mbo_ie[32] = {0};
|
||||
uint8_t mbo_ie_len = 32;
|
||||
|
||||
/* Return if MBO IE is not enabled in driver */
|
||||
if (!esp_wifi_is_mbo_enabled_internal(WIFI_IF_STA)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mbo_ie_len = wpas_mbo_ie(&g_wpa_supp, mbo_ie, mbo_ie_len, 0);
|
||||
os_memcpy(ie, mbo_ie, mbo_ie_len);
|
||||
|
||||
return mbo_ie_len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len)
|
||||
{
|
||||
uint8_t ext_caps_ie[5] = {0};
|
||||
uint8_t ext_caps_ie_len = 3;
|
||||
uint8_t *pos = ext_caps_ie;
|
||||
|
||||
if (!esp_wifi_is_btm_enabled_internal(WIFI_IF_STA)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pos++ = WLAN_EID_EXT_CAPAB;
|
||||
*pos++ = ext_caps_ie_len;
|
||||
*pos++ = 0;
|
||||
*pos++ = 0;
|
||||
#define WLAN_EXT_CAPAB_BSS_TRANSITION BIT(3)
|
||||
*pos |= WLAN_EXT_CAPAB_BSS_TRANSITION;
|
||||
#undef WLAN_EXT_CAPAB_BSS_TRANSITION
|
||||
os_memcpy(ie, ext_caps_ie, sizeof(ext_caps_ie));
|
||||
|
||||
return ext_caps_ie_len + 2;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t get_operating_class_ie(uint8_t *ie, size_t len)
|
||||
{
|
||||
uint8_t op_class_ie[4] = {0};
|
||||
uint8_t op_class_ie_len = 2;
|
||||
uint8_t *pos = op_class_ie;
|
||||
|
||||
*pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
|
||||
*pos++ = op_class_ie_len;
|
||||
#define OPER_CLASS 0x51
|
||||
/* Current Operating Class */
|
||||
*pos++ = OPER_CLASS;
|
||||
#undef OPER_CLASS
|
||||
*pos = 0;
|
||||
os_memcpy(ie, op_class_ie, sizeof(op_class_ie));
|
||||
|
||||
return op_class_ie_len + 2;
|
||||
}
|
||||
|
||||
void esp_set_scan_ie(void)
|
||||
{
|
||||
#define SCAN_IE_LEN 64
|
||||
uint8_t *ie, *pos;
|
||||
size_t len = SCAN_IE_LEN, ie_len;
|
||||
|
||||
ie = os_malloc(SCAN_IE_LEN);
|
||||
if (!ie) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate ie");
|
||||
return;
|
||||
}
|
||||
pos = ie;
|
||||
ie_len = get_extended_caps_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
#ifdef CONFIG_MBO
|
||||
ie_len = get_mbo_oce_scan_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
#endif
|
||||
esp_wifi_unset_appie_internal(WIFI_APPIE_PROBEREQ);
|
||||
esp_wifi_set_appie_internal(WIFI_APPIE_PROBEREQ, ie, SCAN_IE_LEN - len, 0);
|
||||
os_free(ie);
|
||||
#undef SCAN_IE_LEN
|
||||
}
|
||||
|
||||
void esp_set_assoc_ie(void)
|
||||
{
|
||||
#define ASSOC_IE_LEN 128
|
||||
uint8_t *ie, *pos;
|
||||
size_t len = ASSOC_IE_LEN, ie_len;
|
||||
|
||||
ie = os_malloc(ASSOC_IE_LEN);
|
||||
if (!ie) {
|
||||
wpa_printf(MSG_ERROR, "failed to allocate ie");
|
||||
return;
|
||||
}
|
||||
pos = ie;
|
||||
ie_len = get_extended_caps_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
ie_len = get_operating_class_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
ie_len = get_rm_enabled_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
#ifdef CONFIG_MBO
|
||||
ie_len = get_mbo_oce_assoc_ie(pos, len);
|
||||
pos += ie_len;
|
||||
len -= ie_len;
|
||||
#endif
|
||||
esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ);
|
||||
esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_REQ, ie, ASSOC_IE_LEN - len, 0);
|
||||
os_free(ie);
|
||||
#undef ASSOC_IE_LEN
|
||||
}
|
||||
|
||||
void esp_get_tx_power(uint8_t *tx_power)
|
||||
@ -399,15 +589,3 @@ int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data)
|
||||
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;
|
||||
}
|
||||
|
@ -1,17 +1,7 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO 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.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ESP_COMMON_I_H
|
||||
@ -47,23 +37,20 @@ enum SIG_SUPPLICANT {
|
||||
};
|
||||
|
||||
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);
|
||||
void esp_supplicant_common_deinit(void);
|
||||
void esp_set_scan_ie(void);
|
||||
void esp_set_assoc_ie(void);
|
||||
#else
|
||||
|
||||
#include "esp_rrm.h"
|
||||
#include "esp_wnm.h"
|
||||
#include "esp_mbo.h"
|
||||
|
||||
static inline void esp_set_scan_ie(void) { }
|
||||
static inline void esp_set_assoc_ie(void) { }
|
||||
|
||||
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)
|
||||
{
|
||||
@ -77,5 +64,9 @@ int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
|
||||
return -1;
|
||||
}
|
||||
|
||||
int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,17 +1,7 @@
|
||||
/**
|
||||
* Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO 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.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
@ -32,8 +22,8 @@
|
||||
|
||||
extern struct wpa_supplicant g_wpa_supp;
|
||||
|
||||
static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
static void scan_done_event_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
|
||||
@ -46,7 +36,7 @@ static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base,
|
||||
esp_supplicant_post_evt(SIG_SUPPLICANT_SCAN_DONE, 0);
|
||||
}
|
||||
|
||||
static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
|
||||
static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss);
|
||||
|
||||
@ -64,7 +54,7 @@ static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_supp_scan_done_cleanup(struct wpa_supplicant *wpa_s)
|
||||
static void scan_done_cleanup(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
uint16_t number = 1;
|
||||
wifi_ap_record_t ap_records;
|
||||
@ -84,10 +74,10 @@ void esp_supplicant_handle_scan_done_evt(void)
|
||||
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);
|
||||
handle_wnm_scan_done(wpa_s);
|
||||
}
|
||||
if (wpa_s->scanning) {
|
||||
esp_supp_scan_done_cleanup(wpa_s);
|
||||
scan_done_cleanup(wpa_s);
|
||||
}
|
||||
wpa_bss_update_end(wpa_s);
|
||||
#ifndef SCAN_CACHE_SUPPORTED
|
||||
@ -101,7 +91,7 @@ void esp_scan_init(struct wpa_supplicant *wpa_s)
|
||||
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);
|
||||
&scan_done_event_handler, NULL);
|
||||
}
|
||||
|
||||
void esp_scan_deinit(struct wpa_supplicant *wpa_s)
|
||||
@ -110,7 +100,7 @@ void esp_scan_deinit(struct wpa_supplicant *wpa_s)
|
||||
os_free(wpa_s->last_scan_res);
|
||||
wpa_s->last_scan_res = NULL;
|
||||
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_SCAN_DONE,
|
||||
&esp_scan_done_event_handler);
|
||||
&scan_done_event_handler);
|
||||
}
|
||||
|
||||
int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
@ -158,10 +148,7 @@ int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
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;
|
||||
res->ie_len = len;
|
||||
|
||||
ptr += sizeof(struct wpa_scan_res);
|
||||
|
||||
@ -173,8 +160,8 @@ int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esp_issue_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *scan_params)
|
||||
static int issue_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *scan_params)
|
||||
{
|
||||
wifi_scan_config_t *params = NULL;
|
||||
int ret = 0;
|
||||
@ -203,9 +190,13 @@ static int esp_issue_scan(struct wpa_supplicant *wpa_s,
|
||||
goto cleanup;
|
||||
}
|
||||
os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len);
|
||||
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
|
||||
} else
|
||||
|
||||
if (scan_params->mode == BEACON_REPORT_MODE_PASSIVE) {
|
||||
params->scan_type = WIFI_SCAN_TYPE_PASSIVE;
|
||||
} else {
|
||||
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
|
||||
}
|
||||
|
||||
if (scan_params->bssid) {
|
||||
params->bssid = os_zalloc(ETH_ALEN);
|
||||
@ -260,7 +251,7 @@ cleanup:
|
||||
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_driver_scan_params *params)
|
||||
{
|
||||
return esp_issue_scan(wpa_s, params);
|
||||
return issue_scan(wpa_s, params);
|
||||
}
|
||||
|
||||
void wpa_scan_results_free(struct wpa_scan_results *res)
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2019 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _ESP_WIFI_DRIVER_H_
|
||||
#define _ESP_WIFI_DRIVER_H_
|
||||
@ -57,8 +49,7 @@ typedef enum {
|
||||
|
||||
/* 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_MAX = WIFI_APPIE_MAX,
|
||||
} wifi_appie_ram_t;
|
||||
|
||||
enum {
|
||||
@ -137,6 +128,7 @@ struct wpa_funcs {
|
||||
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);
|
||||
void (*wpa_config_done)(void);
|
||||
bool (*wpa_sta_profile_match)(u8 *bssid);
|
||||
};
|
||||
|
||||
struct wpa2_funcs {
|
||||
@ -266,5 +258,6 @@ esp_err_t esp_wifi_action_tx_req(uint8_t type, uint8_t channel,
|
||||
uint32_t wait_time_ms, const wifi_action_tx_req_t *req);
|
||||
esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t type, uint8_t channel,
|
||||
uint32_t wait_time_ms, wifi_action_rx_cb_t rx_cb);
|
||||
bool esp_wifi_is_mbo_enabled_internal(uint8_t if_index);
|
||||
|
||||
#endif /* _ESP_WIFI_DRIVER_H_ */
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2019 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
@ -123,6 +115,8 @@ bool wpa_attach(void)
|
||||
if(ret) {
|
||||
ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK);
|
||||
}
|
||||
esp_set_scan_ie();
|
||||
esp_set_assoc_ie();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -185,7 +179,7 @@ void wpa_sta_connect(uint8_t *bssid)
|
||||
void wpa_config_done(void)
|
||||
{
|
||||
/* used in future for setting scan and assoc IEs */
|
||||
esp_set_rm_enabled_ie();
|
||||
esp_set_assoc_ie();
|
||||
}
|
||||
|
||||
int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data)
|
||||
@ -230,6 +224,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
|
||||
static inline void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
|
||||
{
|
||||
wpa_cb->wpa_sta_rx_mgmt = NULL;
|
||||
wpa_cb->wpa_sta_profile_match = NULL;
|
||||
}
|
||||
static inline void esp_supplicant_common_deinit(void)
|
||||
{
|
||||
|
@ -132,8 +132,9 @@ static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
|
||||
|
||||
return !is_zero_ether_addr(bss->bssid) && wpa_s->current_bss->bssid &&
|
||||
(os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0);
|
||||
#endif
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
|
||||
@ -198,7 +199,7 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
|
||||
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);
|
||||
os_memcpy(bss->ies, 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);
|
||||
@ -238,7 +239,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
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);
|
||||
os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
|
||||
bss->ie_len = res->ie_len;
|
||||
bss->beacon_ie_len = res->beacon_ie_len;
|
||||
} else {
|
||||
@ -258,7 +259,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
if (wpa_s->current_bss == bss)
|
||||
wpa_s->current_bss = nbss;
|
||||
bss = nbss;
|
||||
os_memcpy(bss + 1, res + 1,
|
||||
os_memcpy(bss->ies, res + 1,
|
||||
res->ie_len + res->beacon_ie_len);
|
||||
bss->ie_len = res->ie_len;
|
||||
bss->beacon_ie_len = res->beacon_ie_len;
|
||||
@ -471,6 +472,31 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
|
||||
return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
|
||||
* @bss: BSS table entry
|
||||
* @vendor_type: Vendor type (four octets starting the IE payload)
|
||||
* 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_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
|
||||
{
|
||||
const u8 *ies;
|
||||
const struct element *elem;
|
||||
|
||||
ies = wpa_bss_ie_ptr(bss);
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
|
||||
if (elem->datalen >= 4 &&
|
||||
vendor_type == WPA_GET_BE32(elem->data))
|
||||
return &elem->id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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),
|
||||
|
@ -58,8 +58,14 @@ struct wpa_bss {
|
||||
size_t beacon_ie_len;
|
||||
/* followed by ie_len octets of IEs */
|
||||
/* followed by beacon_ie_len octets of IEs */
|
||||
u8 ies[];
|
||||
};
|
||||
|
||||
static inline const u8 * wpa_bss_ie_ptr(const struct wpa_bss *bss)
|
||||
{
|
||||
return bss->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,
|
||||
@ -75,6 +81,7 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
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);
|
||||
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
|
||||
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);
|
||||
|
@ -37,6 +37,42 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
|
||||
{
|
||||
const struct element *elem;
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
|
||||
if (elem->datalen >= 4 &&
|
||||
vendor_type == WPA_GET_BE32(elem->data))
|
||||
return &elem->id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||
{
|
||||
/*
|
||||
* MBO IE requires 6 bytes without the attributes: EID (1), length (1),
|
||||
* OUI (3), OUI type (1).
|
||||
*/
|
||||
if (len < 6 + attr_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
|
||||
len, attr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*buf++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*buf++ = attr_len + 4;
|
||||
WPA_PUT_BE24(buf, OUI_WFA);
|
||||
buf += 3;
|
||||
*buf++ = MBO_OUI_TYPE;
|
||||
os_memcpy(buf, attr, attr_len);
|
||||
|
||||
return 6 + attr_len;
|
||||
}
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len)
|
||||
{
|
||||
|
@ -39,5 +39,7 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
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);
|
||||
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
||||
u8 get_operating_class(u8 chan, int sec_channel);
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
@ -212,6 +212,7 @@
|
||||
#define WLAN_EID_FAST_BSS_TRANSITION 55
|
||||
#define WLAN_EID_TIMEOUT_INTERVAL 56
|
||||
#define WLAN_EID_RIC_DATA 57
|
||||
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
|
||||
#define WLAN_EID_HT_OPERATION 61
|
||||
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
|
||||
#define WLAN_EID_WAPI 68
|
||||
@ -536,6 +537,13 @@ struct ieee80211_ht_operation {
|
||||
/* 2 - Reserved */
|
||||
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
|
||||
|
||||
#define MBO_IE_VENDOR_TYPE 0x506f9a16
|
||||
#define OSEN_IE_VENDOR_TYPE 0x506f9a12
|
||||
#define MBO_OUI_TYPE 22
|
||||
#define OCE_STA BIT(0)
|
||||
#define OCE_STA_CFON BIT(1)
|
||||
#define OCE_AP BIT(2)
|
||||
|
||||
/*
|
||||
* WMM Information Element (used in (Re)Association Request frames; may also be
|
||||
* used in Beacon frames)
|
||||
@ -622,6 +630,45 @@ enum wmm_ac {
|
||||
WMM_AC_NUM = 4
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2: MBO Attributes */
|
||||
/* Table 4-5: MBO Attributes */
|
||||
/* OCE v0.0.10, Table 4-3: OCE Attributes */
|
||||
enum mbo_attr_id {
|
||||
MBO_ATTR_ID_AP_CAPA_IND = 1,
|
||||
MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2,
|
||||
MBO_ATTR_ID_CELL_DATA_CAPA = 3,
|
||||
MBO_ATTR_ID_ASSOC_DISALLOW = 4,
|
||||
MBO_ATTR_ID_CELL_DATA_PREF = 5,
|
||||
MBO_ATTR_ID_TRANSITION_REASON = 6,
|
||||
MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7,
|
||||
MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8,
|
||||
OCE_ATTR_ID_CAPA_IND = 101,
|
||||
OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT = 102,
|
||||
OCE_ATTR_ID_REDUCED_WAN_METRICS = 103,
|
||||
OCE_ATTR_ID_RNR_COMPLETENESS = 104,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */
|
||||
/* Table 4-7: MBO AP Capability Indication Field Values */
|
||||
#define MBO_AP_CAPA_CELL_AWARE BIT(6)
|
||||
|
||||
/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */
|
||||
/* Table 4-10: Reason Code Field Values */
|
||||
enum mbo_non_pref_chan_reason {
|
||||
MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0,
|
||||
MBO_NON_PREF_CHAN_REASON_RSSI = 1,
|
||||
MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2,
|
||||
MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */
|
||||
/* Table 4-13: Cellular Data Connectivity Field */
|
||||
enum mbo_cellular_capa {
|
||||
MBO_CELL_CAPA_AVAILABLE = 1,
|
||||
MBO_CELL_CAPA_NOT_AVAILABLE = 2,
|
||||
MBO_CELL_CAPA_NOT_SUPPORTED = 3,
|
||||
};
|
||||
|
||||
/* 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 {
|
||||
@ -634,6 +681,12 @@ enum mbo_transition_reject_reason {
|
||||
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
|
||||
};
|
||||
|
||||
/* OCE v0.0.10, 4.2.1: OCE Capability Indication Attribute */
|
||||
#define OCE_RELEASE 1
|
||||
#define OCE_RELEASE_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define OCE_IS_STA_CFON BIT(3)
|
||||
#define OCE_IS_NON_OCE_AP_PRESENT BIT(4)
|
||||
|
||||
/* IEEE 802.11v - WNM Action field values */
|
||||
enum wnm_action {
|
||||
WNM_EVENT_REQ = 0,
|
||||
|
799
components/wpa_supplicant/src/common/mbo.c
Normal file
799
components/wpa_supplicant/src/common/mbo.c
Normal file
@ -0,0 +1,799 @@
|
||||
/*
|
||||
* wpa_supplicant - MBO
|
||||
*
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* 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 "rsn_supp/wpa.h"
|
||||
#include "wpa_supplicant_i.h"
|
||||
#include "bss.h"
|
||||
#include "scan.h"
|
||||
#include "ieee802_11_common.h"
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
#include "esp_timer.h"
|
||||
#include "esp_mbo.h"
|
||||
|
||||
extern struct wpa_supplicant g_wpa_supp;
|
||||
|
||||
#endif
|
||||
|
||||
/* type + length + oui + oui type */
|
||||
#define MBO_IE_HEADER 6
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
|
||||
{
|
||||
if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE)
|
||||
return -1;
|
||||
|
||||
/* Only checking the validity of the channel and oper_class */
|
||||
if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
|
||||
{
|
||||
const u8 *mbo;
|
||||
u8 ie_len = mbo_ie[1];
|
||||
|
||||
if (ie_len < MBO_IE_HEADER - 2)
|
||||
return NULL;
|
||||
mbo = mbo_ie + MBO_IE_HEADER;
|
||||
|
||||
return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr);
|
||||
}
|
||||
|
||||
|
||||
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
||||
enum mbo_attr_id attr)
|
||||
{
|
||||
const u8 *mbo_ie;
|
||||
|
||||
mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
|
||||
if (!mbo_ie)
|
||||
return NULL;
|
||||
|
||||
return mbo_attr_from_mbo_ie(mbo_ie, attr);
|
||||
}
|
||||
|
||||
|
||||
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
|
||||
{
|
||||
const u8 *mbo, *end;
|
||||
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
|
||||
if (!mbo)
|
||||
return NULL;
|
||||
|
||||
end = mbo + 2 + mbo[1];
|
||||
mbo += MBO_IE_HEADER;
|
||||
|
||||
return get_ie(mbo, end - mbo, attr);
|
||||
}
|
||||
|
||||
|
||||
void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss
|
||||
#ifndef ESP_SUPPLICANT
|
||||
, struct wpa_ssid *ssid
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const u8 *rsne, *mbo, *oce;
|
||||
struct wpa_ie_data ie;
|
||||
|
||||
wpa_s->disable_mbo_oce = 0;
|
||||
if (!bss)
|
||||
return;
|
||||
mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
|
||||
oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
|
||||
if (!mbo && !oce)
|
||||
return;
|
||||
if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
|
||||
return; /* STA-CFON is not required to enable PMF */
|
||||
rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
|
||||
if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
|
||||
return; /* AP is not using RSN */
|
||||
|
||||
if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
|
||||
wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (!esp_wifi_sta_pmf_enabled())
|
||||
#else
|
||||
if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
|
||||
#endif
|
||||
wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
|
||||
if (wpa_s->disable_mbo_oce)
|
||||
wpa_printf(MSG_INFO,
|
||||
"MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
|
||||
}
|
||||
|
||||
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
|
||||
struct wpabuf *mbo,
|
||||
u8 start, u8 end)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class);
|
||||
|
||||
for (i = start; i < end; i++)
|
||||
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan);
|
||||
|
||||
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
|
||||
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size)
|
||||
{
|
||||
wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
|
||||
wpabuf_put_u8(mbo, size); /* Length */
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
|
||||
struct wpabuf *mbo, u8 start, u8 end)
|
||||
{
|
||||
size_t size = end - start + 3;
|
||||
|
||||
if (size + 2 > wpabuf_tailroom(mbo))
|
||||
return;
|
||||
|
||||
wpas_mbo_non_pref_chan_attr_hdr(mbo, size);
|
||||
wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
|
||||
{
|
||||
wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(mbo, len); /* Length */
|
||||
wpabuf_put_be24(mbo, OUI_WFA);
|
||||
wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
|
||||
struct wpabuf *mbo, u8 start,
|
||||
u8 end)
|
||||
{
|
||||
size_t size = end - start + 7;
|
||||
|
||||
if (size + 2 > wpabuf_tailroom(mbo))
|
||||
return;
|
||||
|
||||
wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
|
||||
wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
|
||||
struct wpabuf *mbo, int subelement)
|
||||
{
|
||||
u8 i, start = 0;
|
||||
struct wpa_mbo_non_pref_channel *start_pref;
|
||||
|
||||
if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
|
||||
if (subelement)
|
||||
wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
|
||||
else
|
||||
wpas_mbo_non_pref_chan_attr_hdr(mbo, 0);
|
||||
return;
|
||||
}
|
||||
start_pref = &wpa_s->non_pref_chan[0];
|
||||
|
||||
for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
|
||||
struct wpa_mbo_non_pref_channel *non_pref = NULL;
|
||||
|
||||
if (i < wpa_s->non_pref_chan_num)
|
||||
non_pref = &wpa_s->non_pref_chan[i];
|
||||
if (!non_pref ||
|
||||
non_pref->oper_class != start_pref->oper_class ||
|
||||
non_pref->reason != start_pref->reason ||
|
||||
non_pref->preference != start_pref->preference) {
|
||||
if (subelement)
|
||||
wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
|
||||
start, i);
|
||||
else
|
||||
wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
|
||||
i);
|
||||
|
||||
if (!non_pref)
|
||||
return;
|
||||
|
||||
start = i;
|
||||
start_pref = non_pref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
|
||||
int add_oce_capa)
|
||||
{
|
||||
struct wpabuf *mbo;
|
||||
int res;
|
||||
|
||||
if (len < MBO_IE_HEADER + 3 + 7 +
|
||||
((wpa_s->enable_oce & OCE_STA) ? 3 : 0))
|
||||
return 0;
|
||||
|
||||
/* Leave room for the MBO IE header */
|
||||
mbo = wpabuf_alloc(len - MBO_IE_HEADER);
|
||||
if (!mbo)
|
||||
return 0;
|
||||
|
||||
/* Add non-preferred channels attribute */
|
||||
wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
|
||||
|
||||
/*
|
||||
* Send cellular capabilities attribute even if AP does not advertise
|
||||
* cellular capabilities.
|
||||
*/
|
||||
wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA);
|
||||
wpabuf_put_u8(mbo, 1);
|
||||
#ifdef ESP_SUPPLICANT
|
||||
wpabuf_put_u8(mbo, MBO_CELL_CAPA_NOT_SUPPORTED);
|
||||
#else
|
||||
wpabuf_put_u8(mbo, wpa_s->mbo_cell_capa);
|
||||
#endif
|
||||
|
||||
/* Add OCE capability indication attribute if OCE is enabled */
|
||||
if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) {
|
||||
wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND);
|
||||
wpabuf_put_u8(mbo, 1);
|
||||
wpabuf_put_u8(mbo, OCE_RELEASE);
|
||||
}
|
||||
|
||||
res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
|
||||
if (!res)
|
||||
wpa_printf(MSG_ERROR, "Failed to add MBO/OCE IE");
|
||||
|
||||
wpabuf_free(mbo);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
|
||||
const u8 *data, size_t len)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
|
||||
/*
|
||||
* Send WNM-Notification Request frame only in case of a change in
|
||||
* non-preferred channels list during association, if the AP supports
|
||||
* MBO.
|
||||
*/
|
||||
if (!wpa_s->current_bss ||
|
||||
!wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
|
||||
return;
|
||||
|
||||
buf = wpabuf_alloc(4 + len);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
|
||||
wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
|
||||
wpa_s->mbo_wnm_token++;
|
||||
if (wpa_s->mbo_wnm_token == 0)
|
||||
wpa_s->mbo_wnm_token++;
|
||||
wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
|
||||
|
||||
wpabuf_put_data(buf, data, len);
|
||||
|
||||
res = wpa_drv_send_action(wpa_s, 0, 0,
|
||||
wpabuf_head(buf), wpabuf_len(buf), 0);
|
||||
if (res < 0)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to send WNM-Notification Request frame with non-preferred channel list");
|
||||
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(512);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
|
||||
wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
|
||||
wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
|
||||
struct wpa_mbo_non_pref_channel *b)
|
||||
{
|
||||
return a->oper_class == b->oper_class && a->chan == b->chan;
|
||||
}
|
||||
|
||||
/*
|
||||
* wpa_non_pref_chan_cmp - Compare two channels for sorting
|
||||
*
|
||||
* In MBO IE non-preferred channel subelement we can put many channels in an
|
||||
* attribute if they are in the same operating class and have the same
|
||||
* preference and reason. To make it easy for the functions that build
|
||||
* the IE attributes and WNM Request subelements, save the channels sorted
|
||||
* by their oper_class and reason.
|
||||
*/
|
||||
static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
|
||||
{
|
||||
const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
|
||||
|
||||
if (a->oper_class != b->oper_class)
|
||||
return (int) a->oper_class - (int) b->oper_class;
|
||||
if (a->reason != b->reason)
|
||||
return (int) a->reason - (int) b->reason;
|
||||
return (int) a->preference - (int) b->preference;
|
||||
}
|
||||
|
||||
|
||||
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
||||
const char *non_pref_chan)
|
||||
{
|
||||
char *cmd, *token, *context = NULL;
|
||||
struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans;
|
||||
size_t num = 0, size = 0;
|
||||
unsigned i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s",
|
||||
non_pref_chan ? non_pref_chan : "N/A");
|
||||
|
||||
/*
|
||||
* The shortest channel configuration is 7 characters - 3 colons and
|
||||
* 4 values.
|
||||
*/
|
||||
if (!non_pref_chan || os_strlen(non_pref_chan) < 7)
|
||||
goto update;
|
||||
|
||||
cmd = os_strdup(non_pref_chan);
|
||||
if (!cmd)
|
||||
return -1;
|
||||
|
||||
while ((token = str_token(cmd, " ", &context))) {
|
||||
struct wpa_mbo_non_pref_channel *chan;
|
||||
int ret;
|
||||
unsigned int _oper_class;
|
||||
unsigned int _chan;
|
||||
unsigned int _preference;
|
||||
unsigned int _reason;
|
||||
|
||||
if (num == size) {
|
||||
size = size ? size * 2 : 1;
|
||||
tmp_chans = os_realloc_array(chans, size,
|
||||
sizeof(*chans));
|
||||
if (!tmp_chans) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Couldn't reallocate non_pref_chan");
|
||||
goto fail;
|
||||
}
|
||||
chans = tmp_chans;
|
||||
}
|
||||
|
||||
chan = &chans[num];
|
||||
|
||||
ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
|
||||
&_chan, &_preference, &_reason);
|
||||
if (ret != 4 ||
|
||||
_oper_class > 255 || _chan > 255 ||
|
||||
_preference > 255 || _reason > 65535 ) {
|
||||
wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
|
||||
token);
|
||||
goto fail;
|
||||
}
|
||||
chan->oper_class = _oper_class;
|
||||
chan->chan = _chan;
|
||||
chan->preference = _preference;
|
||||
chan->reason = _reason;
|
||||
|
||||
if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
|
||||
chan->chan, chan->reason)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid non_pref_chan: oper class %d chan %d reason %d",
|
||||
chan->oper_class, chan->chan, chan->reason);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
if (wpa_non_pref_chan_is_eq(chan, &chans[i]))
|
||||
break;
|
||||
if (i != num) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"oper class %d chan %d is duplicated",
|
||||
chan->oper_class, chan->chan);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
num++;
|
||||
}
|
||||
|
||||
os_free(cmd);
|
||||
|
||||
if (chans) {
|
||||
qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel),
|
||||
wpa_non_pref_chan_cmp);
|
||||
}
|
||||
|
||||
update:
|
||||
os_free(wpa_s->non_pref_chan);
|
||||
wpa_s->non_pref_chan = chans;
|
||||
wpa_s->non_pref_chan_num = num;
|
||||
wpas_mbo_non_pref_chan_changed(wpa_s);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
os_free(chans);
|
||||
os_free(cmd);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
||||
struct non_pref_chan_s *non_pref_chan)
|
||||
{
|
||||
struct wpa_mbo_non_pref_channel *chans = NULL;
|
||||
/*
|
||||
* The shortest channel configuration is 7 characters - 3 colons and
|
||||
* 4 values.
|
||||
*/
|
||||
if (!non_pref_chan)
|
||||
goto update;
|
||||
|
||||
|
||||
chans = os_malloc(sizeof(struct wpa_mbo_non_pref_channel) * non_pref_chan->non_pref_chan_num);
|
||||
os_memcpy(chans, non_pref_chan->chan, sizeof(struct wpa_mbo_non_pref_channel) * non_pref_chan->non_pref_chan_num);
|
||||
|
||||
update:
|
||||
os_free(wpa_s->non_pref_chan);
|
||||
wpa_s->non_pref_chan = chans;
|
||||
if (non_pref_chan)
|
||||
wpa_s->non_pref_chan_num = non_pref_chan->non_pref_chan_num;
|
||||
else
|
||||
wpa_s->non_pref_chan_num = 0;
|
||||
wpas_mbo_non_pref_chan_changed(wpa_s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
|
||||
{
|
||||
u8 *len;
|
||||
|
||||
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
|
||||
len = wpabuf_put(ie, 1);
|
||||
|
||||
wpabuf_put_be24(ie, OUI_WFA);
|
||||
wpabuf_put_u8(ie, MBO_OUI_TYPE);
|
||||
|
||||
wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA);
|
||||
wpabuf_put_u8(ie, 1);
|
||||
#ifdef ESP_SUPPLICANT
|
||||
wpabuf_put_u8(ie, MBO_CELL_CAPA_NOT_SUPPORTED);
|
||||
#else
|
||||
wpabuf_put_u8(ie, wpa_s->mbo_cell_capa);
|
||||
#endif
|
||||
if (wpa_s->enable_oce & OCE_STA) {
|
||||
wpabuf_put_u8(ie, OCE_ATTR_ID_CAPA_IND);
|
||||
wpabuf_put_u8(ie, 1);
|
||||
wpabuf_put_u8(ie, OCE_RELEASE);
|
||||
}
|
||||
*len = (u8 *) wpabuf_put(ie, 0) - len - 1;
|
||||
}
|
||||
|
||||
#ifdef ESP_SUPPLICANT
|
||||
|
||||
static struct
|
||||
wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
|
||||
const u8 *bssid)
|
||||
{
|
||||
struct wpa_bss_tmp_disallowed *bss;
|
||||
|
||||
dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
|
||||
struct wpa_bss_tmp_disallowed, list) {
|
||||
if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
|
||||
return bss;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void wpa_bss_tmp_disallow_timeout(void *timeout_ctx)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = &g_wpa_supp;
|
||||
struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
|
||||
|
||||
/* Make sure the bss is not already freed */
|
||||
dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
|
||||
struct wpa_bss_tmp_disallowed, list) {
|
||||
if (bss == tmp) {
|
||||
dl_list_del(&tmp->list);
|
||||
esp_timer_stop(bss->blacklist_timer);
|
||||
esp_timer_delete(bss->blacklist_timer);
|
||||
os_free(tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
unsigned int sec, int rssi_threshold)
|
||||
{
|
||||
struct wpa_bss_tmp_disallowed *bss;
|
||||
|
||||
bss = wpas_get_disallowed_bss(wpa_s, bssid);
|
||||
if (bss) {
|
||||
esp_timer_stop(bss->blacklist_timer);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
bss = os_malloc(sizeof(*bss));
|
||||
esp_timer_create_args_t blacklist_timer_create = {
|
||||
.callback = &wpa_bss_tmp_disallow_timeout,
|
||||
.arg = bss,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "blacklist_timeout_timer"
|
||||
};
|
||||
esp_timer_create(&blacklist_timer_create, &(bss->blacklist_timer));
|
||||
|
||||
if (!bss) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to allocate memory for temp disallow BSS");
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(bss->bssid, bssid, ETH_ALEN);
|
||||
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
|
||||
|
||||
finish:
|
||||
esp_timer_start_once(bss->blacklist_timer, (sec + 1) * 1e6);
|
||||
}
|
||||
|
||||
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss)
|
||||
{
|
||||
struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
|
||||
|
||||
dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
|
||||
struct wpa_bss_tmp_disallowed, list) {
|
||||
if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
|
||||
disallowed = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!disallowed)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
|
||||
size_t len)
|
||||
{
|
||||
const u8 *pos, *cell_pref = NULL;
|
||||
u8 id, elen;
|
||||
u16 disallowed_sec = 0;
|
||||
|
||||
if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
|
||||
mbo_ie[3] != MBO_OUI_TYPE)
|
||||
return;
|
||||
|
||||
pos = mbo_ie + 4;
|
||||
len -= 4;
|
||||
|
||||
while (len >= 2) {
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
len -= 2;
|
||||
|
||||
if (elen > len)
|
||||
goto fail;
|
||||
|
||||
switch (id) {
|
||||
case MBO_ATTR_ID_CELL_DATA_PREF:
|
||||
if (elen != 1)
|
||||
goto fail;
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
if (wpa_s->mbo_cell_capa ==
|
||||
MBO_CELL_CAPA_AVAILABLE)
|
||||
cell_pref = pos;
|
||||
else
|
||||
#endif
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Station does not support Cellular data connection");
|
||||
break;
|
||||
case MBO_ATTR_ID_TRANSITION_REASON:
|
||||
if (elen != 1)
|
||||
goto fail;
|
||||
|
||||
wpa_s->wnm_mbo_trans_reason_present = 1;
|
||||
wpa_s->wnm_mbo_transition_reason = *pos;
|
||||
break;
|
||||
case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
|
||||
if (elen != 2)
|
||||
goto fail;
|
||||
|
||||
if (wpa_s->wnm_mode &
|
||||
WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Unexpected association retry delay, BSS is terminating");
|
||||
goto fail;
|
||||
} else if (wpa_s->wnm_mode &
|
||||
WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
|
||||
disallowed_sec = WPA_GET_LE16(pos);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Association retry delay: %u",
|
||||
disallowed_sec);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Association retry delay attribute not in disassoc imminent mode");
|
||||
}
|
||||
|
||||
break;
|
||||
case MBO_ATTR_ID_AP_CAPA_IND:
|
||||
case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
|
||||
case MBO_ATTR_ID_CELL_DATA_CAPA:
|
||||
case MBO_ATTR_ID_ASSOC_DISALLOW:
|
||||
case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Attribute %d should not be included in BTM Request frame",
|
||||
id);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
|
||||
id);
|
||||
return;
|
||||
}
|
||||
|
||||
pos += elen;
|
||||
len -= elen;
|
||||
}
|
||||
|
||||
if (cell_pref)
|
||||
wpa_printf(MSG_INFO, "preference=%u",
|
||||
*cell_pref);
|
||||
|
||||
if (wpa_s->wnm_mbo_trans_reason_present)
|
||||
wpa_printf(MSG_INFO, "reason=%u",
|
||||
wpa_s->wnm_mbo_transition_reason);
|
||||
|
||||
if (disallowed_sec && wpa_s->current_bss)
|
||||
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
|
||||
disallowed_sec, 0);
|
||||
|
||||
return;
|
||||
fail:
|
||||
wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
|
||||
id, elen, len);
|
||||
}
|
||||
|
||||
|
||||
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
|
||||
size_t len,
|
||||
enum mbo_transition_reject_reason reason)
|
||||
{
|
||||
u8 reject_attr[3];
|
||||
|
||||
reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
|
||||
reject_attr[1] = 1;
|
||||
reject_attr[2] = reason;
|
||||
|
||||
return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
|
||||
}
|
||||
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
|
||||
{
|
||||
u8 cell_capa[7];
|
||||
|
||||
if (wpa_s->mbo_cell_capa == mbo_cell_capa) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Cellular capability already set to %u",
|
||||
mbo_cell_capa);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->mbo_cell_capa = mbo_cell_capa;
|
||||
|
||||
cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
cell_capa[1] = 5; /* Length */
|
||||
WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
|
||||
cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
|
||||
cell_capa[6] = mbo_cell_capa;
|
||||
|
||||
wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
|
||||
wpa_supplicant_set_default_scan_ies(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, u32 mbo_subtypes)
|
||||
{
|
||||
struct wpabuf *anqp_buf;
|
||||
u8 *len_pos;
|
||||
u8 i;
|
||||
|
||||
if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
|
||||
wpa_printf(MSG_INFO, "MBO: " MACSTR
|
||||
" does not support MBO - cannot request MBO ANQP elements from it",
|
||||
MAC2STR(bss->bssid));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate size for the maximum case - all MBO subtypes are set */
|
||||
anqp_buf = wpabuf_alloc(9 + MAX_MBO_ANQP_SUBTYPE);
|
||||
if (!anqp_buf)
|
||||
return NULL;
|
||||
|
||||
len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(anqp_buf, OUI_WFA);
|
||||
wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
|
||||
|
||||
wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_QUERY_LIST);
|
||||
|
||||
/* The first valid MBO subtype is 1 */
|
||||
for (i = 1; i <= MAX_MBO_ANQP_SUBTYPE; i++) {
|
||||
if (mbo_subtypes & BIT(i))
|
||||
wpabuf_put_u8(anqp_buf, i);
|
||||
}
|
||||
|
||||
gas_anqp_set_element_len(anqp_buf, len_pos);
|
||||
|
||||
return anqp_buf;
|
||||
}
|
||||
|
||||
|
||||
void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, const u8 *sa,
|
||||
const u8 *data, size_t slen)
|
||||
{
|
||||
const u8 *pos = data;
|
||||
u8 subtype;
|
||||
|
||||
if (slen < 1)
|
||||
return;
|
||||
|
||||
subtype = *pos++;
|
||||
slen--;
|
||||
|
||||
switch (subtype) {
|
||||
case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
|
||||
if (slen < 1)
|
||||
break;
|
||||
wpa_msg(wpa_s, MSG_INFO, RX_MBO_ANQP MACSTR
|
||||
" cell_conn_pref=%u", MAC2STR(sa), *pos);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "MBO: Unsupported ANQP subtype %u",
|
||||
subtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
@ -851,8 +851,15 @@ wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
|
||||
goto out;
|
||||
}
|
||||
params->channel = req->channel;
|
||||
#ifdef ESP_SUPPLICANT
|
||||
if (params->channel == 0xff) {
|
||||
/* set it to zero */
|
||||
params->channel = 0;
|
||||
}
|
||||
#endif
|
||||
params->duration = le_to_host16(req->duration);
|
||||
params->duration_mandatory = duration_mandatory;
|
||||
params->mode = req->mode;
|
||||
if (!params->duration) {
|
||||
wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
|
||||
ret = -1;
|
||||
|
@ -191,6 +191,109 @@ static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
static struct wpa_bss *
|
||||
get_mbo_transition_candidate(struct wpa_supplicant *wpa_s,
|
||||
enum mbo_transition_reject_reason *reason)
|
||||
{
|
||||
struct wpa_bss *target = NULL;
|
||||
struct wpa_bss_trans_info params;
|
||||
struct wpa_bss_candidate_info *info = NULL;
|
||||
struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements;
|
||||
u8 *first_candidate_bssid = NULL, *pos;
|
||||
unsigned int i;
|
||||
|
||||
params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason;
|
||||
params.n_candidates = 0;
|
||||
params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN);
|
||||
if (!params.bssid)
|
||||
return NULL;
|
||||
|
||||
pos = params.bssid;
|
||||
for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) {
|
||||
if (nei->is_first)
|
||||
first_candidate_bssid = nei->bssid;
|
||||
if (!nei->acceptable)
|
||||
continue;
|
||||
os_memcpy(pos, nei->bssid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
params.n_candidates++;
|
||||
}
|
||||
|
||||
if (!params.n_candidates)
|
||||
goto end;
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms);
|
||||
#endif
|
||||
if (!info) {
|
||||
/* If failed to get candidate BSS transition status from driver,
|
||||
* get the first acceptable candidate from wpa_supplicant.
|
||||
*/
|
||||
target = wpa_bss_get_bssid(wpa_s, params.bssid);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get the first acceptable candidate from driver */
|
||||
for (i = 0; i < info->num; i++) {
|
||||
if (info->candidates[i].is_accept) {
|
||||
target = wpa_bss_get_bssid(wpa_s,
|
||||
info->candidates[i].bssid);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* If Disassociation Imminent is set and driver rejects all the
|
||||
* candidate select first acceptable candidate which has
|
||||
* rssi > disassoc_imminent_rssi_threshold
|
||||
*/
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
|
||||
for (i = 0; i < info->num; i++) {
|
||||
target = wpa_bss_get_bssid(wpa_s,
|
||||
info->candidates[i].bssid);
|
||||
#ifndef ESP_SUPPLICANT
|
||||
if (target &&
|
||||
(target->level <
|
||||
wpa_s->conf->disassoc_imminent_rssi_threshold))
|
||||
continue;
|
||||
#else
|
||||
if (target)
|
||||
continue;
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* While sending BTM reject use reason code of the first candidate
|
||||
* received in BTM request frame
|
||||
*/
|
||||
if (reason) {
|
||||
for (i = 0; i < info->num; i++) {
|
||||
if (first_candidate_bssid &&
|
||||
os_memcmp(first_candidate_bssid,
|
||||
info->candidates[i].bssid, ETH_ALEN) == 0)
|
||||
{
|
||||
*reason = info->candidates[i].reject_reason;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target = NULL;
|
||||
|
||||
end:
|
||||
os_free(params.bssid);
|
||||
if (info) {
|
||||
os_free(info->candidates);
|
||||
os_free(info);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
|
||||
/* basic function to match candidate profile with current bss */
|
||||
bool wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *current_bss,
|
||||
@ -294,7 +397,14 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
|
||||
nei->acceptable = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (wpa_s->wnm_mbo_trans_reason_present)
|
||||
target = get_mbo_transition_candidate(wpa_s, reason);
|
||||
else
|
||||
target = get_first_acceptable(wpa_s);
|
||||
#else /* CONFIG_MBO */
|
||||
target = get_first_acceptable(wpa_s);
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
if (target) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -506,6 +616,27 @@ static void wnm_send_bss_transition_mgmt_resp(
|
||||
if (status == WNM_BSS_TM_ACCEPT)
|
||||
wnm_add_cand_list(wpa_s, &buf);
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (status != WNM_BSS_TM_ACCEPT &&
|
||||
wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) {
|
||||
u8 mbo[10];
|
||||
size_t ret;
|
||||
|
||||
ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo),
|
||||
reason);
|
||||
if (ret) {
|
||||
if (wpabuf_resize(&buf, ret) < 0) {
|
||||
wpabuf_free(buf);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Failed to allocate memory for MBO IE");
|
||||
return;
|
||||
}
|
||||
|
||||
wpabuf_put_data(buf, mbo, ret);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
res = wpa_drv_send_action(wpa_s, 0, 0,
|
||||
wpabuf_head_u8(buf), wpabuf_len(buf), 0);
|
||||
if (res < 0) {
|
||||
@ -692,8 +823,11 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
|
||||
{
|
||||
unsigned int beacon_int;
|
||||
u8 valid_int;
|
||||
#ifdef CONFIG_MBO
|
||||
const u8 *vendor;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
if (wpa_s->disable_btm)
|
||||
if (wpa_s->disable_mbo_oce || wpa_s->disable_btm)
|
||||
return;
|
||||
|
||||
if (end - pos < 5)
|
||||
@ -721,6 +855,19 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
|
||||
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
|
||||
wpa_s->wnm_dissoc_timer, valid_int);
|
||||
|
||||
#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
|
||||
if (wpa_s->reject_btm_req_reason) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
|
||||
wpa_s->reject_btm_req_reason);
|
||||
wnm_send_bss_transition_mgmt_resp(
|
||||
wpa_s, wpa_s->wnm_dialog_token,
|
||||
wpa_s->reject_btm_req_reason,
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
|
||||
|
||||
pos += 5;
|
||||
|
||||
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
|
||||
|
@ -44,6 +44,9 @@ struct neighbor_report {
|
||||
unsigned int bearing_present:1;
|
||||
unsigned int bss_term_present:1;
|
||||
unsigned int acceptable:1;
|
||||
#ifdef CONFIG_MBO
|
||||
unsigned int is_first:1;
|
||||
#endif /* CONFIG_MBO */
|
||||
struct measurement_pilot *meas_pilot;
|
||||
struct multiple_bssid *mul_bssid;
|
||||
int freq;
|
||||
@ -56,6 +59,13 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
|
||||
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
|
||||
u8 *sender, u8 *payload, size_t len);
|
||||
|
||||
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
|
||||
size_t len);
|
||||
|
||||
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
|
||||
size_t len,
|
||||
enum mbo_transition_reject_reason reason);
|
||||
|
||||
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
|
||||
u8 query_reason,
|
||||
const char *btm_candidates,
|
||||
@ -66,5 +76,7 @@ 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);
|
||||
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss);
|
||||
|
||||
#endif /* WNM_STA_H */
|
||||
|
@ -362,7 +362,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
|
||||
* @key: EAPOL-Key Key Confirmation Key (KCK)
|
||||
|
@ -324,6 +324,8 @@ const char * wpa_cipher_txt(int cipher);
|
||||
|
||||
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
|
||||
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
|
||||
u8 *mic);
|
||||
|
@ -41,6 +41,16 @@ struct rrm_data {
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct wpa_bss_tmp_disallowed {
|
||||
struct dl_list list;
|
||||
u8 bssid[ETH_ALEN];
|
||||
#ifndef ESP_SUPPLICANT
|
||||
int rssi_threshold;
|
||||
#else
|
||||
esp_timer_handle_t blacklist_timer;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
struct beacon_rep_data {
|
||||
u8 token;
|
||||
@ -61,6 +71,7 @@ enum scan_trigger_reason {
|
||||
|
||||
struct wpa_supplicant {
|
||||
int disable_btm;
|
||||
unsigned int disable_mbo_oce;
|
||||
/* rrm ie */
|
||||
uint8_t rrm_ie[5];
|
||||
u8 extend_caps[8];
|
||||
@ -101,10 +112,58 @@ struct wpa_supplicant {
|
||||
u8 wnm_bss_termination_duration[12];
|
||||
struct neighbor_report *wnm_neighbor_report_elements;
|
||||
struct os_reltime wnm_cand_valid_until;
|
||||
#ifdef CONFIG_MBO
|
||||
unsigned int wnm_mbo_trans_reason_present:1;
|
||||
u8 wnm_mbo_transition_reason;
|
||||
/* Multiband operation non-preferred channel */
|
||||
struct wpa_mbo_non_pref_channel {
|
||||
enum mbo_non_pref_chan_reason reason;
|
||||
u8 oper_class;
|
||||
u8 chan;
|
||||
u8 preference;
|
||||
} *non_pref_chan;
|
||||
size_t non_pref_chan_num;
|
||||
u8 mbo_wnm_token;
|
||||
/**
|
||||
* enable_oce - Enable OCE if it is enabled by user and device also
|
||||
* supports OCE.
|
||||
* User can enable OCE with wpa_config's 'oce' parameter as follows -
|
||||
* - Set BIT(0) to enable OCE in non-AP STA mode.
|
||||
* - Set BIT(1) to enable OCE in STA-CFON mode.
|
||||
*/
|
||||
u8 enable_oce;
|
||||
struct dl_list bss_tmp_disallowed;
|
||||
#endif /* CONFIG_MBO */
|
||||
#endif /* CONFIG_WNM */
|
||||
struct rrm_data rrm;
|
||||
struct beacon_rep_data beacon_rep_data;
|
||||
struct os_reltime beacon_rep_scan;
|
||||
};
|
||||
|
||||
#endif
|
||||
struct non_pref_chan_s;
|
||||
|
||||
/* MBO functions */
|
||||
int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
|
||||
int add_oce_capa);
|
||||
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
|
||||
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
|
||||
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
||||
enum mbo_attr_id attr);
|
||||
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
|
||||
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
|
||||
size_t len);
|
||||
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
|
||||
size_t len,
|
||||
enum mbo_transition_reject_reason reason);
|
||||
void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
|
||||
struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, u32 mbo_subtypes);
|
||||
void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_bss *bss, const u8 *sa,
|
||||
const u8 *data, size_t slen);
|
||||
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
|
||||
|
||||
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
||||
struct non_pref_chan_s *non_pref_chan);
|
||||
|
||||
#endif /* WPA_SUPPLICANT_I_H */
|
||||
|
@ -143,6 +143,7 @@ struct wpa_driver_scan_params {
|
||||
u16 duration;
|
||||
|
||||
unsigned int duration_mandatory;
|
||||
u8 mode;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -174,6 +175,20 @@ struct scan_info {
|
||||
u8 scan_start_tsf_bssid[ETH_ALEN];
|
||||
} scan_info;
|
||||
|
||||
struct wpa_bss_trans_info {
|
||||
u8 mbo_transition_reason;
|
||||
u8 n_candidates;
|
||||
u8 *bssid;
|
||||
};
|
||||
|
||||
struct wpa_bss_candidate_info {
|
||||
u8 num;
|
||||
struct candidate_list {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 is_accept;
|
||||
u32 reject_reason;
|
||||
} *candidates;
|
||||
};
|
||||
|
||||
/* driver_common.c */
|
||||
void wpa_scan_results_free(struct wpa_scan_results *res);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wnm.h"
|
||||
#include "esp_rrm.h"
|
||||
#include "esp_mbo.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
@ -40,6 +41,7 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
wifi_event_sta_disconnected_t *disconn = event_data;
|
||||
ESP_LOGI(TAG, "station got disconnected reason=%d", disconn->reason);
|
||||
if (disconn->reason == WIFI_REASON_ROAMING) {
|
||||
ESP_LOGI(TAG, "station roaming, do nothing");
|
||||
} else {
|
||||
@ -323,6 +325,37 @@ static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Example code to update channel preference in MBO */
|
||||
static void clear_chan_preference()
|
||||
{
|
||||
esp_mbo_update_non_pref_chan(NULL);
|
||||
}
|
||||
|
||||
static void update_chan_preference(void)
|
||||
{
|
||||
struct non_pref_chan_s *chans = malloc(sizeof(struct non_pref_chan_s) + 2 * sizeof(struct non_pref_chan));
|
||||
chans->non_pref_chan_num = 2;
|
||||
|
||||
/* first */
|
||||
struct non_pref_chan *chan = &chans->chan[0];
|
||||
chan->reason = NON_PREF_CHAN_REASON_UNSPECIFIED;
|
||||
chan->oper_class = 0x51;
|
||||
chan->chan = 1;
|
||||
chan->preference = 0;
|
||||
|
||||
/* second */
|
||||
chan = &chans->chan[1];
|
||||
chan->reason = NON_PREF_CHAN_REASON_UNSPECIFIED;
|
||||
chan->oper_class = 0x51;
|
||||
chan->chan = 11;
|
||||
chan->preference = 1;
|
||||
|
||||
esp_mbo_update_non_pref_chan(chans);
|
||||
free(chans);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
@ -348,6 +381,8 @@ static void initialise_wifi(void)
|
||||
.password = EXAMPLE_WIFI_PASSWORD,
|
||||
.rm_enabled =1,
|
||||
.btm_enabled =1,
|
||||
.mbo_enabled =1,
|
||||
.pmf_cfg.capable = 1,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
CONFIG_WPA_11KV_SUPPORT=y
|
||||
CONFIG_WPA_SCAN_CACHE=y
|
||||
CONFIG_WPA_MBO_SUPPORT=y
|
||||
|
@ -1229,7 +1229,6 @@ components/esp_wifi/include/esp_wifi.h
|
||||
components/esp_wifi/include/esp_wifi_crypto_types.h
|
||||
components/esp_wifi/include/esp_wifi_default.h
|
||||
components/esp_wifi/include/esp_wifi_netif.h
|
||||
components/esp_wifi/include/esp_wifi_types.h
|
||||
components/esp_wifi/include/smartconfig_ack.h
|
||||
components/esp_wifi/src/coexist.c
|
||||
components/esp_wifi/src/lib_printf.c
|
||||
@ -2997,24 +2996,18 @@ components/wifi_provisioning/src/wifi_provisioning_priv.h
|
||||
components/wifi_provisioning/src/wifi_scan.c
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_dpp.h
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_rrm.h
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_wnm.h
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_wpa.h
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_wpa2.h
|
||||
components/wpa_supplicant/esp_supplicant/include/esp_wps.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_common.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_common_i.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_dpp.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_hostap.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_hostap.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_scan.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_scan_i.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpa2.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpa3_i.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpa_err.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.c
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h
|
||||
components/wpa_supplicant/esp_supplicant/src/esp_wps.c
|
||||
@ -3045,6 +3038,7 @@ components/wpa_supplicant/src/common/eapol_common.h
|
||||
components/wpa_supplicant/src/common/ieee802_11_common.c
|
||||
components/wpa_supplicant/src/common/ieee802_11_common.h
|
||||
components/wpa_supplicant/src/common/ieee802_11_defs.h
|
||||
components/wpa_supplicant/src/common/mbo.c
|
||||
components/wpa_supplicant/src/common/rrm.c
|
||||
components/wpa_supplicant/src/common/rrm.h
|
||||
components/wpa_supplicant/src/common/sae.c
|
||||
|
Loading…
x
Reference in New Issue
Block a user