Merge branch 'feature/mbo_support' into 'master'

esp_wifi: Add support for MBO certification

Closes WIFI-3777

See merge request espressif/esp-idf!12650
This commit is contained in:
Jiang Jiang Jian
2021-10-09 16:31:31 +00:00
28 changed files with 1605 additions and 193 deletions

View File

@@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2015-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. * SPDX-License-Identifier: Apache-2.0
// 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_WIFI_TYPES_H__ #ifndef __ESP_WIFI_TYPES_H__
@@ -80,6 +72,7 @@ typedef enum {
WIFI_REASON_ASSOC_NOT_AUTHED = 9, WIFI_REASON_ASSOC_NOT_AUTHED = 9,
WIFI_REASON_DISASSOC_PWRCAP_BAD = 10, WIFI_REASON_DISASSOC_PWRCAP_BAD = 10,
WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11, WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11,
WIFI_REASON_BSS_TRANSITION_DISASSOC = 12,
WIFI_REASON_IE_INVALID = 13, WIFI_REASON_IE_INVALID = 13,
WIFI_REASON_MIC_FAILURE = 14, WIFI_REASON_MIC_FAILURE = 14,
WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, 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. */ 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 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 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; } wifi_sta_config_t;
/** @brief Configuration data for ESP32 AP or STA. /** @brief Configuration data for ESP32 AP or STA.

View File

@@ -154,8 +154,13 @@ if(CONFIG_WPA_11KV_SUPPORT)
else() else()
set(roaming_src "") set(roaming_src "")
endif() 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 INCLUDE_DIRS include port/include esp_supplicant/include
PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src
PRIV_REQUIRES mbedtls esp_timer) PRIV_REQUIRES mbedtls esp_timer)
@@ -190,4 +195,7 @@ if(CONFIG_WPA_WPS_STRICT)
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_STRICT) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPS_STRICT)
endif() 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) set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

View File

@@ -59,12 +59,18 @@ menu "Supplicant"
and on the radio environment. Current implementation adds beacon report, and on the radio environment. Current implementation adds beacon report,
link measurement, neighbor report. link measurement, neighbor report.
if WPA_11KV_SUPPORT menuconfig WPA_SCAN_CACHE
config WPA_SCAN_CACHE
bool "Keep scan results in cache" bool "Keep scan results in cache"
depends on WPA_11KV_SUPPORT
default n default n
help help
Keep scan results in cache, if not enabled, those Keep scan results in cache, if not enabled, those
will be flushed immediately. will be flushed immediately.
endif
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 endmenu

View File

@@ -70,6 +70,9 @@ ifneq ($(CONFIG_WPA_11KV_SUPPORT), y)
esp_supplicant/src/esp_common.o \ esp_supplicant/src/esp_common.o \
esp_supplicant/src/esp_scan.o esp_supplicant/src/esp_scan.o
endif 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 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 ifdef CONFIG_WPA_WPS_STRICT
CFLAGS += -DCONFIG_WPS_STRICT CFLAGS += -DCONFIG_WPS_STRICT
endif endif
ifdef CONFIG_WPA_MBO_SUPPORT
CFLAGS += -DCONFIG_MBO
endif

View 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

View File

@@ -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"); * SPDX-License-Identifier: Apache-2.0
* 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 #ifndef _ESP_WNM_H
@@ -29,11 +19,13 @@ enum btm_query_reason {
REASON_UNSPECIFIED = 0, REASON_UNSPECIFIED = 0,
REASON_FRAME_LOSS = 1, REASON_FRAME_LOSS = 1,
REASON_DELAY = 2, REASON_DELAY = 2,
REASON_QOS_CAPACITY = 3, REASON_BANDWIDTH = 3,
REASON_FIRST_ASSOC = 4, REASON_LOAD_BALANCE = 4,
REASON_LOAD_BALALNCE = 5, REASON_RSSI = 5,
REASON_BETTER_AP = 6, REASON_RETRANSMISSIONS = 6,
REASON_CURRENT_DEAUTH = 7, REASON_INTERFERENCE = 7,
REASON_GRAY_ZONE = 8,
REASON_PREMIUM_AP = 9,
}; };
/** /**

View File

@@ -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"); * SPDX-License-Identifier: Apache-2.0
* 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/includes.h"
@@ -37,7 +27,7 @@ static void *s_supplicant_task_hdl = NULL;
static void *s_supplicant_evt_queue = NULL; static void *s_supplicant_evt_queue = NULL;
static void *s_supplicant_api_lock = NULL; static void *s_supplicant_api_lock = NULL;
static int esp_handle_action_frm(u8 *frame, size_t len, static int handle_action_frm(u8 *frame, size_t len,
u8 *sender, u32 rssi, u8 channel) u8 *sender, u32 rssi, u8 channel)
{ {
struct ieee_mgmt_frame *frm = os_malloc(sizeof(struct ieee_mgmt_frame) + len); 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; 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) u8 *payload, size_t len, u32 rssi)
{ {
if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) { 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 category;
u8 bssid[ETH_ALEN]; 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) { if (category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action(wpa_s, sender, payload, len); ieee802_11_rx_wnm_action(wpa_s, sender, payload, len);
} else if (category == WLAN_ACTION_RADIO_MEASUREMENT) { } 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; return 0;
} }
static void esp_btm_rrm_task(void *pvParameters) static void btm_rrm_task(void *pvParameters)
{ {
supplicant_event_t *evt; supplicant_event_t *evt;
bool task_del = false; bool task_del = false;
@@ -120,7 +110,7 @@ static void esp_btm_rrm_task(void *pvParameters)
case SIG_SUPPLICANT_RX_ACTION: case SIG_SUPPLICANT_RX_ACTION:
{ {
struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data; 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); os_free(frm);
break; break;
} }
@@ -153,7 +143,7 @@ static void esp_btm_rrm_task(void *pvParameters)
vTaskDelete(NULL); 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; 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"); 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); wpa_s->type &= ~(1 << WLAN_FC_STYPE_ACTION);
/* subtype is defined only for action frame */ /* subtype is defined only for action frame */
@@ -193,7 +183,7 @@ static void esp_register_action_frame(struct wpa_supplicant *wpa_s)
esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype); 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, static void supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) int32_t event_id, void* event_data)
{ {
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
@@ -215,12 +205,12 @@ 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); ieee802_11_parse_elems(wpa_s, ie, bss->ie_len);
wpa_bss_flush(wpa_s); wpa_bss_flush(wpa_s);
/* Register for action frames */ /* Register for action frames */
esp_register_action_frame(wpa_s); register_action_frame(wpa_s);
/* clear set bssid flag */ /* 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, static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) int32_t event_id, void* event_data)
{ {
struct wpa_supplicant *wpa_s = &g_wpa_supp; struct wpa_supplicant *wpa_s = &g_wpa_supp;
@@ -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) void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
{ {
struct wpa_supplicant *wpa_s = &g_wpa_supp; struct wpa_supplicant *wpa_s = &g_wpa_supp;
s_supplicant_evt_queue = xQueueCreate(3, sizeof(supplicant_event_t)); 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(); s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex();
if (!s_supplicant_api_lock) { 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); wpas_clear_beacon_rep_data(wpa_s);
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, 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_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->type = 0;
wpa_s->subtype = 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) void esp_supplicant_common_deinit(void)
@@ -268,28 +304,38 @@ void esp_supplicant_common_deinit(void)
wpas_rrm_reset(wpa_s); wpas_rrm_reset(wpa_s);
wpas_clear_beacon_rep_data(wpa_s); wpas_clear_beacon_rep_data(wpa_s);
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, 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_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, int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
void *cb_ctx) void *cb_ctx)
{ {
struct wpa_supplicant *wpa_s = &g_wpa_supp;
struct wpa_ssid_value wpa_ssid = {0}; struct wpa_ssid_value wpa_ssid = {0};
struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
os_memcpy(wpa_ssid.ssid, ssid->ssid, ssid->len); os_memcpy(wpa_ssid.ssid, ssid->ssid, ssid->len);
wpa_ssid.ssid_len = 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, int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
const char *btm_candidates, const char *btm_candidates,
int cand_list) int cand_list)
{ {
struct wpa_supplicant *wpa_s = &g_wpa_supp; return wnm_send_bss_transition_mgmt_query(&g_wpa_supp, query_reason, btm_candidates, cand_list);
return wnm_send_bss_transition_mgmt_query(wpa_s, 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, 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 */ /* We only support roaming in same ESS, therefore only bssid setting is needed */
os_memcpy(config->sta.bssid, bss->bssid, ETH_ALEN); os_memcpy(config->sta.bssid, bss->bssid, ETH_ALEN);
config->sta.bssid_set = 1; 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); esp_wifi_set_config(WIFI_IF_STA, config);
os_free(config); os_free(config);
esp_wifi_connect(); 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 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_LINK_MEASUREMENT;
*pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
@@ -326,10 +379,147 @@ void esp_set_rm_enabled_ie(void)
#endif #endif
WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE; WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE;
/* set rm enabled IE if enabled in driver */ os_memcpy(ie, rrm_ie, sizeof(rrm_ie));
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); 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) 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(); SUPPLICANT_API_UNLOCK();
return 0; 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;
}

