MCUXpresso_MIMXRT1021xxxxx/middleware/wifi_nxp/wifidriver/mlan_11v.c
Yilin Sun 763d32be90
Updated SDK to v2.15.000
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-03-15 22:23:36 +08:00

355 lines
12 KiB
C

/** @file mlan_11v.c
*
* @brief This file provides functions for process 11v(BTM) frames
*
* Copyright 2022 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/********************************************************
Change log:
08/11/2022: initial version
********************************************************/
#include <mlan_api.h>
#include "wifi-sdio.h"
#ifdef CONFIG_11V
#define BTM_RESP_BUF_SIZE 200
#define WNM_BTM_QUERY_BUF_SIZE 10U
#define WLAN_FC_TYPE_MGMT 0
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
static void wlan_wnm_parse_neighbor_report(t_u8 *pos, t_u8 len, struct wnm_neighbor_report *rep)
{
t_u8 remain_len = 0;
if (len < (t_u8)13U)
{
wifi_d("WNM: This neighbor report is too short");
}
(void)memcpy(rep->bssid, pos, MLAN_MAC_ADDR_LENGTH);
rep->bssid_info = wlan_cpu_to_le32(*(t_u32 *)(void *)(pos + MLAN_MAC_ADDR_LENGTH));
rep->reg_class = *(pos + 10);
rep->channel = *(pos + 11);
rep->PhyType = *(pos + 12);
pos += 13;
remain_len = (t_u8)(len - (t_u8)13U);
while (remain_len >= (t_u8)2U)
{
t_u8 e_id, e_len;
e_id = *pos++;
e_len = *pos++;
remain_len -= (t_u8)2U;
if (e_len > remain_len)
{
wifi_d("WNM: neighbor report length not matched");
break;
}
switch (e_id)
{
case MGMT_WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
if (e_len < (t_u8)1U)
{
break;
}
rep->prefer = pos[0];
rep->prefer_select = 1;
break;
default:
(void)PRINTF("UNKNOWN nbor Report e id\r\n");
break;
}
remain_len -= e_len;
pos += e_len;
}
}
void wlan_send_mgmt_wnm_btm_resp(t_u8 dialog_token,
enum wnm_btm_status_code status,
t_u8 *dst_addr,
t_u8 *src_addr,
t_u8 *target_bssid,
t_u8 *tag_nr,
t_u8 tag_len,
bool protect)
{
wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
IEEEtypes_FrameCtl_t *mgmt_fc_p = MNULL;
t_u8 *pos = MNULL;
t_u16 pkt_len = 0;
pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(
SUBTYPE_ACTION, (mlan_802_11_mac_addr *)(void *)dst_addr, (mlan_802_11_mac_addr *)(void *)src_addr,
(mlan_802_11_mac_addr *)(void *)dst_addr, sizeof(wlan_mgmt_pkt) + (size_t)BTM_RESP_BUF_SIZE);
if (pmgmt_pkt_hdr == MNULL)
{
wifi_d("No memory available for BTM resp");
return;
}
mgmt_fc_p = (IEEEtypes_FrameCtl_t *)(void *)&pmgmt_pkt_hdr->wlan_header.frm_ctl;
if (protect)
{
mgmt_fc_p->wep = 1;
}
/* 802.11 management body */
pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_WNM;
pos[1] = (t_u8)IEEE_MGMT_WNM_BTM_RESPONSE;
pos[2] = dialog_token;
pos[3] = (t_u8)status;
pos[4] = 0; /* delay */
pos += 5;
if (target_bssid != NULL)
{
(void)memcpy((void *)pos, (const void *)target_bssid, (size_t)MLAN_MAC_ADDR_LENGTH);
pos += 6;
}
else if (status == WNM_BTM_ACCEPT)
{
(void)memcpy((void *)pos, "\0\0\0\0\0\0", (size_t)MLAN_MAC_ADDR_LENGTH);
pos += 6;
}
else
{
/* Do nothing */
}
if (status == WNM_BTM_ACCEPT && tag_nr != NULL)
{
(void)memcpy((void *)pos, (const void *)tag_nr, (size_t)tag_len);
pos += tag_len;
}
pkt_len = (t_u16)(pos - (t_u8 *)pmgmt_pkt_hdr);
pmgmt_pkt_hdr->frm_len = (t_u16)((t_u16)pkt_len - sizeof(t_u16));
(void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
os_mem_free(pmgmt_pkt_hdr);
}
static bool wlan_11v_find_in_channels(t_u8 *channels, t_u8 entry_num, t_u8 chan)
{
t_u8 i;
for (i = 0; i < entry_num; i++)
{
if (channels[i] == chan)
{
return true;
}
}
return false;
}
/********************************************************
Global functions
********************************************************/
/**
* @brief This function process BTM request frame
*
* @param pos BTM request frame head
* @param end end of frame
* @param src_addr source address
*
*/
void wlan_process_mgmt_wnm_btm_req(t_u8 *pos, t_u8 *end, t_u8 *src_addr, t_u8 *dest_addr, bool protect)
{
t_u8 dialog_token;
t_u8 wnm_num_neighbor_report = 0, neighbor_index = 0;
t_u8 btm_mode;
t_u8 prefer_old = 0, prefer_select = 0;
t_u8 *ptagnr = NULL;
t_u8 tagnr_len = 0;
wlan_nlist_report_param *pnlist_rep_param = MNULL;
t_u8 entry_num = 0;
if (end - pos < 5)
{
return;
}
pnlist_rep_param = (wlan_nlist_report_param *)os_mem_alloc(sizeof(wlan_nlist_report_param));
if (pnlist_rep_param == MNULL)
{
wifi_e("11v nlist report param buffer alloc failed %d", sizeof(wlan_nlist_report_param));
return;
}
(void)memset(pnlist_rep_param, 0, sizeof(wlan_nlist_report_param));
dialog_token = pos[0];
btm_mode = pos[1];
pos += 5;
if ((btm_mode & IEEE_WNM_BTM_REQUEST_BSS_TERMINATION_INCLUDED) != 0U)
{
pos += 12; /* BSS Termination Duration */
}
if ((btm_mode & IEEE_WNM_BTM_REQUEST_PREFERENCE_CAND_LIST_INCLUDED) != 0U)
{
struct wnm_neighbor_report *preport =
os_mem_calloc((size_t)WLAN_WNM_MAX_NEIGHBOR_REPORT * sizeof(struct wnm_neighbor_report));
if (preport == NULL)
{
wifi_e("No memory available for neighbor report.");
os_mem_free((void *)pnlist_rep_param);
return;
}
while (end - pos >= 2 && wnm_num_neighbor_report < (t_u8)WLAN_WNM_MAX_NEIGHBOR_REPORT)
{
t_u8 tag = *pos++;
t_u8 len = *pos++;
if ((int)len > (end - pos))
{
wifi_d("WNM: Truncated BTM request");
os_mem_free((void *)preport);
os_mem_free((void *)pnlist_rep_param);
return;
}
if (tag == (t_u8)NEIGHBOR_REPORT)
{
struct wnm_neighbor_report *rep;
rep = &preport[wnm_num_neighbor_report];
wlan_wnm_parse_neighbor_report(pos, len, rep);
if (!wlan_11v_find_in_channels(pnlist_rep_param->channels, entry_num, rep->channel))
{
pnlist_rep_param->channels[entry_num] = rep->channel;
entry_num++;
}
if (rep->prefer_select != (t_u8)0U && (rep->prefer > prefer_old))
{
ptagnr = pos - 2;
tagnr_len = len + (t_u8)2U;
prefer_old = (t_u8)rep->prefer;
prefer_select = 1;
neighbor_index = wnm_num_neighbor_report;
}
wnm_num_neighbor_report++;
}
pos += len;
}
if (wnm_num_neighbor_report == (t_u8)0U)
{
wlan_send_mgmt_wnm_btm_resp(dialog_token, WNM_BTM_REJECT_NO_SUITABLE_CANDIDATES, dest_addr, src_addr, NULL,
ptagnr, tagnr_len, protect);
os_mem_free((void *)preport);
os_mem_free((void *)pnlist_rep_param);
return;
}
if (prefer_select == (t_u8)1U)
{
wlan_send_mgmt_wnm_btm_resp(dialog_token, WNM_BTM_ACCEPT, dest_addr, src_addr,
preport[neighbor_index].bssid, ptagnr, tagnr_len, protect);
/* disconnect and re-assocate with AP2 */
pnlist_rep_param->nlist_mode = WLAN_NLIST_11V_PREFERRED;
pnlist_rep_param->num_channels = 1;
pnlist_rep_param->channels[0] = preport[neighbor_index].channel;
pnlist_rep_param->btm_mode = btm_mode;
(void)memcpy((void *)pnlist_rep_param->bssid, (const void *)preport[neighbor_index].bssid,
(size_t)MLAN_MAC_ADDR_LENGTH);
}
else
{
pnlist_rep_param->nlist_mode = WLAN_NLIST_11V;
pnlist_rep_param->num_channels = entry_num;
pnlist_rep_param->btm_mode = btm_mode;
pnlist_rep_param->dialog_token = dialog_token;
pnlist_rep_param->protect = protect;
(void)memcpy((void *)pnlist_rep_param->dst_addr, (const void *)dest_addr, (size_t)MLAN_MAC_ADDR_LENGTH);
}
if (wifi_event_completion(WIFI_EVENT_NLIST_REPORT, WIFI_EVENT_REASON_SUCCESS, (void *)pnlist_rep_param) !=
WM_SUCCESS)
{
/* If fail to send message on queue, free allocated memory ! */
os_mem_free((void *)pnlist_rep_param);
}
os_mem_free(preport);
}
else
{
enum wnm_btm_status_code status;
if ((btm_mode & IEEE_WNM_BTM_REQUEST_ESS_DISASSOC_IMMINENT) != 0U)
{
status = WNM_BTM_ACCEPT;
}
else
{
status = WNM_BTM_REJECT_UNSPECIFIED;
}
wlan_send_mgmt_wnm_btm_resp(dialog_token, status, dest_addr, src_addr, NULL, ptagnr, tagnr_len, protect);
/* If don't use variable pnlist_rep_param, free allocated memory ! */
os_mem_free((void *)pnlist_rep_param);
}
}
int wlan_send_mgmt_bss_trans_query(mlan_private *pmpriv, t_u8 query_reason)
{
t_u16 pkt_len;
mlan_802_11_mac_addr *da = MNULL;
mlan_802_11_mac_addr *sa = MNULL;
wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
t_u8 *pos = MNULL;
int meas_pkt_len = 0;
if (pmpriv->bss_index != (t_u8)MLAN_BSS_ROLE_STA || pmpriv->media_connected != MTRUE)
{
wifi_d("invalid interface %d for sending neighbor report request", pmpriv->bss_index);
return (int)MLAN_STATUS_FAILURE;
}
da = &pmpriv->curr_bss_params.bss_descriptor.mac_address;
sa = (mlan_802_11_mac_addr *)(void *)(&pmpriv->curr_addr[0]);
pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(SUBTYPE_ACTION, da, sa, da, sizeof(wlan_mgmt_pkt) + WNM_BTM_QUERY_BUF_SIZE);
if (pmgmt_pkt_hdr == MNULL)
{
wifi_e("No memory for bss transition management query");
return (int)MLAN_STATUS_FAILURE;
}
/* 802.11 management body */
pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_WNM;
pos[1] = (t_u8)IEEE_MGMT_WNM_BTM_QUERY;
pos[2] = pmpriv->bss_trans_query_token++;
if (pmpriv->bss_trans_query_token == (t_u8)255U)
{
pmpriv->bss_trans_query_token = (t_u8)1U;
}
pos[3] = query_reason;
pos += 4;
meas_pkt_len = pos - (t_u8 *)pmgmt_pkt_hdr;
pkt_len = (t_u16)meas_pkt_len;
pmgmt_pkt_hdr->frm_len = pkt_len - (t_u16)sizeof(pmgmt_pkt_hdr->frm_len);
(void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
os_mem_free(pmgmt_pkt_hdr);
return (int)MLAN_STATUS_SUCCESS;
}
#endif /* CONFIG_11V */