esp_wifi: Add support for MBO certification

This commit is contained in:
Kapil Gupta
2021-09-29 10:37:59 +05:30
committed by bot
parent e35a87f723
commit 834afad47e
28 changed files with 1605 additions and 193 deletions

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");
* 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;
}