mwifiex/mwifiex_8997/mlan/mlan_11n_rxreorder.c
Fugang Duan bd8827d169 mwifiex: 8997: add W16.68.10.p16 release sdk
The sdk release is from NXP offial web:
https://www.nxp.com/products/wireless/wi-fi-plus-bluetooth/
88w8997-wi-fi-dual-band-with-bluetooth-5-for-a-v-streaming-and-digital-tv:88W8997?tab=Design_Tools_Tab

The release file is:
PCIE-WLAN-UART-BT-8997-U16-X86-W16.68.10.p16-16.26.10.p16-C4X16640_V4-MGPL

The sdk version is: W16.68.10.p16

Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
2020-01-13 10:35:39 +08:00

1664 lines
46 KiB
C
Executable file

/** @file mlan_11n_rxreorder.c
*
* @brief This file contains the handling of RxReordering in wlan
* driver.
*
* Copyright (C) 2008-2019, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
/********************************************************
Change log:
11/10/2008: initial version
********************************************************/
#include "mlan.h"
#include "mlan_join.h"
#include "mlan_util.h"
#include "mlan_fw.h"
#include "mlan_main.h"
#include "mlan_wmm.h"
#include "mlan_11n.h"
#include "mlan_11n_rxreorder.h"
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @brief This function will dispatch amsdu packet and
* forward it to kernel/upper layer
*
* @param priv A pointer to mlan_private
* @param pmbuf A pointer to the received buffer
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
wlan_11n_dispatch_amsdu_pkt(mlan_private *priv, pmlan_buffer pmbuf)
{
RxPD *prx_pd;
prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
ENTER();
if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
pmbuf->data_len = prx_pd->rx_pkt_length;
pmbuf->data_offset += prx_pd->rx_pkt_offset;
wlan_11n_deaggregate_pkt(priv, pmbuf);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
LEAVE();
return MLAN_STATUS_FAILURE;
}
/**
* @brief This function will process the rx packet and
* forward it to kernel/upper layer
*
* @param priv A pointer to mlan_private
* @param payload A pointer to rx packet payload
* @param rx_reor_tbl_ptr pointer to RxReorderTbl
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static mlan_status
wlan_11n_dispatch_pkt(t_void *priv, t_void *payload,
RxReorderTbl *rx_reor_tbl_ptr)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = ((pmlan_private)priv)->adapter;
ENTER();
if (payload == (t_void *)RX_PKT_DROPPED_IN_FW) {
LEAVE();
return ret;
}
if (ISSUPP_RSN_REPLAY_DETECTION(pmadapter->fw_cap_info) &&
rx_reor_tbl_ptr &&
wlan_is_rsn_replay_attack((mlan_private *)priv, payload,
rx_reor_tbl_ptr)) {
LEAVE();
return ret;
}
#ifdef UAP_SUPPORT
if (GET_BSS_ROLE((mlan_private *)priv) == MLAN_BSS_ROLE_UAP) {
if (MLAN_STATUS_SUCCESS ==
wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
(pmlan_buffer)payload)) {
LEAVE();
return ret;
}
ret = wlan_process_uap_rx_packet(priv, (pmlan_buffer)payload);
LEAVE();
return ret;
}
#endif /* UAP_SUPPORT */
#ifdef STA_SUPPORT
if (MLAN_STATUS_SUCCESS ==
wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
(pmlan_buffer)payload)) {
LEAVE();
return ret;
}
ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer)payload);
#endif /* STA_SUPPORT */
LEAVE();
return ret;
}
/**
* @brief This function restarts the reordering timeout timer
*
* @param pmadapter A pointer to mlan_adapter
* @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
*
* @return N/A
*/
static void
mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,
RxReorderTbl *rx_reor_tbl_ptr)
{
t_u16 min_flush_time = 0;
ENTER();
if (rx_reor_tbl_ptr->win_size >= 32)
min_flush_time = MIN_FLUSH_TIMER_15_MS;
else
min_flush_time = MIN_FLUSH_TIMER_MS;
if (rx_reor_tbl_ptr->timer_context.timer_is_set)
pmadapter->callbacks.moal_stop_timer(pmadapter->pmoal_handle,
rx_reor_tbl_ptr->
timer_context.timer);
pmadapter->callbacks.moal_start_timer(pmadapter->pmoal_handle,
rx_reor_tbl_ptr->timer_context.
timer, MFALSE,
(rx_reor_tbl_ptr->win_size *
min_flush_time));
rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
LEAVE();
}
/**
* @brief This function dispatches all the packets in the buffer.
* There could be holes in the buffer.
*
* @param priv A pointer to mlan_private
* @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
* @param start_win Start window
*
* @return MLAN_STATUS_SUCCESS
*/
static mlan_status
wlan_11n_dispatch_pkt_until_start_win(t_void *priv,
RxReorderTbl *rx_reor_tbl_ptr,
int start_win)
{
int no_pkt_to_send, i, xchg;
mlan_status ret = MLAN_STATUS_SUCCESS;
void *rx_tmp_ptr = MNULL;
mlan_private *pmpriv = (mlan_private *)priv;
ENTER();
no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
MIN((start_win - rx_reor_tbl_ptr->start_win),
rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
for (i = 0; i < no_pkt_to_send; ++i) {
pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->
pmoal_handle,
pmpriv->rx_pkt_lock);
rx_tmp_ptr = MNULL;
if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
}
pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
pmoal_handle,
pmpriv->
rx_pkt_lock);
if (rx_tmp_ptr)
wlan_11n_dispatch_pkt(priv, rx_tmp_ptr,
rx_reor_tbl_ptr);
}
pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
pmpriv->rx_pkt_lock);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
*/
xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
for (i = 0; i < xchg; ++i) {
rx_reor_tbl_ptr->rx_reorder_ptr[i] =
rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
}
rx_reor_tbl_ptr->start_win = start_win;
pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
pmoal_handle,
pmpriv->rx_pkt_lock);
LEAVE();
return ret;
}
/**
* @brief This function will display the rxReorder table
*
* @param pmadapter A pointer to mlan_adapter structure
* @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
*
* @return N/A
*/
static t_void
wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter, RxReorderTbl *rx_reor_tbl_ptr)
{
ENTER();
DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
sizeof(t_void *) * rx_reor_tbl_ptr->win_size);
LEAVE();
}
/**
* @brief This function will dispatch all packets sequentially
* from start_win until a hole is found and adjust the
* start_win appropriately
*
* @param priv A pointer to mlan_private
* @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
*
* @return MLAN_STATUS_SUCCESS
*/
static mlan_status
wlan_11n_scan_and_dispatch(t_void *priv, RxReorderTbl *rx_reor_tbl_ptr)
{
int i, j, xchg;
mlan_status ret = MLAN_STATUS_SUCCESS;
void *rx_tmp_ptr = MNULL;
mlan_private *pmpriv = (mlan_private *)priv;
ENTER();
for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->
pmoal_handle,
pmpriv->rx_pkt_lock);
if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->
adapter->
pmoal_handle,
pmpriv->
rx_pkt_lock);
break;
}
rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
pmoal_handle,
pmpriv->
rx_pkt_lock);
wlan_11n_dispatch_pkt(priv, rx_tmp_ptr, rx_reor_tbl_ptr);
}
pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
pmpriv->rx_pkt_lock);
/*
* We don't have a circular buffer, hence use rotation to simulate
* circular buffer
*/
if (i > 0) {
xchg = rx_reor_tbl_ptr->win_size - i;
for (j = 0; j < xchg; ++j) {
rx_reor_tbl_ptr->rx_reorder_ptr[j] =
rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
}
}
rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
& (MAX_TID_VALUE - 1);
pmpriv->adapter->callbacks.moal_spin_unlock(pmpriv->adapter->
pmoal_handle,
pmpriv->rx_pkt_lock);
LEAVE();
return ret;
}
/**
* @brief This function delete rxreorder table's entry
* and free the memory
*
* @param priv A pointer to mlan_private
* @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
*
* @return N/A
*/
static t_void
wlan_11n_delete_rxreorder_tbl_entry(mlan_private *priv,
RxReorderTbl *rx_reor_tbl_ptr)
{
pmlan_adapter pmadapter = priv->adapter;
ENTER();
if (!rx_reor_tbl_ptr) {
LEAVE();
return;
}
mlan_block_rx_process(pmadapter, MTRUE);
wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
(rx_reor_tbl_ptr->start_win +
rx_reor_tbl_ptr->win_size)
& (MAX_TID_VALUE - 1));
if (rx_reor_tbl_ptr->timer_context.timer) {
if (rx_reor_tbl_ptr->timer_context.timer_is_set) {
priv->adapter->callbacks.moal_stop_timer(pmadapter->
pmoal_handle,
rx_reor_tbl_ptr->timer_context.
timer);
rx_reor_tbl_ptr->timer_context.timer_is_set = MFALSE;
}
priv->adapter->callbacks.moal_free_timer(pmadapter->
pmoal_handle,
rx_reor_tbl_ptr->timer_context.
timer);
rx_reor_tbl_ptr->timer_context.timer = MNULL;
}
PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
util_unlink_list(pmadapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr,
(pmlan_linked_list)rx_reor_tbl_ptr,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)rx_reor_tbl_ptr->
rx_reorder_ptr);
pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)rx_reor_tbl_ptr);
mlan_block_rx_process(pmadapter, MFALSE);
LEAVE();
}
/**
* @brief This function returns the last used sequence number
*
* @param rx_reorder_tbl_ptr A pointer to structure RxReorderTbl
*
* @return Last used sequence number
*/
static int
wlan_11n_find_last_seqnum(RxReorderTbl *rx_reorder_tbl_ptr)
{
int i;
ENTER();
for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) {
if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
LEAVE();
return i;
}
}
LEAVE();
return -1;
}
/**
* @brief This function flushes all data
*
* @param priv A pointer to mlan_private structure
* @param rx_reor_tbl_ptr A pointer to RxReorderTbl
*
* @return N/A
*/
static t_void
wlan_start_flush_data(mlan_private *priv, RxReorderTbl *rx_reor_tbl_ptr)
{
int startWin;
ENTER();
wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
startWin = wlan_11n_find_last_seqnum(rx_reor_tbl_ptr);
if (startWin >= 0) {
PRINTM(MINFO, "Flush data %d\n", startWin);
wlan_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
((rx_reor_tbl_ptr->
start_win + startWin +
1) & (MAX_TID_VALUE -
1)));
}
wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
LEAVE();
}
/**
* @brief This function set the flag to flushes data
*
* @param context Reorder context pointer
*
* @return N/A
*/
static t_void
wlan_flush_data(t_void *context)
{
reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *)context;
ENTER();
/* Set the flag to flush data */
reorder_cnxt->priv->adapter->flush_data = MTRUE;
reorder_cnxt->ptr->flush_data = MTRUE;
reorder_cnxt->timer_is_set = MFALSE;
wlan_recv_event(reorder_cnxt->priv, MLAN_EVENT_ID_DRV_DEFER_RX_WORK,
MNULL);
LEAVE();
}
/**
* @brief This function will create a entry in rx reordering table for the
* given ta/tid and will initialize it with seq_num, win_size
*
* @param priv A pointer to mlan_private
* @param ta ta to find in reordering table
* @param tid tid to find in reordering table
* @param win_size win_size for the give ta/tid pair.
* @param seq_num Starting sequence number for current entry.
*
* @return N/A
*/
static t_void
wlan_11n_create_rxreorder_tbl(mlan_private *priv, t_u8 *ta, int tid,
int win_size, int seq_num)
{
int i;
pmlan_adapter pmadapter = priv->adapter;
RxReorderTbl *rx_reor_tbl_ptr, *new_node;
sta_node *sta_ptr = MNULL;
t_u16 last_seq = 0;
ENTER();
/*
* If we get a TID, ta pair which is already present dispatch all the
* the packets and move the window size until the ssn
*/
rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta);
if (rx_reor_tbl_ptr) {
if (rx_reor_tbl_ptr->timer_context.timer_is_set) {
priv->adapter->callbacks.moal_stop_timer(pmadapter->
pmoal_handle,
rx_reor_tbl_ptr->
timer_context.
timer);
rx_reor_tbl_ptr->timer_context.timer_is_set = MFALSE;
}
rx_reor_tbl_ptr->flush_data = MFALSE;
wlan_11n_dispatch_pkt_until_start_win(priv,
rx_reor_tbl_ptr, seq_num);
new_node = rx_reor_tbl_ptr;
PRINTM(MDAT_D, "%s: Reset with seq_num %d, tid %d, ta " MACSTR
", win_size %d\n", __func__,
seq_num, tid, MAC2STR(ta), win_size);
} else {
PRINTM(MDAT_D, "%s: seq_num %d, tid %d, ta " MACSTR
", win_size %d\n", __func__,
seq_num, tid, MAC2STR(ta), win_size);
if (pmadapter->callbacks.
moal_malloc(pmadapter->pmoal_handle, sizeof(RxReorderTbl),
MLAN_MEM_DEF, (t_u8 **)&new_node)) {
PRINTM(MERROR, "Rx reorder memory allocation failed\n");
LEAVE();
return;
}
util_init_list((pmlan_linked_list)new_node);
if (pmadapter->callbacks.
moal_malloc(pmadapter->pmoal_handle,
sizeof(t_void *) * win_size, MLAN_MEM_DEF,
(t_u8 **)&new_node->rx_reorder_ptr)) {
PRINTM(MERROR,
"Rx reorder table memory allocation" "failed\n");
pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)new_node);
LEAVE();
return;
}
PRINTM(MDAT_D,
"Create ReorderPtr: %p start_win=%d last_seq=%d\n",
new_node, new_node->start_win, last_seq);
new_node->timer_context.ptr = new_node;
new_node->timer_context.priv = priv;
new_node->timer_context.timer_is_set = MFALSE;
pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle,
&new_node->
timer_context.timer,
wlan_flush_data,
&new_node->timer_context);
util_enqueue_list_tail(pmadapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr,
(pmlan_linked_list)new_node,
pmadapter->callbacks.moal_spin_lock,
pmadapter->callbacks.moal_spin_unlock);
}
new_node->tid = tid;
memcpy(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH);
new_node->start_win = seq_num;
new_node->pkt_count = 0;
if (queuing_ra_based(priv)) {
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
sta_ptr = wlan_get_station_entry(priv, ta);
if (sta_ptr)
last_seq = sta_ptr->rx_seq[tid];
}
PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq,
new_node->start_win);
} else {
sta_ptr = wlan_get_station_entry(priv, ta);
if (sta_ptr)
last_seq = sta_ptr->rx_seq[tid];
else
last_seq = priv->rx_seq[tid];
}
new_node->last_seq = last_seq;
new_node->win_size = win_size;
new_node->force_no_drop = MFALSE;
new_node->check_start_win = MTRUE;
new_node->ba_status = BA_STREAM_SETUP_INPROGRESS;
for (i = 0; i < win_size; ++i)
new_node->rx_reorder_ptr[i] = MNULL;
new_node->hi_curr_rx_count32 = 0xffffffff;
new_node->lo_curr_rx_count16 = 0;
LEAVE();
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief This function will return the pointer to a entry in rx reordering
* table which matches the give TA/TID pair
*
* @param priv A pointer to mlan_private
* @param ta ta to find in reordering table
* @param tid tid to find in reordering table
*
* @return A pointer to structure RxReorderTbl
*/
RxReorderTbl *
wlan_11n_get_rxreorder_tbl(mlan_private *priv, int tid, t_u8 *ta)
{
RxReorderTbl *rx_reor_tbl_ptr;
ENTER();
rx_reor_tbl_ptr =
(RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr, MNULL,
MNULL);
if (!rx_reor_tbl_ptr) {
LEAVE();
return MNULL;
}
while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
if ((!memcmp
(priv->adapter, rx_reor_tbl_ptr->ta, ta,
MLAN_MAC_ADDR_LENGTH)) && (rx_reor_tbl_ptr->tid == tid)) {
LEAVE();
return rx_reor_tbl_ptr;
}
rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
}
LEAVE();
return MNULL;
}
/**
* @brief This function prepares command for adding a block ack
* request.
*
* @param priv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer to data buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_cmd_11n_addba_req(mlan_private *priv,
HostCmd_DS_COMMAND *cmd, t_void *pdata_buf)
{
HostCmd_DS_11N_ADDBA_REQ *padd_ba_req = (HostCmd_DS_11N_ADDBA_REQ *)
&cmd->params.add_ba_req;
ENTER();
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) +
S_DS_GEN);
memcpy(priv->adapter, padd_ba_req, pdata_buf,
sizeof(HostCmd_DS_11N_ADDBA_REQ));
padd_ba_req->block_ack_param_set =
wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
padd_ba_req->block_ack_tmo =
wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
padd_ba_req->add_req_result = 0;
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function check if AMPDU Rx allowed
*
* @param priv A pointer to mlan_private structure
* @param tid TID
*
* @return MTRUE/MFALSE
*/
t_u8
wlan_is_addba_reject(mlan_private *priv, t_u8 tid)
{
#ifdef STA_SUPPORT
#endif
return priv->addba_reject[tid];
}
/**
* @brief This function prepares command for adding a block ack
* response.
*
* @param priv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer to data buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_cmd_11n_addba_rspgen(mlan_private *priv,
HostCmd_DS_COMMAND *cmd, void *pdata_buf)
{
HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
&cmd->params.add_ba_rsp;
HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
(HostCmd_DS_11N_ADDBA_REQ *)pdata_buf;
t_u8 tid = 0;
int win_size = 0;
ENTER();
pevt_addba_req->block_ack_param_set =
wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
pevt_addba_req->block_ack_tmo =
wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
cmd->size =
wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
memcpy(priv->adapter, padd_ba_rsp->peer_mac_addr,
pevt_addba_req->peer_mac_addr, MLAN_MAC_ADDR_LENGTH);
padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
padd_ba_rsp->block_ack_tmo =
wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
padd_ba_rsp->add_rsp_result = 0;
padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
if (wlan_is_addba_reject(priv, tid)
#ifdef STA_SUPPORT
|| ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
&& priv->wps.session_enable)
#endif
#ifdef UAP_SUPPORT
|| ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
&& (util_scalar_read(priv->adapter->pmoal_handle,
&priv->adapter->pending_bridge_pkts,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.
moal_spin_unlock) > RX_LOW_THRESHOLD))
#endif
)
padd_ba_rsp->status_code =
wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
else
padd_ba_rsp->status_code =
wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
if (!priv->add_ba_param.rx_amsdu)
/* We do not support AMSDU inside AMPDU, hence reset the bit */
padd_ba_rsp->block_ack_param_set &=
~BLOCKACKPARAM_AMSDU_SUPP_MASK;
padd_ba_rsp->block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
BLOCKACKPARAM_WINSIZE_POS);
win_size =
(padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS;
if (win_size == 0)
padd_ba_rsp->status_code =
wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
padd_ba_rsp->block_ack_param_set =
wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
if (padd_ba_rsp->status_code ==
wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT))
wlan_11n_create_rxreorder_tbl(priv,
pevt_addba_req->peer_mac_addr,
tid, win_size,
pevt_addba_req->ssn);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function prepares command for deleting a block ack
* request.
*
* @param priv A pointer to mlan_private structure
* @param cmd A pointer to HostCmd_DS_COMMAND structure
* @param pdata_buf A pointer to data buffer
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_cmd_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *cmd, void *pdata_buf)
{
HostCmd_DS_11N_DELBA *pdel_ba = (HostCmd_DS_11N_DELBA *)
&cmd->params.del_ba;
ENTER();
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
memcpy(priv->adapter, pdel_ba, pdata_buf, sizeof(HostCmd_DS_11N_DELBA));
pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
pdel_ba->del_result = 0;
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @bref This function is to reset PN value when ptk rekey
* @param pmpriv pointer to mlan_private
* @param key pointer to mlan_ds_encrypt_key
*
* @return N/A
*/
t_void
wlan_reset_pn_value(mlan_private *pmpriv, mlan_ds_encrypt_key *key)
{
RxReorderTbl *rx_reor_tbl_ptr = MNULL;
t_u8 tid = 0;
ENTER();
if (key->key_flags & KEY_FLAG_REMOVE_KEY
|| key->key_flags & KEY_FLAG_GROUP_KEY)
goto done;
for (tid = 0; tid < 7; tid++) {
rx_reor_tbl_ptr =
wlan_11n_get_rxreorder_tbl(pmpriv, tid, key->mac_addr);
if (rx_reor_tbl_ptr) {
rx_reor_tbl_ptr->hi_curr_rx_count32 = 0xffffffff;
rx_reor_tbl_ptr->lo_curr_rx_count16 = 0;
}
}
done:
LEAVE();
return;
}
/**
* @bref This function check PN numbers to detect replay counter attack
* @param pmpriv pointer to mlan_private
* @param payload pointer to mlan_buffer
* @param rx_reor_tbl_ptr pointer to RxReorderTbl
*
* @return MTRUE/MFALSE
*/
t_u8
wlan_is_rsn_replay_attack(mlan_private *pmpriv, t_void *payload,
RxReorderTbl *rx_reor_tbl_ptr)
{
RxPD *prx_pd = MNULL;
pmlan_buffer pmbuf = MNULL;
pmlan_adapter pmadapter = pmpriv->adapter;
ENTER();
pmbuf = (pmlan_buffer)payload;
prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
if (!(prx_pd->flags & RXPD_FLAG_PN_CHECK_SUPPORT)) {
LEAVE();
return MFALSE;
}
if ((prx_pd->hi_rx_count32 == rx_reor_tbl_ptr->hi_curr_rx_count32 &&
prx_pd->lo_rx_count16 <= rx_reor_tbl_ptr->lo_curr_rx_count16)
|| (rx_reor_tbl_ptr->hi_curr_rx_count32 != 0xffffffff &&
prx_pd->hi_rx_count32 < rx_reor_tbl_ptr->hi_curr_rx_count32)) {
PRINTM(MERROR,
"Drop packet because of invalid PN value. Last PN:0x%x 0x%x,New PN:0x%x 0x%x\n",
rx_reor_tbl_ptr->hi_curr_rx_count32,
rx_reor_tbl_ptr->lo_curr_rx_count16,
prx_pd->hi_rx_count32, prx_pd->lo_rx_count16);
wlan_free_mlan_buffer(pmadapter, pmbuf);
LEAVE();
return MTRUE;
}
rx_reor_tbl_ptr->lo_curr_rx_count16 = prx_pd->lo_rx_count16;
rx_reor_tbl_ptr->hi_curr_rx_count32 = prx_pd->hi_rx_count32;
LEAVE();
return MFALSE;
}
/**
* @brief This function will identify if RxReodering is needed for the packet
* and will do the reordering if required before sending it to kernel
*
* @param priv A pointer to mlan_private
* @param seq_num Seqence number of the current packet
* @param tid Tid of the current packet
* @param ta Transmiter address of the current packet
* @param pkt_type Packetype for the current packet (to identify if its a BAR)
* @param payload Pointer to the payload
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
t_u8 *ta, t_u8 pkt_type, void *payload)
{
RxReorderTbl *rx_reor_tbl_ptr;
int prev_start_win, start_win, end_win, win_size;
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = ((mlan_private *)priv)->adapter;
ENTER();
rx_reor_tbl_ptr =
wlan_11n_get_rxreorder_tbl((mlan_private *)priv, tid, ta);
if (!rx_reor_tbl_ptr || rx_reor_tbl_ptr->win_size <= 1) {
if (pkt_type != PKT_TYPE_BAR)
wlan_11n_dispatch_pkt(priv, payload, rx_reor_tbl_ptr);
LEAVE();
return ret;
} else {
if (rx_reor_tbl_ptr->flush_data) {
rx_reor_tbl_ptr->flush_data = MFALSE;
wlan_start_flush_data(priv, rx_reor_tbl_ptr);
}
if ((pkt_type == PKT_TYPE_AMSDU) && !rx_reor_tbl_ptr->amsdu) {
wlan_11n_dispatch_pkt(priv, payload, rx_reor_tbl_ptr);
LEAVE();
return ret;
}
if (pkt_type == PKT_TYPE_BAR)
PRINTM(MDAT_D, "BAR ");
if (pkt_type == PKT_TYPE_AMSDU)
PRINTM(MDAT_D, "AMSDU ");
if (rx_reor_tbl_ptr->check_start_win) {
if (seq_num == rx_reor_tbl_ptr->start_win)
rx_reor_tbl_ptr->check_start_win = MFALSE;
else {
rx_reor_tbl_ptr->pkt_count++;
if (rx_reor_tbl_ptr->pkt_count <
(rx_reor_tbl_ptr->win_size / 2)) {
if (rx_reor_tbl_ptr->last_seq ==
seq_num) {
/** drop duplicate packet */
ret = MLAN_STATUS_FAILURE;
} else {
/** forward the packet to kernel */
rx_reor_tbl_ptr->last_seq =
seq_num;
if (pkt_type != PKT_TYPE_BAR)
wlan_11n_dispatch_pkt
(priv, payload,
rx_reor_tbl_ptr);
}
LEAVE();
return ret;
}
rx_reor_tbl_ptr->check_start_win = MFALSE;
if ((seq_num != rx_reor_tbl_ptr->start_win) &&
(rx_reor_tbl_ptr->last_seq !=
DEFAULT_SEQ_NUM)) {
end_win =
(rx_reor_tbl_ptr->start_win +
rx_reor_tbl_ptr->win_size -
1) & (MAX_TID_VALUE - 1);
if (((end_win >
rx_reor_tbl_ptr->start_win)
&& (rx_reor_tbl_ptr->last_seq >=
rx_reor_tbl_ptr->start_win)
&& (rx_reor_tbl_ptr->last_seq <
end_win)) ||
((end_win <
rx_reor_tbl_ptr->start_win) &&
((rx_reor_tbl_ptr->last_seq >=
rx_reor_tbl_ptr->start_win) ||
(rx_reor_tbl_ptr->last_seq <
end_win)))) {
PRINTM(MDAT_D,
"Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
rx_reor_tbl_ptr->
last_seq,
rx_reor_tbl_ptr->
start_win, seq_num);
rx_reor_tbl_ptr->start_win =
rx_reor_tbl_ptr->
last_seq + 1;
} else if ((seq_num <
rx_reor_tbl_ptr->start_win)
&& (seq_num >
rx_reor_tbl_ptr->
last_seq)) {
PRINTM(MDAT_D,
"Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
rx_reor_tbl_ptr->
last_seq,
rx_reor_tbl_ptr->
start_win, seq_num);
rx_reor_tbl_ptr->start_win =
rx_reor_tbl_ptr->
last_seq + 1;
}
}
}
}
if (rx_reor_tbl_ptr->force_no_drop) {
wlan_11n_dispatch_pkt_until_start_win(priv,
rx_reor_tbl_ptr,
(rx_reor_tbl_ptr->
start_win +
rx_reor_tbl_ptr->
win_size)
& (MAX_TID_VALUE -
1));
if (pkt_type != PKT_TYPE_BAR)
rx_reor_tbl_ptr->start_win = seq_num;
mlan_11n_rxreorder_timer_restart(pmadapter,
rx_reor_tbl_ptr);
}
prev_start_win = start_win = rx_reor_tbl_ptr->start_win;
win_size = rx_reor_tbl_ptr->win_size;
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
PRINTM(MDAT_D, "TID %d, TA " MACSTR "\n", tid, MAC2STR(ta));
PRINTM(MDAT_D,
"1:seq_num %d start_win %d win_size %d end_win %d\n",
seq_num, start_win, win_size, end_win);
/*
* If seq_num is less then starting win then ignore and drop
* the packet
*/
if (rx_reor_tbl_ptr->force_no_drop) {
PRINTM(MDAT_D, "No drop packet\n");
rx_reor_tbl_ptr->force_no_drop = MFALSE;
} else {
/* Wrap */
if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
if (seq_num >= ((start_win + (TWOPOW11)) &
(MAX_TID_VALUE - 1)) &&
(seq_num < start_win)) {
if (pkt_type == PKT_TYPE_BAR)
PRINTM(MDAT_D,
"BAR: start_win=%d, end_win=%d, seq_num=%d\n",
start_win, end_win,
seq_num);
ret = MLAN_STATUS_FAILURE;
goto done;
}
} else if ((seq_num < start_win) ||
(seq_num >= (start_win + (TWOPOW11)))) {
if (pkt_type == PKT_TYPE_BAR)
PRINTM(MDAT_D,
"BAR: start_win=%d, end_win=%d, seq_num=%d\n",
start_win, end_win, seq_num);
ret = MLAN_STATUS_FAILURE;
goto done;
}
}
/*
* If this packet is a BAR we adjust seq_num as
* WinStart = seq_num
*/
if (pkt_type == PKT_TYPE_BAR)
seq_num =
((seq_num + win_size) - 1) & (MAX_TID_VALUE -
1);
PRINTM(MDAT_D,
"2:seq_num %d start_win %d win_size %d end_win %d\n",
seq_num, start_win, win_size, end_win);
if (((end_win < start_win) &&
(seq_num < start_win) && (seq_num > end_win))
|| ((end_win > start_win) &&
((seq_num > end_win) || (seq_num < start_win)))) {
end_win = seq_num;
if (((seq_num - win_size) + 1) >= 0)
start_win = (end_win - win_size) + 1;
else
start_win = (MAX_TID_VALUE -
(win_size - seq_num)) + 1;
ret = wlan_11n_dispatch_pkt_until_start_win(priv,
rx_reor_tbl_ptr,
start_win);
if (ret)
goto done;
}
PRINTM(MDAT_D, "3:seq_num %d start_win %d win_size %d"
" end_win %d\n", seq_num, start_win, win_size, end_win);
if (pkt_type != PKT_TYPE_BAR) {
if (seq_num >= start_win) {
if (rx_reor_tbl_ptr->rx_reorder_ptr[seq_num
-
start_win])
{
PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
rx_reor_tbl_ptr->rx_reorder_ptr[seq_num
- start_win] =
payload;
} else { /* Wrap condition */
if (rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+
(MAX_TID_VALUE))
-
start_win])
{
PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
ret = MLAN_STATUS_FAILURE;
goto done;
}
rx_reor_tbl_ptr->rx_reorder_ptr[(seq_num
+
(MAX_TID_VALUE))
- start_win] =
payload;
}
}
wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
/*
* Dispatch all packets sequentially from start_win until a
* hole is found and adjust the start_win appropriately
*/
ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
}
done:
if (!rx_reor_tbl_ptr->timer_context.timer_is_set ||
(prev_start_win != rx_reor_tbl_ptr->start_win)) {
mlan_11n_rxreorder_timer_restart(pmadapter, rx_reor_tbl_ptr);
}
LEAVE();
return ret;
}
/**
* @brief This function will delete an entry for a given tid/ta pair. tid/ta
* are taken from delba_event body
*
* @param priv A pointer to mlan_private
* @param tid tid to send delba
* @param peer_mac MAC address to send delba
* @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
* @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
* @param reason_code delete ba reason
*
* @return N/A
*/
void
mlan_11n_delete_bastream_tbl(mlan_private *priv, int tid,
t_u8 *peer_mac, t_u8 type, int initiator,
t_u16 reason_code)
{
RxReorderTbl *rx_reor_tbl_ptr;
TxBAStreamTbl *ptxtbl;
t_u8 cleanup_rx_reorder_tbl;
raListTbl *ra_list = MNULL;
int tid_down;
ENTER();
if (type == TYPE_DELBA_RECEIVE)
cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
else
cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
PRINTM(MEVENT, "delete_bastream_tbl: " MACSTR " tid=%d, type=%d"
"initiator=%d reason=%d\n", MAC2STR(peer_mac), tid, type,
initiator, reason_code);
if (cleanup_rx_reorder_tbl) {
rx_reor_tbl_ptr =
wlan_11n_get_rxreorder_tbl(priv, tid, peer_mac);
if (!rx_reor_tbl_ptr) {
PRINTM(MWARN, "TID, TA not found in table!\n");
LEAVE();
return;
}
wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
} else {
wlan_request_ralist_lock(priv);
ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac,
MFALSE);
if (!ptxtbl) {
PRINTM(MWARN, "TID, RA not found in table!\n");
wlan_release_ralist_lock(priv);
LEAVE();
return;
}
wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
wlan_release_ralist_lock(priv);
tid_down = wlan_get_wmm_tid_down(priv, tid);
ra_list = wlan_wmm_get_ralist_node(priv, tid_down, peer_mac);
if (ra_list) {
ra_list->amsdu_in_ampdu = MFALSE;
ra_list->ba_status = BA_STREAM_NOT_SETUP;
if (type == TYPE_DELBA_RECEIVE) {
if (reason_code == REASON_CODE_STA_TIMEOUT)
ra_list->del_ba_count = 0;
else
ra_list->del_ba_count++;
ra_list->packet_count = 0;
/** after delba, we will try to set up BA again after sending 1k packets*/
#define MIN_BA_SETUP_PACKET_REQIRED 1024
ra_list->ba_packet_threshold =
MIN_BA_SETUP_PACKET_REQIRED +
wlan_get_random_ba_threshold(priv->
adapter);
}
}
}
LEAVE();
}
/**
* @brief This function handles the command response of
* a block ack response
*
* @param priv A pointer to mlan_private structure
* @param resp A pointer to HostCmd_DS_COMMAND
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
wlan_ret_11n_addba_resp(mlan_private *priv, HostCmd_DS_COMMAND *resp)
{
HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp = (HostCmd_DS_11N_ADDBA_RSP *)
&resp->params.add_ba_rsp;
int tid;
RxReorderTbl *rx_reor_tbl_ptr = MNULL;
ENTER();
padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
padd_ba_rsp->block_ack_param_set =
wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
padd_ba_rsp->block_ack_tmo =
wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
padd_ba_rsp->ssn = wlan_le16_to_cpu(padd_ba_rsp->ssn);
tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK)
>> BLOCKACKPARAM_TID_POS;
/* Check if we had rejected the ADDBA, if yes then do not create the
* stream
*/
if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
PRINTM(MCMND,
"ADDBA RSP: " MACSTR
" tid=%d ssn=%d win_size=%d,amsdu=%d\n",
MAC2STR(padd_ba_rsp->peer_mac_addr), tid,
padd_ba_rsp->ssn,
((padd_ba_rsp->
block_ack_param_set & BLOCKACKPARAM_WINSIZE_MASK)
>> BLOCKACKPARAM_WINSIZE_POS),
padd_ba_rsp->
block_ack_param_set & BLOCKACKPARAM_AMSDU_SUPP_MASK);
rx_reor_tbl_ptr =
wlan_11n_get_rxreorder_tbl(priv, tid,
padd_ba_rsp->peer_mac_addr);
if (rx_reor_tbl_ptr) {
rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_COMPLETE;
if ((padd_ba_rsp->
block_ack_param_set &
BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
priv->add_ba_param.rx_amsdu)
rx_reor_tbl_ptr->amsdu = MTRUE;
else
rx_reor_tbl_ptr->amsdu = MFALSE;
}
} else {
PRINTM(MCMND, "ADDBA RSP: Failed(" MACSTR " tid=%d)\n",
MAC2STR(padd_ba_rsp->peer_mac_addr), tid);
rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid,
padd_ba_rsp->
peer_mac_addr);
if (rx_reor_tbl_ptr)
wlan_11n_delete_rxreorder_tbl_entry(priv,
rx_reor_tbl_ptr);
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function handles ba_stream_timeout event
*
* @param priv A pointer to mlan_private
* @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
*
* @return N/A
*/
void
wlan_11n_ba_stream_timeout(mlan_private *priv, HostCmd_DS_11N_BATIMEOUT *event)
{
HostCmd_DS_11N_DELBA delba;
ENTER();
DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *)event, 20);
memset(priv->adapter, &delba, 0, sizeof(HostCmd_DS_11N_DELBA));
memcpy(priv->adapter, delba.peer_mac_addr, event->peer_mac_addr,
MLAN_MAC_ADDR_LENGTH);
delba.del_ba_param_set |= (t_u16)event->tid << DELBA_TID_POS;
delba.del_ba_param_set |=
(t_u16)event->origninator << DELBA_INITIATOR_POS;
delba.reason_code = REASON_CODE_STA_TIMEOUT;
wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
LEAVE();
return;
}
/**
* @brief This function cleans up reorder tbl
*
* @param priv A pointer to mlan_private
*
* @return N/A
*/
void
wlan_11n_cleanup_reorder_tbl(mlan_private *priv)
{
RxReorderTbl *del_tbl_ptr;
ENTER();
while ((del_tbl_ptr = (RxReorderTbl *)
util_peek_list(priv->adapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr,
priv->adapter->callbacks.moal_spin_lock,
priv->adapter->callbacks.moal_spin_unlock))) {
wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
}
util_init_list((pmlan_linked_list)&priv->rx_reorder_tbl_ptr);
memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
LEAVE();
}
/**
* @brief This function handle the rxba_sync event
*
* @param priv A pointer to mlan_private
* @param event_buf A pointer to event buf
* @param len event_buf length
* @return N/A
*/
void
wlan_11n_rxba_sync_event(mlan_private *priv, t_u8 *event_buf, t_u16 len)
{
MrvlIEtypes_RxBaSync_t *tlv_rxba = (MrvlIEtypes_RxBaSync_t *)event_buf;
t_u16 tlv_type, tlv_len;
RxReorderTbl *rx_reor_tbl_ptr = MNULL;
t_u8 i, j;
t_u16 seq_num = 0;
int tlv_buf_left = len;
ENTER();
DBG_HEXDUMP(MEVT_D, "RXBA_SYNC_EVT", event_buf, len);
while (tlv_buf_left >= sizeof(MrvlIEtypes_RxBaSync_t)) {
tlv_type = wlan_le16_to_cpu(tlv_rxba->header.type);
tlv_len = wlan_le16_to_cpu(tlv_rxba->header.len);
if (tlv_type != TLV_TYPE_RXBA_SYNC) {
PRINTM(MERROR, "Wrong TLV id=0x%x\n", tlv_type);
goto done;
}
tlv_rxba->seq_num = wlan_le16_to_cpu(tlv_rxba->seq_num);
tlv_rxba->bitmap_len = wlan_le16_to_cpu(tlv_rxba->bitmap_len);
PRINTM(MEVENT, MACSTR " tid=%d seq_num=%d bitmap_len=%d\n",
MAC2STR(tlv_rxba->mac), tlv_rxba->tid, tlv_rxba->seq_num,
tlv_rxba->bitmap_len);
rx_reor_tbl_ptr =
wlan_11n_get_rxreorder_tbl(priv, tlv_rxba->tid,
tlv_rxba->mac);
if (!rx_reor_tbl_ptr) {
PRINTM(MEVENT, "Can not find rx_reorder_tbl\n");
goto done;
}
if (rx_reor_tbl_ptr->force_no_drop) {
PRINTM(MEVENT, "Ignore RXBA_SYNC_EVT in resume\n");
goto done;
}
for (i = 0; i < tlv_rxba->bitmap_len; i++) {
for (j = 0; j < 8; j++) {
if (tlv_rxba->bitmap[i] & (1 << j)) {
seq_num =
(tlv_rxba->seq_num + i * 8 +
j) & (MAX_TID_VALUE - 1);
PRINTM(MEVENT,
"Fw dropped packet, seq=%d start_win=%d, win_size=%d\n",
seq_num,
rx_reor_tbl_ptr->start_win,
rx_reor_tbl_ptr->win_size);
if (MLAN_STATUS_SUCCESS !=
mlan_11n_rxreorder_pkt(priv,
seq_num,
tlv_rxba->
tid,
tlv_rxba->
mac, 0,
(t_void *)
RX_PKT_DROPPED_IN_FW))
{
PRINTM(MERROR,
"Fail to handle dropped packet, seq=%d\n",
seq_num);
}
}
}
}
tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
tlv_rxba =
(MrvlIEtypes_RxBaSync_t *)((t_u8 *)tlv_rxba + tlv_len +
sizeof(MrvlIEtypesHeader_t));
}
done:
LEAVE();
return;
}
/**
* @brief This function cleans up reorder tbl for specific station
*
* @param priv A pointer to mlan_private
* @param ta ta to find in reordering table
* @return N/A
*/
void
wlan_cleanup_reorder_tbl(mlan_private *priv, t_u8 *ta)
{
RxReorderTbl *rx_reor_tbl_ptr = MNULL;
t_u8 i;
ENTER();
for (i = 0; i < MAX_NUM_TID; ++i) {
rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, i, ta);
if (rx_reor_tbl_ptr)
wlan_11n_delete_rxreorder_tbl_entry(priv,
rx_reor_tbl_ptr);
}
LEAVE();
return;
}
/**
* @brief This function will set force_no_drop flag in rxreorder_tbl.
*
* @param priv A pointer to mlan_private
* @param flag MTRUE/MFALSE
*
* @return N/A
*/
void
wlan_set_rxreorder_tbl_no_drop_flag(mlan_private *priv, t_u8 flag)
{
RxReorderTbl *rx_reor_tbl_ptr;
ENTER();
rx_reor_tbl_ptr =
(RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr,
priv->adapter->callbacks.
moal_spin_lock,
priv->adapter->callbacks.
moal_spin_unlock);
if (!rx_reor_tbl_ptr) {
LEAVE();
return;
}
while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
rx_reor_tbl_ptr->force_no_drop = flag;
rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
}
LEAVE();
return;
}
/**
* @brief This function update all the rx_reorder_tbl's force_no_drop flag
*
* @param pmadapter A pointer to mlan_adapter
* @param flag MTRUE/MFALSE
* @return N/A
*/
void
wlan_update_rxreorder_tbl(pmlan_adapter pmadapter, t_u8 flag)
{
t_u8 i;
pmlan_private priv = MNULL;
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i]) {
priv = pmadapter->priv[i];
wlan_set_rxreorder_tbl_no_drop_flag(priv, flag);
}
}
return;
}
/**
* @brief This function will flush the data in rxreorder_tbl.
* which has flush_data flag on.
*
* @param priv A pointer to mlan_private
*
* @return N/A
*/
void
wlan_flush_priv_rxreorder_tbl(mlan_private *priv)
{
RxReorderTbl *rx_reor_tbl_ptr;
ENTER();
rx_reor_tbl_ptr =
(RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
&priv->rx_reorder_tbl_ptr,
priv->adapter->callbacks.
moal_spin_lock,
priv->adapter->callbacks.
moal_spin_unlock);
if (!rx_reor_tbl_ptr) {
LEAVE();
return;
}
while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
if (rx_reor_tbl_ptr->flush_data) {
rx_reor_tbl_ptr->flush_data = MFALSE;
wlan_start_flush_data(priv, rx_reor_tbl_ptr);
}
rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
}
LEAVE();
return;
}
/**
* @brief This function update all the rx_reorder_tbl's force_no_drop flag
*
* @param pmadapter A pointer to mlan_adapter
* @return N/A
*/
void
wlan_flush_rxreorder_tbl(pmlan_adapter pmadapter)
{
t_u8 i;
pmlan_private priv = MNULL;
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i]) {
priv = pmadapter->priv[i];
wlan_flush_priv_rxreorder_tbl(priv);
}
}
return;
}
/**
* @brief This function update all the rx_win_size based on coex flag
*
* @param pmadapter A pointer to mlan_adapter
* @param coex_flag coex flag
*
* @return N/A
*/
void
wlan_update_ampdu_rxwinsize(pmlan_adapter pmadapter, t_u8 coex_flag)
{
t_u8 i;
t_u32 rx_win_size = 0;
pmlan_private priv = MNULL;
ENTER();
if (!pmadapter->coex_rx_winsize) {
LEAVE();
return;
}
PRINTM(MEVENT, "Update rxwinsize %d\n", coex_flag);
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i]) {
priv = pmadapter->priv[i];
rx_win_size = priv->add_ba_param.rx_win_size;
if (coex_flag == MTRUE) {
#ifdef STA_SUPPORT
if (priv->bss_type == MLAN_BSS_TYPE_STA)
priv->add_ba_param.rx_win_size =
MLAN_STA_COEX_AMPDU_DEF_RXWINSIZE;
#endif
#ifdef WIFI_DIRECT_SUPPORT
if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
priv->add_ba_param.rx_win_size =
MLAN_WFD_COEX_AMPDU_DEF_RXWINSIZE;
#endif
if (priv->bss_type == MLAN_BSS_TYPE_NAN)
priv->add_ba_param.rx_win_size =
MLAN_NAN_COEX_AMPDU_DEF_RXWINSIZE;
#ifdef UAP_SUPPORT
if (priv->bss_type == MLAN_BSS_TYPE_UAP)
priv->add_ba_param.rx_win_size =
MLAN_UAP_COEX_AMPDU_DEF_RXWINSIZE;
#endif
} else {
priv->add_ba_param.rx_win_size =
priv->user_rxwinsize;
}
if (pmadapter->coex_win_size &&
pmadapter->coex_rx_win_size)
priv->add_ba_param.rx_win_size =
pmadapter->coex_rx_win_size;
if (rx_win_size != priv->add_ba_param.rx_win_size) {
if (priv->media_connected == MTRUE) {
for (i = 0; i < MAX_NUM_TID; i++)
wlan_11n_delba(priv, i);
wlan_recv_event(priv,
MLAN_EVENT_ID_DRV_DEFER_HANDLING,
MNULL);
}
}
}
}
LEAVE();
return;
}
/**
* @brief This function updates ampdu rx_win_size
*
* @param pmadapter A pointer to mlan_adapter
*
* @return N/A
*/
void
wlan_coex_ampdu_rxwinsize(pmlan_adapter pmadapter)
{
t_u8 i;
pmlan_private priv = MNULL;
t_u8 count = 0;
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i]) {
priv = pmadapter->priv[i];
#ifdef STA_SUPPORT
if (GET_BSS_ROLE((mlan_private *)priv) ==
MLAN_BSS_ROLE_STA) {
if (priv->media_connected == MTRUE)
count++;
}
#endif
#ifdef UAP_SUPPORT
if (GET_BSS_ROLE((mlan_private *)priv) ==
MLAN_BSS_ROLE_UAP) {
if (priv->uap_bss_started)
count++;
}
#endif
}
if (count >= 2)
break;
}
if (count >= 2)
wlan_update_ampdu_rxwinsize(pmadapter, MTRUE);
else
wlan_update_ampdu_rxwinsize(pmadapter, MFALSE);
return;
}