View File

@@ -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"); * SPDX-License-Identifier: Apache-2.0
* 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 #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_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_get_tx_power(uint8_t *tx_power);
void esp_supplicant_common_init(struct wpa_funcs *wpa_cb); void esp_supplicant_common_init(struct wpa_funcs *wpa_cb);
void esp_supplicant_common_deinit(void); void esp_supplicant_common_deinit(void);
void esp_set_scan_ie(void);
void esp_set_assoc_ie(void);
#else #else
#include "esp_rrm.h" #include "esp_rrm.h"
#include "esp_wnm.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, int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
void *cb_ctx) void *cb_ctx)
{ {
@@ -77,5 +64,9 @@ int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
return -1; return -1;
} }
int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
{
return -1;
}
#endif #endif
#endif #endif

View File

@@ -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"); * SPDX-License-Identifier: Apache-2.0
* 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/includes.h"
@@ -32,7 +22,7 @@
extern struct wpa_supplicant g_wpa_supp; extern struct wpa_supplicant g_wpa_supp;
static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base, static void scan_done_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) int32_t event_id, void* event_data)
{ {
struct wpa_supplicant *wpa_s = &g_wpa_supp; 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); 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); 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; uint16_t number = 1;
wifi_ap_record_t ap_records; 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) { if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) {
wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf); wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf);
} else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) { } 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) { if (wpa_s->scanning) {
esp_supp_scan_done_cleanup(wpa_s); scan_done_cleanup(wpa_s);
} }
wpa_bss_update_end(wpa_s); wpa_bss_update_end(wpa_s);
#ifndef SCAN_CACHE_SUPPORTED #ifndef SCAN_CACHE_SUPPORTED
@@ -101,7 +91,7 @@ void esp_scan_init(struct wpa_supplicant *wpa_s)
wpa_bss_init(wpa_s); wpa_bss_init(wpa_s);
wpa_s->last_scan_res = NULL; wpa_s->last_scan_res = NULL;
esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, 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) 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); os_free(wpa_s->last_scan_res);
wpa_s->last_scan_res = NULL; wpa_s->last_scan_res = NULL;
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_SCAN_DONE, 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, 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; res->level = rssi;
os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN); os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN);
res->parent_tsf = current_tsf - wpa_s->scan_start_tsf; res->parent_tsf = current_tsf - wpa_s->scan_start_tsf;
if (type == WLAN_FC_STYPE_PROBE_RESP)
res->ie_len = len; res->ie_len = len;
else if (type == WLAN_FC_STYPE_BEACON)
res->beacon_ie_len = len;
ptr += sizeof(struct wpa_scan_res); ptr += sizeof(struct wpa_scan_res);
@@ -173,7 +160,7 @@ int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
return 0; return 0;
} }
static int esp_issue_scan(struct wpa_supplicant *wpa_s, static int issue_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *scan_params) struct wpa_driver_scan_params *scan_params)
{ {
wifi_scan_config_t *params = NULL; wifi_scan_config_t *params = NULL;
@@ -203,9 +190,13 @@ static int esp_issue_scan(struct wpa_supplicant *wpa_s,
goto cleanup; goto cleanup;
} }
os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len); os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len);
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
} else } else
if (scan_params->mode == BEACON_REPORT_MODE_PASSIVE) {
params->scan_type = WIFI_SCAN_TYPE_PASSIVE; params->scan_type = WIFI_SCAN_TYPE_PASSIVE;
} else {
params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
}
if (scan_params->bssid) { if (scan_params->bssid) {
params->bssid = os_zalloc(ETH_ALEN); params->bssid = os_zalloc(ETH_ALEN);
@@ -260,7 +251,7 @@ cleanup:
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params) 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) void wpa_scan_results_free(struct wpa_scan_results *res)

View File

@@ -1,16 +1,8 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2019-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. * SPDX-License-Identifier: Apache-2.0
// 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_WIFI_DRIVER_H_ #ifndef _ESP_WIFI_DRIVER_H_
#define _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 */ /* wifi_appie_t is in rom code and can't be changed anymore, use wifi_appie_ram_t for new app IEs */
typedef enum { typedef enum {
WIFI_APPIE_RM_ENABLED_CAPS = WIFI_APPIE_MAX, WIFI_APPIE_RAM_MAX = WIFI_APPIE_MAX,
WIFI_APPIE_RAM_MAX,
} wifi_appie_ram_t; } wifi_appie_ram_t;
enum { 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 (*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); 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); void (*wpa_config_done)(void);
bool (*wpa_sta_profile_match)(u8 *bssid);
}; };
struct wpa2_funcs { 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); 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, 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); 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_ */ #endif /* _ESP_WIFI_DRIVER_H_ */

View File

@@ -1,16 +1,8 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2019-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. * SPDX-License-Identifier: Apache-2.0
// 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/includes.h"
#include "utils/common.h" #include "utils/common.h"
@@ -123,6 +115,8 @@ bool wpa_attach(void)
if(ret) { if(ret) {
ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK); 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; return ret;
} }
@@ -185,7 +179,7 @@ void wpa_sta_connect(uint8_t *bssid)
void wpa_config_done(void) void wpa_config_done(void)
{ {
/* used in future for setting scan and assoc IEs */ /* 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) 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) static inline void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
{ {
wpa_cb->wpa_sta_rx_mgmt = NULL; wpa_cb->wpa_sta_rx_mgmt = NULL;
wpa_cb->wpa_sta_profile_match = NULL;
} }
static inline void esp_supplicant_common_deinit(void) static inline void esp_supplicant_common_deinit(void)
{ {

View File

@@ -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 && return !is_zero_ether_addr(bss->bssid) && wpa_s->current_bss->bssid &&
(os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0); (os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0);
#endif #else
return 0; return 0;
#endif
} }
static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) 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->ssid_len = ssid_len;
bss->ie_len = res->ie_len; bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_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, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); 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); dl_list_del(&bss->list);
if (bss->ie_len + bss->beacon_ie_len >= if (bss->ie_len + bss->beacon_ie_len >=
res->ie_len + res->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->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len; bss->beacon_ie_len = res->beacon_ie_len;
} else { } else {
@@ -258,7 +259,7 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
if (wpa_s->current_bss == bss) if (wpa_s->current_bss == bss)
wpa_s->current_bss = nbss; wpa_s->current_bss = nbss;
bss = nbss; bss = nbss;
os_memcpy(bss + 1, res + 1, os_memcpy(bss->ies, res + 1,
res->ie_len + res->beacon_ie_len); res->ie_len + res->beacon_ie_len);
bss->ie_len = res->ie_len; bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_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); 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) 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), return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),

View File

@@ -58,8 +58,14 @@ struct wpa_bss {
size_t beacon_ie_len; size_t beacon_ie_len;
/* followed by ie_len octets of IEs */ /* followed by ie_len octets of IEs */
/* followed by beacon_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_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res, 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, struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid); const u8 *bssid);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie); 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); 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 * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s,
struct wpa_bss *prev_bss); struct wpa_bss *prev_bss);

View File

@@ -37,6 +37,42 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
return NULL; 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, int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len) size_t nei_rep_len)
{ {

View File

@@ -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); 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_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len);
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab); 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); u8 get_operating_class(u8 chan, int sec_channel);
#endif /* IEEE802_11_COMMON_H */ #endif /* IEEE802_11_COMMON_H */

View File

@@ -212,6 +212,7 @@
#define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57 #define WLAN_EID_RIC_DATA 57
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
#define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_WAPI 68 #define WLAN_EID_WAPI 68
@@ -536,6 +537,13 @@ struct ieee80211_ht_operation {
/* 2 - Reserved */ /* 2 - Reserved */
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 #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 * WMM Information Element (used in (Re)Association Request frames; may also be
* used in Beacon frames) * used in Beacon frames)
@@ -622,6 +630,45 @@ enum wmm_ac {
WMM_AC_NUM = 4 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 */ /* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
/* Table 4-21: Transition Rejection Reason Code Field Values */ /* Table 4-21: Transition Rejection Reason Code Field Values */
enum mbo_transition_reject_reason { enum mbo_transition_reject_reason {
@@ -634,6 +681,12 @@ enum mbo_transition_reject_reason {
MBO_TRANSITION_REJECT_REASON_SERVICES = 6, 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 */ /* IEEE 802.11v - WNM Action field values */
enum wnm_action { enum wnm_action {
WNM_EVENT_REQ = 0, WNM_EVENT_REQ = 0,

View 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

View File

@@ -851,8 +851,15 @@ wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
goto out; goto out;
} }
params->channel = req->channel; 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 = le_to_host16(req->duration);
params->duration_mandatory = duration_mandatory; params->duration_mandatory = duration_mandatory;
params->mode = req->mode;
if (!params->duration) { if (!params->duration) {
wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0"); wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
ret = -1; ret = -1;

View File

@@ -191,6 +191,109 @@ static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s)
return NULL; 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, &params);
#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 */ /* basic function to match candidate profile with current bss */
bool wpa_scan_res_match(struct wpa_supplicant *wpa_s, bool wpa_scan_res_match(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss, 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; 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); target = get_first_acceptable(wpa_s);
#else /* CONFIG_MBO */
target = get_first_acceptable(wpa_s);
#endif /* CONFIG_MBO */
if (target) { if (target) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
@@ -506,6 +616,27 @@ static void wnm_send_bss_transition_mgmt_resp(
if (status == WNM_BSS_TM_ACCEPT) if (status == WNM_BSS_TM_ACCEPT)
wnm_add_cand_list(wpa_s, &buf); 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, res = wpa_drv_send_action(wpa_s, 0, 0,
wpabuf_head_u8(buf), wpabuf_len(buf), 0); wpabuf_head_u8(buf), wpabuf_len(buf), 0);
if (res < 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; unsigned int beacon_int;
u8 valid_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; return;
if (end - pos < 5) 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_dialog_token, wpa_s->wnm_mode,
wpa_s->wnm_dissoc_timer, valid_int); 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; pos += 5;
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {

View File

@@ -44,6 +44,9 @@ struct neighbor_report {
unsigned int bearing_present:1; unsigned int bearing_present:1;
unsigned int bss_term_present:1; unsigned int bss_term_present:1;
unsigned int acceptable:1; unsigned int acceptable:1;
#ifdef CONFIG_MBO
unsigned int is_first:1;
#endif /* CONFIG_MBO */
struct measurement_pilot *meas_pilot; struct measurement_pilot *meas_pilot;
struct multiple_bssid *mul_bssid; struct multiple_bssid *mul_bssid;
int freq; 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, void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
u8 *sender, u8 *payload, size_t len); 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, int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
u8 query_reason, u8 query_reason,
const char *btm_candidates, 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, void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, char *ssid, struct wpa_bss *bss, char *ssid,
int after_new_scan); int after_new_scan);
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss);
#endif /* WNM_STA_H */ #endif /* WNM_STA_H */

View File

@@ -362,7 +362,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
return 0; return 0;
} }
/** /**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK) * @key: EAPOL-Key Key Confirmation Key (KCK)

View File

@@ -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, int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data); 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, int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 *mic); u8 *mic);

View File

@@ -41,6 +41,16 @@ struct rrm_data {
u8 dst_addr[ETH_ALEN]; 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 #define SSID_MAX_LEN 32
struct beacon_rep_data { struct beacon_rep_data {
u8 token; u8 token;
@@ -61,6 +71,7 @@ enum scan_trigger_reason {
struct wpa_supplicant { struct wpa_supplicant {
int disable_btm; int disable_btm;
unsigned int disable_mbo_oce;
/* rrm ie */ /* rrm ie */
uint8_t rrm_ie[5]; uint8_t rrm_ie[5];
u8 extend_caps[8]; u8 extend_caps[8];
@@ -101,10 +112,58 @@ struct wpa_supplicant {
u8 wnm_bss_termination_duration[12]; u8 wnm_bss_termination_duration[12];
struct neighbor_report *wnm_neighbor_report_elements; struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until; 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 */ #endif /* CONFIG_WNM */
struct rrm_data rrm; struct rrm_data rrm;
struct beacon_rep_data beacon_rep_data; struct beacon_rep_data beacon_rep_data;
struct os_reltime beacon_rep_scan; 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 */

View File

@@ -143,6 +143,7 @@ struct wpa_driver_scan_params {
u16 duration; u16 duration;
unsigned int duration_mandatory; unsigned int duration_mandatory;
u8 mode;
}; };
/** /**
@@ -174,6 +175,20 @@ struct scan_info {
u8 scan_start_tsf_bssid[ETH_ALEN]; u8 scan_start_tsf_bssid[ETH_ALEN];
} scan_info; } 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 */ /* driver_common.c */
void wpa_scan_results_free(struct wpa_scan_results *res); void wpa_scan_results_free(struct wpa_scan_results *res);

View File

@@ -6,6 +6,7 @@
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_wnm.h" #include "esp_wnm.h"
#include "esp_rrm.h" #include "esp_rrm.h"
#include "esp_mbo.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_system.h" #include "esp_system.h"
@@ -40,6 +41,7 @@ static void event_handler(void* arg, esp_event_base_t event_base,
esp_wifi_connect(); esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t *disconn = event_data; wifi_event_sta_disconnected_t *disconn = event_data;
ESP_LOGI(TAG, "station got disconnected reason=%d", disconn->reason);
if (disconn->reason == WIFI_REASON_ROAMING) { if (disconn->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "station roaming, do nothing"); ESP_LOGI(TAG, "station roaming, do nothing");
} else { } else {
@@ -323,6 +325,37 @@ static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base,
} }
#endif #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) static void initialise_wifi(void)
{ {
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
@@ -348,6 +381,8 @@ static void initialise_wifi(void)
.password = EXAMPLE_WIFI_PASSWORD, .password = EXAMPLE_WIFI_PASSWORD,
.rm_enabled =1, .rm_enabled =1,
.btm_enabled =1, .btm_enabled =1,
.mbo_enabled =1,
.pmf_cfg.capable = 1,
}, },
}; };

View File

@@ -1,2 +1,3 @@
CONFIG_WPA_11KV_SUPPORT=y CONFIG_WPA_11KV_SUPPORT=y
CONFIG_WPA_SCAN_CACHE=y CONFIG_WPA_SCAN_CACHE=y
CONFIG_WPA_MBO_SUPPORT=y

View File

@@ -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_crypto_types.h
components/esp_wifi/include/esp_wifi_default.h components/esp_wifi/include/esp_wifi_default.h
components/esp_wifi/include/esp_wifi_netif.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/include/smartconfig_ack.h
components/esp_wifi/src/coexist.c components/esp_wifi/src/coexist.c
components/esp_wifi/src/lib_printf.c components/esp_wifi/src/lib_printf.c
@@ -2979,24 +2978,18 @@ components/wifi_provisioning/src/wifi_provisioning_priv.h
components/wifi_provisioning/src/wifi_scan.c components/wifi_provisioning/src/wifi_scan.c
components/wpa_supplicant/esp_supplicant/include/esp_dpp.h 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_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_wpa.h
components/wpa_supplicant/esp_supplicant/include/esp_wpa2.h components/wpa_supplicant/esp_supplicant/include/esp_wpa2.h
components/wpa_supplicant/esp_supplicant/include/esp_wps.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.c
components/wpa_supplicant/esp_supplicant/src/esp_dpp_i.h 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.c
components/wpa_supplicant/esp_supplicant/src/esp_hostap.h 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_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_wpa2.c
components/wpa_supplicant/esp_supplicant/src/esp_wpa3.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_wpa3_i.h
components/wpa_supplicant/esp_supplicant/src/esp_wpa_err.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.c
components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h components/wpa_supplicant/esp_supplicant/src/esp_wpas_glue.h
components/wpa_supplicant/esp_supplicant/src/esp_wps.c components/wpa_supplicant/esp_supplicant/src/esp_wps.c
@@ -3027,6 +3020,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.c
components/wpa_supplicant/src/common/ieee802_11_common.h components/wpa_supplicant/src/common/ieee802_11_common.h
components/wpa_supplicant/src/common/ieee802_11_defs.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.c
components/wpa_supplicant/src/common/rrm.h components/wpa_supplicant/src/common/rrm.h
components/wpa_supplicant/src/common/sae.c components/wpa_supplicant/src/common/sae.c