mirror of
https://github.com/Mange/rtl8192eu-linux-driver
synced 2024-11-22 21:45:22 +00:00
2a467a7923
Convert all rtw_zvmalloc calls within the driver to use the existing kernel vzalloc function, which has the same semantics. Also rewrite the two places where it is mentioned in comments to say vzalloc, and remove the redundant cast to struct adapter * in ./os_dep/usb_intf.c as vzalloc returns void *. The reason for the conversion is that rtw_zvmalloc is just a preprocessor definition for _rtw_zvmalloc which itself is just an inline wrapper around vmalloc which then zeroes the memory out. As vzalloc does the same thing via usage of __GFP_ZERO, this code is redundant and can subsequently be removed. Link: https://lore.kernel.org/r/20210818234853.208448-5-phil@philpotter.co.uk
5078 lines
142 KiB
C
5078 lines
142 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright(c) 2007 - 2017 Realtek Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
*****************************************************************************/
|
|
#define _RTW_RECV_C_
|
|
|
|
#include <drv_types.h>
|
|
#include <hal_data.h>
|
|
|
|
#if defined(PLATFORM_LINUX) && defined (PLATFORM_WINDOWS)
|
|
|
|
#error "Shall be Linux or Windows, but not both!\n"
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
static void rtw_signal_stat_timer_hdl(void *ctx);
|
|
|
|
enum {
|
|
SIGNAL_STAT_CALC_PROFILE_0 = 0,
|
|
SIGNAL_STAT_CALC_PROFILE_1,
|
|
SIGNAL_STAT_CALC_PROFILE_MAX
|
|
};
|
|
|
|
u8 signal_stat_calc_profile[SIGNAL_STAT_CALC_PROFILE_MAX][2] = {
|
|
{4, 1}, /* Profile 0 => pre_stat : curr_stat = 4 : 1 */
|
|
{3, 7} /* Profile 1 => pre_stat : curr_stat = 3 : 7 */
|
|
};
|
|
|
|
#ifndef RTW_SIGNAL_STATE_CALC_PROFILE
|
|
#define RTW_SIGNAL_STATE_CALC_PROFILE SIGNAL_STAT_CALC_PROFILE_1
|
|
#endif
|
|
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
u8 rtw_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
|
u8 rtw_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
|
static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
|
|
static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
|
|
#ifdef CONFIG_TDLS
|
|
static u8 SNAP_ETH_TYPE_TDLS[2] = {0x89, 0x0d};
|
|
#endif
|
|
|
|
#ifdef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe);
|
|
#endif
|
|
void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
|
|
{
|
|
|
|
|
|
|
|
memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv));
|
|
|
|
_rtw_spinlock_init(&psta_recvpriv->lock);
|
|
|
|
/* for(i=0; i<MAX_RX_NUMBLKS; i++) */
|
|
/* _rtw_init_queue(&psta_recvpriv->blk_strms[i]); */
|
|
|
|
_rtw_init_queue(&psta_recvpriv->defrag_q);
|
|
|
|
|
|
}
|
|
|
|
sint _rtw_init_recv_priv(struct recv_priv *precvpriv, _adapter *padapter)
|
|
{
|
|
sint i;
|
|
|
|
union recv_frame *precvframe;
|
|
sint res = _SUCCESS;
|
|
|
|
|
|
/* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
|
|
/* memset((unsigned char *)precvpriv, 0, sizeof (struct recv_priv)); */
|
|
|
|
_rtw_spinlock_init(&precvpriv->lock);
|
|
|
|
#ifdef CONFIG_RECV_THREAD_MODE
|
|
_rtw_init_sema(&precvpriv->recv_sema, 0);
|
|
|
|
#endif
|
|
|
|
_rtw_init_queue(&precvpriv->free_recv_queue);
|
|
_rtw_init_queue(&precvpriv->recv_pending_queue);
|
|
_rtw_init_queue(&precvpriv->uc_swdec_pending_queue);
|
|
|
|
precvpriv->adapter = padapter;
|
|
|
|
precvpriv->free_recvframe_cnt = NR_RECVFRAME;
|
|
|
|
precvpriv->sink_udpport = 0;
|
|
precvpriv->pre_rtp_rxseq = 0;
|
|
precvpriv->cur_rtp_rxseq = 0;
|
|
|
|
#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA
|
|
precvpriv->store_law_data_flag = 1;
|
|
#else
|
|
precvpriv->store_law_data_flag = 0;
|
|
#endif
|
|
|
|
rtw_os_recv_resource_init(precvpriv, padapter);
|
|
|
|
precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
|
|
|
|
if (precvpriv->pallocated_frame_buf == NULL) {
|
|
res = _FAIL;
|
|
goto exit;
|
|
}
|
|
/* memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); */
|
|
|
|
precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ);
|
|
/* precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + RXFRAME_ALIGN_SZ - */
|
|
/* ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); */
|
|
|
|
precvframe = (union recv_frame *) precvpriv->precv_frame_buf;
|
|
|
|
|
|
for (i = 0; i < NR_RECVFRAME ; i++) {
|
|
_rtw_init_listhead(&(precvframe->u.list));
|
|
|
|
rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
|
|
|
|
res = rtw_os_recv_resource_alloc(padapter, precvframe);
|
|
|
|
precvframe->u.hdr.len = 0;
|
|
|
|
precvframe->u.hdr.adapter = padapter;
|
|
precvframe++;
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_USB_HCI
|
|
|
|
atomic_set(&(precvpriv->rx_pending_cnt), 1);
|
|
|
|
_rtw_init_sema(&precvpriv->allrxreturnevt, 0);
|
|
|
|
#endif
|
|
|
|
res = rtw_hal_init_recv_priv(padapter);
|
|
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
rtw_init_timer(&precvpriv->signal_stat_timer, padapter, rtw_signal_stat_timer_hdl, padapter);
|
|
|
|
precvpriv->signal_stat_sampling_interval = 2000; /* ms */
|
|
/* precvpriv->signal_stat_converging_constant = 5000; */ /* ms */
|
|
|
|
rtw_set_signal_stat_timer(precvpriv);
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
exit:
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv);
|
|
void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv)
|
|
{
|
|
#ifdef CONFIG_RECV_THREAD_MODE
|
|
_rtw_free_sema(&precvpriv->recv_sema);
|
|
#endif
|
|
}
|
|
|
|
void _rtw_free_recv_priv(struct recv_priv *precvpriv)
|
|
{
|
|
_adapter *padapter = precvpriv->adapter;
|
|
|
|
|
|
rtw_free_uc_swdec_pending_queue(padapter);
|
|
|
|
rtw_os_recv_resource_free(precvpriv);
|
|
|
|
vfree(precvpriv->pallocated_frame_buf);
|
|
|
|
rtw_hal_free_recv_priv(padapter);
|
|
|
|
|
|
}
|
|
|
|
bool rtw_rframe_del_wfd_ie(union recv_frame *rframe, u8 ies_offset)
|
|
{
|
|
#define DBG_RFRAME_DEL_WFD_IE 0
|
|
u8 *ies = rframe->u.hdr.rx_data + sizeof(struct rtw_ieee80211_hdr_3addr) + ies_offset;
|
|
uint ies_len_ori = rframe->u.hdr.len - (ies - rframe->u.hdr.rx_data);
|
|
uint ies_len;
|
|
|
|
ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_RFRAME_DEL_WFD_IE ? __func__ : NULL);
|
|
rframe->u.hdr.len -= ies_len_ori - ies_len;
|
|
|
|
return ies_len_ori != ies_len;
|
|
}
|
|
|
|
union recv_frame *_rtw_alloc_recvframe(_queue *pfree_recv_queue)
|
|
{
|
|
|
|
union recv_frame *precvframe;
|
|
_list *plist, *phead;
|
|
_adapter *padapter;
|
|
struct recv_priv *precvpriv;
|
|
|
|
if (_rtw_queue_empty(pfree_recv_queue) == _TRUE)
|
|
precvframe = NULL;
|
|
else {
|
|
phead = get_list_head(pfree_recv_queue);
|
|
|
|
plist = get_next(phead);
|
|
|
|
precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
|
|
rtw_list_delete(&precvframe->u.hdr.list);
|
|
padapter = precvframe->u.hdr.adapter;
|
|
if (padapter != NULL) {
|
|
precvpriv = &padapter->recvpriv;
|
|
if (pfree_recv_queue == &precvpriv->free_recv_queue)
|
|
precvpriv->free_recvframe_cnt--;
|
|
}
|
|
}
|
|
|
|
|
|
return precvframe;
|
|
|
|
}
|
|
|
|
union recv_frame *rtw_alloc_recvframe(_queue *pfree_recv_queue)
|
|
{
|
|
_irqL irqL;
|
|
union recv_frame *precvframe;
|
|
|
|
_enter_critical_bh(&pfree_recv_queue->lock, &irqL);
|
|
|
|
precvframe = _rtw_alloc_recvframe(pfree_recv_queue);
|
|
|
|
_exit_critical_bh(&pfree_recv_queue->lock, &irqL);
|
|
|
|
return precvframe;
|
|
}
|
|
|
|
void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv)
|
|
{
|
|
/* Perry: This can be removed */
|
|
_rtw_init_listhead(&precvframe->u.hdr.list);
|
|
|
|
precvframe->u.hdr.len = 0;
|
|
}
|
|
|
|
int rtw_free_recvframe(union recv_frame *precvframe, _queue *pfree_recv_queue)
|
|
{
|
|
_irqL irqL;
|
|
_adapter *padapter = precvframe->u.hdr.adapter;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
|
|
|
|
#ifdef CONFIG_CONCURRENT_MODE
|
|
padapter = GET_PRIMARY_ADAPTER(padapter);
|
|
precvpriv = &padapter->recvpriv;
|
|
pfree_recv_queue = &precvpriv->free_recv_queue;
|
|
precvframe->u.hdr.adapter = padapter;
|
|
#endif
|
|
|
|
|
|
rtw_os_free_recvframe(precvframe);
|
|
|
|
|
|
_enter_critical_bh(&pfree_recv_queue->lock, &irqL);
|
|
|
|
rtw_list_delete(&(precvframe->u.hdr.list));
|
|
|
|
precvframe->u.hdr.len = 0;
|
|
|
|
rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
|
|
|
|
if (padapter != NULL) {
|
|
if (pfree_recv_queue == &precvpriv->free_recv_queue)
|
|
precvpriv->free_recvframe_cnt++;
|
|
}
|
|
|
|
_exit_critical_bh(&pfree_recv_queue->lock, &irqL);
|
|
|
|
|
|
return _SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sint _rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue)
|
|
{
|
|
|
|
_adapter *padapter = precvframe->u.hdr.adapter;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
|
|
|
|
/* _rtw_init_listhead(&(precvframe->u.hdr.list)); */
|
|
rtw_list_delete(&(precvframe->u.hdr.list));
|
|
|
|
|
|
rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue));
|
|
|
|
if (padapter != NULL) {
|
|
if (queue == &precvpriv->free_recv_queue)
|
|
precvpriv->free_recvframe_cnt++;
|
|
}
|
|
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|
|
sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue)
|
|
{
|
|
sint ret;
|
|
_irqL irqL;
|
|
|
|
/* _spinlock(&pfree_recv_queue->lock); */
|
|
_enter_critical_bh(&queue->lock, &irqL);
|
|
ret = _rtw_enqueue_recvframe(precvframe, queue);
|
|
/* _rtw_spinunlock(&pfree_recv_queue->lock); */
|
|
_exit_critical_bh(&queue->lock, &irqL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue)
|
|
{
|
|
return rtw_free_recvframe(precvframe, queue);
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
caller : defrag ; recvframe_chk_defrag in recv_thread (passive)
|
|
pframequeue: defrag_queue : will be accessed in recv_thread (passive)
|
|
|
|
using spinlock to protect
|
|
|
|
*/
|
|
|
|
void rtw_free_recvframe_queue(_queue *pframequeue, _queue *pfree_recv_queue)
|
|
{
|
|
union recv_frame *precvframe;
|
|
_list *plist, *phead;
|
|
|
|
_rtw_spinlock(&pframequeue->lock);
|
|
|
|
phead = get_list_head(pframequeue);
|
|
plist = get_next(phead);
|
|
|
|
while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
|
|
precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
|
|
plist = get_next(plist);
|
|
|
|
/* rtw_list_delete(&precvframe->u.hdr.list); */ /* will do this in rtw_free_recvframe() */
|
|
|
|
rtw_free_recvframe(precvframe, pfree_recv_queue);
|
|
}
|
|
|
|
_rtw_spinunlock(&pframequeue->lock);
|
|
|
|
|
|
}
|
|
|
|
u32 rtw_free_uc_swdec_pending_queue(_adapter *adapter)
|
|
{
|
|
u32 cnt = 0;
|
|
union recv_frame *pending_frame;
|
|
while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
|
|
rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
|
|
cnt++;
|
|
}
|
|
|
|
if (cnt)
|
|
RTW_INFO(FUNC_ADPT_FMT" dequeue %d\n", FUNC_ADPT_ARG(adapter), cnt);
|
|
|
|
return cnt;
|
|
}
|
|
|
|
|
|
sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, _queue *queue)
|
|
{
|
|
_irqL irqL;
|
|
|
|
_enter_critical_bh(&queue->lock, &irqL);
|
|
|
|
rtw_list_delete(&precvbuf->list);
|
|
rtw_list_insert_head(&precvbuf->list, get_list_head(queue));
|
|
|
|
_exit_critical_bh(&queue->lock, &irqL);
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|
|
sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, _queue *queue)
|
|
{
|
|
_irqL irqL;
|
|
#ifdef CONFIG_SDIO_HCI
|
|
_enter_critical_bh(&queue->lock, &irqL);
|
|
#else
|
|
_enter_critical_ex(&queue->lock, &irqL);
|
|
#endif/*#ifdef CONFIG_SDIO_HCI*/
|
|
|
|
rtw_list_delete(&precvbuf->list);
|
|
|
|
rtw_list_insert_tail(&precvbuf->list, get_list_head(queue));
|
|
#ifdef CONFIG_SDIO_HCI
|
|
_exit_critical_bh(&queue->lock, &irqL);
|
|
#else
|
|
_exit_critical_ex(&queue->lock, &irqL);
|
|
#endif/*#ifdef CONFIG_SDIO_HCI*/
|
|
return _SUCCESS;
|
|
|
|
}
|
|
|
|
struct recv_buf *rtw_dequeue_recvbuf(_queue *queue)
|
|
{
|
|
_irqL irqL;
|
|
struct recv_buf *precvbuf;
|
|
_list *plist, *phead;
|
|
|
|
#ifdef CONFIG_SDIO_HCI
|
|
_enter_critical_bh(&queue->lock, &irqL);
|
|
#else
|
|
_enter_critical_ex(&queue->lock, &irqL);
|
|
#endif/*#ifdef CONFIG_SDIO_HCI*/
|
|
|
|
if (_rtw_queue_empty(queue) == _TRUE)
|
|
precvbuf = NULL;
|
|
else {
|
|
phead = get_list_head(queue);
|
|
|
|
plist = get_next(phead);
|
|
|
|
precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list);
|
|
|
|
rtw_list_delete(&precvbuf->list);
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_SDIO_HCI
|
|
_exit_critical_bh(&queue->lock, &irqL);
|
|
#else
|
|
_exit_critical_ex(&queue->lock, &irqL);
|
|
#endif/*#ifdef CONFIG_SDIO_HCI*/
|
|
|
|
return precvbuf;
|
|
|
|
}
|
|
|
|
sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe);
|
|
sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe)
|
|
{
|
|
|
|
sint i, res = _SUCCESS;
|
|
u32 datalen;
|
|
u8 miccode[8];
|
|
u8 bmic_err = _FALSE, brpt_micerror = _TRUE;
|
|
u8 *pframe, *payload, *pframemic;
|
|
u8 *mickey;
|
|
/* u8 *iv,rxdata_key_idx=0; */
|
|
struct sta_info *stainfo;
|
|
struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib;
|
|
struct security_priv *psecuritypriv = &adapter->securitypriv;
|
|
|
|
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
|
|
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
|
|
|
|
stainfo = rtw_get_stainfo(&adapter->stapriv , &prxattrib->ta[0]);
|
|
|
|
if (prxattrib->encrypt == _TKIP_) {
|
|
|
|
/* calculate mic code */
|
|
if (stainfo != NULL) {
|
|
if (IS_MCAST(prxattrib->ra)) {
|
|
/* mickey=&psecuritypriv->dot118021XGrprxmickey.skey[0]; */
|
|
/* iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; */
|
|
/* rxdata_key_idx =( ((iv[3])>>6)&0x3) ; */
|
|
mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
|
|
|
|
/* RTW_INFO("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d),pmlmeinfo->key_index(%d) ,recv key_id(%d)\n", */
|
|
/* psecuritypriv->dot118021XGrpKeyid,pmlmeinfo->key_index,rxdata_key_idx); */
|
|
|
|
if (psecuritypriv->binstallGrpkey == _FALSE) {
|
|
res = _FAIL;
|
|
RTW_INFO("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n");
|
|
goto exit;
|
|
}
|
|
} else {
|
|
mickey = &stainfo->dot11tkiprxmickey.skey[0];
|
|
}
|
|
|
|
datalen = precvframe->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len - prxattrib->icv_len - 8; /* icv_len included the mic code */
|
|
pframe = precvframe->u.hdr.rx_data;
|
|
payload = pframe + prxattrib->hdrlen + prxattrib->iv_len;
|
|
|
|
|
|
/* rtw_seccalctkipmic(&stainfo->dot11tkiprxmickey.skey[0],pframe,payload, datalen ,&miccode[0],(unsigned char)prxattrib->priority); */ /* care the length of the data */
|
|
|
|
rtw_seccalctkipmic(mickey, pframe, payload, datalen , &miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */
|
|
|
|
pframemic = payload + datalen;
|
|
|
|
bmic_err = _FALSE;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
if (miccode[i] != *(pframemic + i)) {
|
|
bmic_err = _TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
if (bmic_err == _TRUE) {
|
|
|
|
|
|
|
|
/* double check key_index for some timing issue , */
|
|
/* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
|
|
if ((IS_MCAST(prxattrib->ra) == _TRUE) && (prxattrib->key_index != pmlmeinfo->key_index))
|
|
brpt_micerror = _FALSE;
|
|
|
|
if ((prxattrib->bdecrypted == _TRUE) && (brpt_micerror == _TRUE)) {
|
|
rtw_handle_tkip_mic_err(adapter, stainfo, (u8)IS_MCAST(prxattrib->ra));
|
|
RTW_INFO(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
|
|
} else {
|
|
RTW_INFO(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
|
|
}
|
|
|
|
res = _FAIL;
|
|
|
|
} else {
|
|
/* mic checked ok */
|
|
if ((psecuritypriv->bcheck_grpkey == _FALSE) && (IS_MCAST(prxattrib->ra) == _TRUE)) {
|
|
psecuritypriv->bcheck_grpkey = _TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
recvframe_pull_tail(precvframe, 8);
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
/*#define DBG_RX_SW_DECRYPTOR*/
|
|
|
|
/* decrypt and set the ivlen,icvlen of the recv_frame */
|
|
union recv_frame *decryptor(_adapter *padapter, union recv_frame *precv_frame);
|
|
union recv_frame *decryptor(_adapter *padapter, union recv_frame *precv_frame)
|
|
{
|
|
|
|
struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
|
|
struct security_priv *psecuritypriv = &padapter->securitypriv;
|
|
union recv_frame *return_packet = precv_frame;
|
|
u32 res = _SUCCESS;
|
|
|
|
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt);
|
|
|
|
|
|
if (prxattrib->encrypt > 0) {
|
|
u8 *iv = precv_frame->u.hdr.rx_data + prxattrib->hdrlen;
|
|
prxattrib->key_index = (((iv[3]) >> 6) & 0x3) ;
|
|
|
|
if (prxattrib->key_index > WEP_KEYS) {
|
|
RTW_INFO("prxattrib->key_index(%d) > WEP_KEYS\n", prxattrib->key_index);
|
|
|
|
switch (prxattrib->encrypt) {
|
|
case _WEP40_:
|
|
case _WEP104_:
|
|
prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex;
|
|
break;
|
|
case _TKIP_:
|
|
case _AES_:
|
|
default:
|
|
prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prxattrib->encrypt && !prxattrib->bdecrypted) {
|
|
if (GetFrameType(get_recvframe_data(precv_frame)) == WIFI_DATA
|
|
#ifdef CONFIG_CONCURRENT_MODE
|
|
&& !IS_MCAST(prxattrib->ra) /* bc/mc packets may use sw decryption for concurrent mode */
|
|
#endif
|
|
)
|
|
psecuritypriv->hw_decrypted = _FALSE;
|
|
|
|
#ifdef DBG_RX_SW_DECRYPTOR
|
|
RTW_INFO(ADPT_FMT" - sec_type:%s DO SW decryption\n",
|
|
ADPT_ARG(padapter), security_type_str(prxattrib->encrypt));
|
|
#endif
|
|
|
|
#ifdef DBG_RX_DECRYPTOR
|
|
RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n",
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
prxattrib->bdecrypted,
|
|
prxattrib->encrypt,
|
|
psecuritypriv->hw_decrypted);
|
|
#endif
|
|
|
|
switch (prxattrib->encrypt) {
|
|
case _WEP40_:
|
|
case _WEP104_:
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wep);
|
|
rtw_wep_decrypt(padapter, (u8 *)precv_frame);
|
|
break;
|
|
case _TKIP_:
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_tkip);
|
|
res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame);
|
|
break;
|
|
case _AES_:
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_aes);
|
|
res = rtw_aes_decrypt(padapter, (u8 *)precv_frame);
|
|
break;
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
case _SMS4_:
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wapi);
|
|
rtw_sms4_decrypt(padapter, (u8 *)precv_frame);
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
} else if (prxattrib->bdecrypted == 1
|
|
&& prxattrib->encrypt > 0
|
|
&& (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)
|
|
) {
|
|
#if 0
|
|
if ((prxstat->icv == 1) && (prxattrib->encrypt != _AES_)) {
|
|
psecuritypriv->hw_decrypted = _FALSE;
|
|
|
|
|
|
rtw_free_recvframe(precv_frame, &padapter->recvpriv.free_recv_queue);
|
|
|
|
return_packet = NULL;
|
|
|
|
} else
|
|
#endif
|
|
{
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_hw);
|
|
|
|
psecuritypriv->hw_decrypted = _TRUE;
|
|
#ifdef DBG_RX_DECRYPTOR
|
|
RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n",
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
prxattrib->bdecrypted,
|
|
prxattrib->encrypt,
|
|
psecuritypriv->hw_decrypted);
|
|
|
|
#endif
|
|
}
|
|
} else {
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_unknown);
|
|
#ifdef DBG_RX_DECRYPTOR
|
|
RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n",
|
|
__FUNCTION__,
|
|
__LINE__,
|
|
prxattrib->bdecrypted,
|
|
prxattrib->encrypt,
|
|
psecuritypriv->hw_decrypted);
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (res != _FAIL
|
|
&& !prxattrib->amsdu
|
|
&& prxattrib->mesh_ctrl_present)
|
|
res = rtw_mesh_rx_validate_mctrl_non_amsdu(padapter, precv_frame);
|
|
#endif
|
|
|
|
if (res == _FAIL) {
|
|
rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue);
|
|
return_packet = NULL;
|
|
} else
|
|
prxattrib->bdecrypted = _TRUE;
|
|
/* recvframe_chkmic(adapter, precv_frame); */ /* move to recvframme_defrag function */
|
|
|
|
|
|
return return_packet;
|
|
|
|
}
|
|
/* ###set the security information in the recv_frame */
|
|
union recv_frame *portctrl(_adapter *adapter, union recv_frame *precv_frame);
|
|
union recv_frame *portctrl(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
u8 *psta_addr = NULL;
|
|
u8 *ptr;
|
|
uint auth_alg;
|
|
struct recv_frame_hdr *pfhdr;
|
|
struct sta_info *psta;
|
|
struct sta_priv *pstapriv ;
|
|
union recv_frame *prtnframe;
|
|
u16 ether_type = 0;
|
|
u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */
|
|
struct rx_pkt_attrib *pattrib;
|
|
|
|
|
|
pstapriv = &adapter->stapriv;
|
|
|
|
auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
|
|
|
|
ptr = get_recvframe_data(precv_frame);
|
|
pfhdr = &precv_frame->u.hdr;
|
|
pattrib = &pfhdr->attrib;
|
|
psta_addr = pattrib->ta;
|
|
|
|
prtnframe = NULL;
|
|
|
|
psta = rtw_get_stainfo(pstapriv, psta_addr);
|
|
|
|
|
|
if (auth_alg == dot11AuthAlgrthm_8021X) {
|
|
if ((psta != NULL) && (psta->ieee8021x_blocked)) {
|
|
/* blocked */
|
|
/* only accept EAPOL frame */
|
|
|
|
prtnframe = precv_frame;
|
|
|
|
/* get ether_type */
|
|
ptr = ptr + pfhdr->attrib.hdrlen + pfhdr->attrib.iv_len + LLC_HEADER_SIZE;
|
|
_rtw_memcpy(ðer_type, ptr, 2);
|
|
ether_type = ntohs((unsigned short)ether_type);
|
|
|
|
if (ether_type == eapol_type)
|
|
prtnframe = precv_frame;
|
|
else {
|
|
/* free this frame */
|
|
rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue);
|
|
prtnframe = NULL;
|
|
}
|
|
} else {
|
|
/* allowed */
|
|
/* check decryption status, and decrypt the frame if needed */
|
|
|
|
|
|
prtnframe = precv_frame;
|
|
/* check is the EAPOL frame or not (Rekey) */
|
|
/* if(ether_type == eapol_type){ */
|
|
/* check Rekey */
|
|
|
|
/* prtnframe=precv_frame; */
|
|
/* } */
|
|
}
|
|
} else
|
|
prtnframe = precv_frame;
|
|
|
|
|
|
return prtnframe;
|
|
|
|
}
|
|
|
|
/* VALID_PN_CHK
|
|
* Return true when PN is legal, otherwise false.
|
|
* Legal PN:
|
|
* 1. If old PN is 0, any PN is legal
|
|
* 2. PN > old PN
|
|
*/
|
|
#define PN_LESS_CHK(a, b) (((a-b) & 0x800000000000) != 0)
|
|
#define VALID_PN_CHK(new, old) (((old) == 0) || PN_LESS_CHK(old, new))
|
|
#define CCMPH_2_KEYID(ch) (((ch) & 0x00000000c0000000) >> 30)
|
|
sint recv_ucast_pn_decache(union recv_frame *precv_frame);
|
|
sint recv_ucast_pn_decache(union recv_frame *precv_frame)
|
|
{
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct sta_info *sta = precv_frame->u.hdr.psta;
|
|
struct stainfo_rxcache *prxcache = &sta->sta_recvpriv.rxcache;
|
|
u8 *pdata = precv_frame->u.hdr.rx_data;
|
|
sint tid = precv_frame->u.hdr.attrib.priority;
|
|
u64 tmp_iv_hdr = 0;
|
|
u64 curr_pn = 0, pkt_pn = 0;
|
|
|
|
if (tid > 15)
|
|
return _FAIL;
|
|
|
|
if (pattrib->encrypt == _AES_) {
|
|
tmp_iv_hdr = le64_to_cpu(*(u64*)(pdata + pattrib->hdrlen));
|
|
pkt_pn = CCMPH_2_PN(tmp_iv_hdr);
|
|
tmp_iv_hdr = le64_to_cpu(*(u64*)prxcache->iv[tid]);
|
|
curr_pn = CCMPH_2_PN(tmp_iv_hdr);
|
|
|
|
if (!VALID_PN_CHK(pkt_pn, curr_pn)) {
|
|
/* return _FAIL; */
|
|
} else {
|
|
prxcache->last_tid = tid;
|
|
_rtw_memcpy(prxcache->iv[tid],
|
|
(pdata + pattrib->hdrlen),
|
|
sizeof(prxcache->iv[tid]));
|
|
}
|
|
}
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|
|
sint recv_bcast_pn_decache(union recv_frame *precv_frame);
|
|
sint recv_bcast_pn_decache(union recv_frame *precv_frame)
|
|
{
|
|
_adapter *padapter = precv_frame->u.hdr.adapter;
|
|
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
|
|
struct security_priv *psecuritypriv = &padapter->securitypriv;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
u8 *pdata = precv_frame->u.hdr.rx_data;
|
|
u64 tmp_iv_hdr = 0;
|
|
u64 curr_pn = 0, pkt_pn = 0;
|
|
u8 key_id;
|
|
|
|
if ((pattrib->encrypt == _AES_) &&
|
|
(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) {
|
|
|
|
tmp_iv_hdr = le64_to_cpu(*(u64*)(pdata + pattrib->hdrlen));
|
|
key_id = CCMPH_2_KEYID(tmp_iv_hdr);
|
|
pkt_pn = CCMPH_2_PN(tmp_iv_hdr);
|
|
|
|
curr_pn = le64_to_cpu(*(u64*)psecuritypriv->iv_seq[key_id]);
|
|
curr_pn &= 0x0000ffffffffffff;
|
|
|
|
if (!VALID_PN_CHK(pkt_pn, curr_pn))
|
|
return _FAIL;
|
|
|
|
*(u64*)psecuritypriv->iv_seq[key_id] = cpu_to_le64(pkt_pn);
|
|
}
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|
|
sint recv_decache(union recv_frame *precv_frame)
|
|
{
|
|
struct sta_info *psta = precv_frame->u.hdr.psta;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
_adapter *adapter = psta->padapter;
|
|
sint tid = pattrib->priority;
|
|
u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num & 0xffff) << 4) |
|
|
(precv_frame->u.hdr.attrib.frag_num & 0xf);
|
|
u16 *prxseq;
|
|
|
|
if (tid > 15)
|
|
return _FAIL;
|
|
|
|
if (pattrib->qos) {
|
|
if (IS_MCAST(pattrib->ra))
|
|
prxseq = &psta->sta_recvpriv.bmc_tid_rxseq[tid];
|
|
else
|
|
prxseq = &psta->sta_recvpriv.rxcache.tid_rxseq[tid];
|
|
} else {
|
|
if (IS_MCAST(pattrib->ra)) {
|
|
prxseq = &psta->sta_recvpriv.nonqos_bmc_rxseq;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" nonqos bmc seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(adapter), pattrib->seq_num);
|
|
#endif
|
|
|
|
} else {
|
|
prxseq = &psta->sta_recvpriv.nonqos_rxseq;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" nonqos seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(adapter), pattrib->seq_num);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (seq_ctrl == *prxseq) {
|
|
/* for non-AMPDU case */
|
|
psta->sta_stats.duplicate_cnt++;
|
|
|
|
if (psta->sta_stats.duplicate_cnt % 100 == 0)
|
|
RTW_INFO("%s: tid=%u seq=%d frag=%d\n", __func__
|
|
, tid, precv_frame->u.hdr.attrib.seq_num
|
|
, precv_frame->u.hdr.attrib.frag_num);
|
|
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" recv_decache _FAIL for sta="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(psta->cmn.mac_addr));
|
|
#endif
|
|
return _FAIL;
|
|
}
|
|
*prxseq = seq_ctrl;
|
|
|
|
return _SUCCESS;
|
|
}
|
|
|
|
void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta)
|
|
{
|
|
#ifdef CONFIG_AP_MODE
|
|
unsigned char pwrbit;
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
|
|
pwrbit = GetPwrMgt(ptr);
|
|
|
|
if (pwrbit) {
|
|
if (!(psta->state & WIFI_SLEEP_STATE)) {
|
|
/* psta->state |= WIFI_SLEEP_STATE; */
|
|
/* rtw_tim_map_set(padapter, pstapriv->sta_dz_bitmap, BIT(psta->cmn.aid)); */
|
|
|
|
stop_sta_xmit(padapter, psta);
|
|
/* RTW_INFO_DUMP("to sleep, sta_dz_bitmap=", pstapriv->sta_dz_bitmap, pstapriv->aid_bmp_len); */
|
|
}
|
|
} else {
|
|
if (psta->state & WIFI_SLEEP_STATE) {
|
|
/* psta->state ^= WIFI_SLEEP_STATE; */
|
|
/* rtw_tim_map_clear(padapter, pstapriv->sta_dz_bitmap, BIT(psta->cmn.aid)); */
|
|
|
|
wakeup_sta_to_xmit(padapter, psta);
|
|
/* RTW_INFO_DUMP("to wakeup, sta_dz_bitmap=", pstapriv->sta_dz_bitmap, pstapriv->aid_bmp_len); */
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta)
|
|
{
|
|
#ifdef CONFIG_AP_MODE
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
|
|
#ifdef CONFIG_TDLS
|
|
if (!(psta->tdls_sta_state & TDLS_LINKED_STATE)) {
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
if (!psta->qos_option)
|
|
return;
|
|
|
|
if (!(psta->qos_info & 0xf))
|
|
return;
|
|
|
|
#ifdef CONFIG_TDLS
|
|
}
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
if (psta->state & WIFI_SLEEP_STATE) {
|
|
u8 wmmps_ac = 0;
|
|
|
|
switch (pattrib->priority) {
|
|
case 1:
|
|
case 2:
|
|
wmmps_ac = psta->uapsd_bk & BIT(1);
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
wmmps_ac = psta->uapsd_vi & BIT(1);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
wmmps_ac = psta->uapsd_vo & BIT(1);
|
|
break;
|
|
case 0:
|
|
case 3:
|
|
default:
|
|
wmmps_ac = psta->uapsd_be & BIT(1);
|
|
break;
|
|
}
|
|
|
|
if (wmmps_ac) {
|
|
if (psta->sleepq_ac_len > 0) {
|
|
/* process received triggered frame */
|
|
xmit_delivery_enabled_frames(padapter, psta);
|
|
} else {
|
|
/* issue one qos null frame with More data bit = 0 and the EOSP bit set (=1) */
|
|
issue_qos_nulldata(padapter, psta->cmn.mac_addr, (u16)pattrib->priority, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_TDLS
|
|
sint OnTDLS(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
sint ret = _SUCCESS;
|
|
u8 *paction = get_recvframe_data(precv_frame);
|
|
u8 category_field = 1;
|
|
#ifdef CONFIG_WFD
|
|
u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a };
|
|
#endif /* CONFIG_WFD */
|
|
struct tdls_info *ptdlsinfo = &(adapter->tdlsinfo);
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
struct sta_priv *pstapriv = &(adapter->stapriv);
|
|
struct sta_info *ptdls_sta = NULL;
|
|
|
|
/* point to action field */
|
|
paction += pattrib->hdrlen
|
|
+ pattrib->iv_len
|
|
+ SNAP_SIZE
|
|
+ ETH_TYPE_LEN
|
|
+ PAYLOAD_TYPE_LEN
|
|
+ category_field;
|
|
|
|
RTW_INFO("[TDLS] Recv %s from "MAC_FMT" with SeqNum = %d\n", rtw_tdls_action_txt(*paction), MAC_ARG(pattrib->src), GetSequence(get_recvframe_data(precv_frame)));
|
|
|
|
if (hal_chk_wl_func(adapter, WL_FUNC_TDLS) == _FALSE) {
|
|
RTW_INFO("Ignore tdls frame since hal doesn't support tdls\n");
|
|
ret = _FAIL;
|
|
return ret;
|
|
}
|
|
|
|
if (rtw_is_tdls_enabled(adapter) == _FALSE) {
|
|
RTW_INFO("recv tdls frame, "
|
|
"but tdls haven't enabled\n");
|
|
ret = _FAIL;
|
|
return ret;
|
|
}
|
|
|
|
ptdls_sta = rtw_get_stainfo(pstapriv, get_sa(ptr));
|
|
if (ptdls_sta == NULL) {
|
|
switch (*paction) {
|
|
case TDLS_SETUP_REQUEST:
|
|
case TDLS_DISCOVERY_REQUEST:
|
|
break;
|
|
default:
|
|
RTW_INFO("[TDLS] %s - Direct Link Peer = "MAC_FMT" not found for action = %d\n", __func__, MAC_ARG(get_sa(ptr)), *paction);
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
switch (*paction) {
|
|
case TDLS_SETUP_REQUEST:
|
|
ret = On_TDLS_Setup_Req(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_SETUP_RESPONSE:
|
|
ret = On_TDLS_Setup_Rsp(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_SETUP_CONFIRM:
|
|
ret = On_TDLS_Setup_Cfm(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_TEARDOWN:
|
|
ret = On_TDLS_Teardown(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_DISCOVERY_REQUEST:
|
|
ret = On_TDLS_Dis_Req(adapter, precv_frame);
|
|
break;
|
|
case TDLS_PEER_TRAFFIC_INDICATION:
|
|
ret = On_TDLS_Peer_Traffic_Indication(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_PEER_TRAFFIC_RESPONSE:
|
|
ret = On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
#ifdef CONFIG_TDLS_CH_SW
|
|
case TDLS_CHANNEL_SWITCH_REQUEST:
|
|
ret = On_TDLS_Ch_Switch_Req(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
case TDLS_CHANNEL_SWITCH_RESPONSE:
|
|
ret = On_TDLS_Ch_Switch_Rsp(adapter, precv_frame, ptdls_sta);
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_WFD
|
|
/* First byte of WFA OUI */
|
|
case 0x50:
|
|
if (_rtw_memcmp(WFA_OUI, paction, 3)) {
|
|
/* Probe request frame */
|
|
if (*(paction + 3) == 0x04) {
|
|
/* WFDTDLS: for sigma test, do not setup direct link automatically */
|
|
ptdlsinfo->dev_discovered = _TRUE;
|
|
RTW_INFO("recv tunneled probe request frame\n");
|
|
issue_tunneled_probe_rsp(adapter, precv_frame);
|
|
}
|
|
/* Probe response frame */
|
|
if (*(paction + 3) == 0x05) {
|
|
/* WFDTDLS: for sigma test, do not setup direct link automatically */
|
|
ptdlsinfo->dev_discovered = _TRUE;
|
|
RTW_INFO("recv tunneled probe response frame\n");
|
|
}
|
|
}
|
|
break;
|
|
#endif /* CONFIG_WFD */
|
|
default:
|
|
RTW_INFO("receive TDLS frame %d but not support\n", *paction);
|
|
ret = _FAIL;
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
|
|
}
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info *sta)
|
|
{
|
|
int sz;
|
|
struct sta_info *psta = NULL;
|
|
struct stainfo_stats *pstats = NULL;
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
|
|
sz = get_recvframe_len(prframe);
|
|
precvpriv->rx_bytes += sz;
|
|
|
|
padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
|
|
|
|
if (!is_broadcast_ether_addr(pattrib->dst) && !IS_MCAST(pattrib->dst))
|
|
padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++;
|
|
|
|
if (sta)
|
|
psta = sta;
|
|
else
|
|
psta = prframe->u.hdr.psta;
|
|
|
|
if (psta) {
|
|
u8 is_ra_bmc = IS_MCAST(pattrib->ra);
|
|
|
|
pstats = &psta->sta_stats;
|
|
|
|
pstats->last_rx_time = rtw_get_current_time();
|
|
pstats->rx_data_pkts++;
|
|
pstats->rx_bytes += sz;
|
|
if (is_broadcast_mac_addr(pattrib->ra)) {
|
|
pstats->rx_data_bc_pkts++;
|
|
pstats->rx_bc_bytes += sz;
|
|
} else if (is_ra_bmc) {
|
|
pstats->rx_data_mc_pkts++;
|
|
pstats->rx_mc_bytes += sz;
|
|
}
|
|
|
|
if (!is_ra_bmc) {
|
|
pstats->rxratecnt[pattrib->data_rate]++;
|
|
/*record rx packets for every tid*/
|
|
pstats->rx_data_qos_pkts[pattrib->priority]++;
|
|
}
|
|
#ifdef CONFIG_DYNAMIC_SOML
|
|
rtw_dyn_soml_byte_update(padapter, pattrib->data_rate, sz);
|
|
#endif
|
|
#if defined(CONFIG_CHECK_LEAVE_LPS) && defined(CONFIG_LPS_CHK_BY_TP)
|
|
if (adapter_to_pwrctl(padapter)->lps_chk_by_tp)
|
|
traffic_check_for_leave_lps_by_tp(padapter, _FALSE, psta);
|
|
#endif /* CONFIG_LPS */
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_CHECK_LEAVE_LPS
|
|
#ifdef CONFIG_LPS_CHK_BY_TP
|
|
if (!adapter_to_pwrctl(padapter)->lps_chk_by_tp)
|
|
#endif
|
|
traffic_check_for_leave_lps(padapter, _FALSE, 0);
|
|
#endif /* CONFIG_CHECK_LEAVE_LPS */
|
|
|
|
}
|
|
|
|
sint sta2sta_data_frame(
|
|
_adapter *adapter,
|
|
union recv_frame *precv_frame,
|
|
struct sta_info **psta
|
|
)
|
|
{
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
sint ret = _SUCCESS;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct sta_priv *pstapriv = &adapter->stapriv;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
u8 *mybssid = get_bssid(pmlmepriv);
|
|
u8 *myhwaddr = adapter_mac_addr(adapter);
|
|
u8 *sta_addr = pattrib->ta;
|
|
sint bmcast = IS_MCAST(pattrib->dst);
|
|
|
|
#ifdef CONFIG_TDLS
|
|
struct tdls_info *ptdlsinfo = &adapter->tdlsinfo;
|
|
#ifdef CONFIG_TDLS_CH_SW
|
|
struct tdls_ch_switch *pchsw_info = &ptdlsinfo->chsw_info;
|
|
#endif
|
|
struct sta_info *ptdls_sta = NULL;
|
|
u8 *psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
|
|
/* frame body located after [+2]: ether-type, [+1]: payload type */
|
|
u8 *pframe_body = psnap_type + 2 + 1;
|
|
#endif
|
|
|
|
|
|
/* RTW_INFO("[%s] %d, seqnum:%d\n", __FUNCTION__, __LINE__, pattrib->seq_num); */
|
|
|
|
if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) ||
|
|
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) {
|
|
|
|
/* filter packets that SA is myself or multicast or broadcast */
|
|
if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
_rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
(!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
|
|
#ifdef CONFIG_TDLS
|
|
|
|
/* direct link data transfer */
|
|
if (ptdlsinfo->link_established == _TRUE) {
|
|
*psta = ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->ta);
|
|
if (ptdls_sta == NULL) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
} else if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) {
|
|
/* filter packets that SA is myself or multicast or broadcast */
|
|
if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
/* da should be for me */
|
|
if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
/* check BSSID */
|
|
if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
_rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
(!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef CONFIG_TDLS_CH_SW
|
|
if (atomic_read(&pchsw_info->chsw_on) == _TRUE) {
|
|
if (adapter->mlmeextpriv.cur_channel != rtw_get_oper_ch(adapter)) {
|
|
pchsw_info->ch_sw_state |= TDLS_PEER_AT_OFF_STATE;
|
|
if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE))
|
|
_cancel_timer_ex(&ptdls_sta->ch_sw_timer);
|
|
/* On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame); */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* process UAPSD tdls sta */
|
|
process_pwrbit_data(adapter, precv_frame, ptdls_sta);
|
|
|
|
/* if NULL-frame, check pwrbit */
|
|
if ((get_frame_sub_type(ptr) & WIFI_DATA_NULL) == WIFI_DATA_NULL) {
|
|
/* NULL-frame with pwrbit=1, buffer_STA should buffer frames for sleep_STA */
|
|
if (GetPwrMgt(ptr)) {
|
|
/* it would be triggered when we are off channel and receiving NULL DATA */
|
|
/* we can confirm that peer STA is at off channel */
|
|
RTW_INFO("TDLS: recv peer null frame with pwr bit 1\n");
|
|
/* ptdls_sta->tdls_sta_state|=TDLS_PEER_SLEEP_STATE; */
|
|
}
|
|
|
|
/* TODO: Updated BSSID's seq. */
|
|
/* RTW_INFO("drop Null Data\n"); */
|
|
ptdls_sta->tdls_sta_state &= ~(TDLS_WAIT_PTR_STATE);
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
/* receive some of all TDLS management frames, process it at ON_TDLS */
|
|
if (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, 2)) {
|
|
ret = OnTDLS(adapter, precv_frame);
|
|
goto exit;
|
|
}
|
|
|
|
if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE)
|
|
process_wmmps_data(adapter, precv_frame, ptdls_sta);
|
|
|
|
ptdls_sta->tdls_sta_state &= ~(TDLS_WAIT_PTR_STATE);
|
|
|
|
}
|
|
} else
|
|
#endif /* CONFIG_TDLS */
|
|
{
|
|
/* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */
|
|
if (!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
|
|
if (bmcast) {
|
|
/* For AP mode, if DA == MCAST, then BSSID should be also MCAST */
|
|
if (!IS_MCAST(pattrib->bssid)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
} else { /* not mc-frame */
|
|
/* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */
|
|
if (!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
} else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) {
|
|
_rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
|
|
|
|
sta_addr = mybssid;
|
|
} else
|
|
ret = _FAIL;
|
|
|
|
#ifdef CONFIG_TDLS
|
|
if (ptdls_sta == NULL)
|
|
#endif
|
|
*psta = rtw_get_stainfo(pstapriv, sta_addr);
|
|
|
|
if (*psta == NULL) {
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
if (adapter->registrypriv.mp_mode == 1) {
|
|
if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)
|
|
adapter->mppriv.rx_pktloss++;
|
|
}
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
|
|
}
|
|
|
|
sint ap2sta_data_frame(
|
|
_adapter *adapter,
|
|
union recv_frame *precv_frame,
|
|
struct sta_info **psta)
|
|
{
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
sint ret = _SUCCESS;
|
|
struct sta_priv *pstapriv = &adapter->stapriv;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
u8 *mybssid = get_bssid(pmlmepriv);
|
|
u8 *myhwaddr = adapter_mac_addr(adapter);
|
|
sint bmcast = IS_MCAST(pattrib->dst);
|
|
|
|
|
|
if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
|
|
&& (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE
|
|
|| check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE)
|
|
) {
|
|
|
|
/* filter packets that SA is myself or multicast or broadcast */
|
|
if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" SA="MAC_FMT", myhwaddr="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(pattrib->src), MAC_ARG(myhwaddr));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
/* da should be for me */
|
|
if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(pattrib->dst));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
/* check BSSID */
|
|
if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
_rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
|
|
(!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" BSSID="MAC_FMT", mybssid="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(pattrib->bssid), MAC_ARG(mybssid));
|
|
#endif
|
|
#ifndef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
if (!bmcast
|
|
&& !IS_RADAR_DETECTED(adapter_to_rfctl(adapter))
|
|
) {
|
|
RTW_INFO(ADPT_FMT" -issue_deauth to the nonassociated ap=" MAC_FMT " for the reason(7)\n", ADPT_ARG(adapter), MAC_ARG(pattrib->bssid));
|
|
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
|
|
}
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
*psta = rtw_get_stainfo(pstapriv, pattrib->ta);
|
|
if (*psta == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" can't get psta under STATION_MODE ; drop pkt\n"
|
|
, FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
/*if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) {
|
|
}
|
|
*/
|
|
|
|
if (get_frame_sub_type(ptr) & BIT(6)) {
|
|
/* No data, will not indicate to upper layer, temporily count it here */
|
|
count_rx_stats(adapter, precv_frame, *psta);
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
}
|
|
|
|
} else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) &&
|
|
(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) {
|
|
_rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
|
|
|
|
|
|
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
|
|
if (*psta == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" can't get psta under WIFI_MP_STATE ; drop pkt\n"
|
|
, FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
|
|
/* Special case */
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
} else {
|
|
if (_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
|
|
*psta = rtw_get_stainfo(pstapriv, pattrib->ta);
|
|
if (*psta == NULL) {
|
|
|
|
/* for AP multicast issue , modify by yiwei */
|
|
static systime send_issue_deauth_time = 0;
|
|
|
|
/* RTW_INFO("After send deauth , %u ms has elapsed.\n", rtw_get_passing_time_ms(send_issue_deauth_time)); */
|
|
|
|
if (rtw_get_passing_time_ms(send_issue_deauth_time) > 10000 || send_issue_deauth_time == 0) {
|
|
send_issue_deauth_time = rtw_get_current_time();
|
|
|
|
RTW_INFO("issue_deauth to the ap=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid));
|
|
|
|
issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = _FAIL;
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" fw_state:0x%x\n"
|
|
, FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
|
|
#endif
|
|
}
|
|
|
|
exit:
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sint sta2ap_data_frame(
|
|
_adapter *adapter,
|
|
union recv_frame *precv_frame,
|
|
struct sta_info **psta)
|
|
{
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct sta_priv *pstapriv = &adapter->stapriv;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
unsigned char *mybssid = get_bssid(pmlmepriv);
|
|
sint ret = _SUCCESS;
|
|
|
|
|
|
if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) {
|
|
/* For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR */
|
|
if (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
*psta = rtw_get_stainfo(pstapriv, pattrib->ta);
|
|
if (*psta == NULL) {
|
|
if (!IS_RADAR_DETECTED(adapter_to_rfctl(adapter))) {
|
|
#ifndef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
RTW_INFO("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src));
|
|
issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
|
|
#endif
|
|
}
|
|
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
}
|
|
|
|
process_pwrbit_data(adapter, precv_frame, *psta);
|
|
|
|
if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE)
|
|
process_wmmps_data(adapter, precv_frame, *psta);
|
|
|
|
if (get_frame_sub_type(ptr) & BIT(6)) {
|
|
/* No data, will not indicate to upper layer, temporily count it here */
|
|
count_rx_stats(adapter, precv_frame, *psta);
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
}
|
|
} else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) &&
|
|
(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) {
|
|
/* RTW_INFO("%s ,in WIFI_MP_STATE\n",__func__); */
|
|
_rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
|
|
|
|
|
|
*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
|
|
if (*psta == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" can't get psta under WIFI_MP_STATE ; drop pkt\n"
|
|
, FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
} else {
|
|
u8 *myhwaddr = adapter_mac_addr(adapter);
|
|
if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
}
|
|
#ifndef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
RTW_INFO("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src));
|
|
issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
|
|
#endif
|
|
ret = RTW_RX_HANDLED;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame);
|
|
sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame)
|
|
{
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct sta_priv *pstapriv = &padapter->stapriv;
|
|
u8 *pframe = precv_frame->u.hdr.rx_data;
|
|
struct sta_info *psta = NULL;
|
|
/* uint len = precv_frame->u.hdr.len; */
|
|
|
|
/* RTW_INFO("+validate_recv_ctrl_frame\n"); */
|
|
|
|
if (GetFrameType(pframe) != WIFI_CTRL_TYPE)
|
|
return _FAIL;
|
|
|
|
/* receive the frames that ra(a1) is my address */
|
|
if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN))
|
|
return _FAIL;
|
|
|
|
psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe));
|
|
if (psta == NULL)
|
|
return _FAIL;
|
|
|
|
/* for rx pkt statistics */
|
|
psta->sta_stats.last_rx_time = rtw_get_current_time();
|
|
psta->sta_stats.rx_ctrl_pkts++;
|
|
|
|
/* only handle ps-poll */
|
|
if (get_frame_sub_type(pframe) == WIFI_PSPOLL) {
|
|
#ifdef CONFIG_AP_MODE
|
|
u16 aid;
|
|
u8 wmmps_ac = 0;
|
|
|
|
aid = GetAid(pframe);
|
|
if (psta->cmn.aid != aid)
|
|
return _FAIL;
|
|
|
|
switch (pattrib->priority) {
|
|
case 1:
|
|
case 2:
|
|
wmmps_ac = psta->uapsd_bk & BIT(0);
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
wmmps_ac = psta->uapsd_vi & BIT(0);
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
wmmps_ac = psta->uapsd_vo & BIT(0);
|
|
break;
|
|
case 0:
|
|
case 3:
|
|
default:
|
|
wmmps_ac = psta->uapsd_be & BIT(0);
|
|
break;
|
|
}
|
|
|
|
if (wmmps_ac)
|
|
return _FAIL;
|
|
|
|
if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
|
|
RTW_INFO("%s alive check-rx ps-poll\n", __func__);
|
|
psta->expire_to = pstapriv->expire_to;
|
|
psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
|
|
}
|
|
|
|
if ((psta->state & WIFI_SLEEP_STATE) && (rtw_tim_map_is_set(padapter, pstapriv->sta_dz_bitmap, psta->cmn.aid))) {
|
|
_irqL irqL;
|
|
_list *xmitframe_plist, *xmitframe_phead;
|
|
struct xmit_frame *pxmitframe = NULL;
|
|
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
|
|
|
|
/* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */
|
|
_enter_critical_bh(&pxmitpriv->lock, &irqL);
|
|
|
|
xmitframe_phead = get_list_head(&psta->sleep_q);
|
|
xmitframe_plist = get_next(xmitframe_phead);
|
|
|
|
if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) {
|
|
pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
|
|
|
|
xmitframe_plist = get_next(xmitframe_plist);
|
|
|
|
rtw_list_delete(&pxmitframe->list);
|
|
|
|
psta->sleepq_len--;
|
|
|
|
if (psta->sleepq_len > 0)
|
|
pxmitframe->attrib.mdata = 1;
|
|
else
|
|
pxmitframe->attrib.mdata = 0;
|
|
|
|
pxmitframe->attrib.triggered = 1;
|
|
|
|
/* RTW_INFO("handling ps-poll, q_len=%d\n", psta->sleepq_len); */
|
|
/* RTW_INFO_DUMP("handling, tim=", pstapriv->tim_bitmap, pstapriv->aid_bmp_len); */
|
|
|
|
#if 0
|
|
_exit_critical_bh(&psta->sleep_q.lock, &irqL);
|
|
if (rtw_hal_xmit(padapter, pxmitframe) == _TRUE)
|
|
rtw_os_xmit_complete(padapter, pxmitframe);
|
|
_enter_critical_bh(&psta->sleep_q.lock, &irqL);
|
|
#endif
|
|
rtw_hal_xmitframe_enqueue(padapter, pxmitframe);
|
|
|
|
if (psta->sleepq_len == 0) {
|
|
rtw_tim_map_clear(padapter, pstapriv->tim_bitmap, psta->cmn.aid);
|
|
|
|
/* RTW_INFO("after handling ps-poll\n"); */
|
|
/* RTW_INFO_DUMP("after handling, tim=", pstapriv->tim_bitmap, pstapriv->aid_bmp_len); */
|
|
|
|
/* upate BCN for TIM IE */
|
|
/* update_BCNTIM(padapter); */
|
|
update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
|
|
}
|
|
|
|
/* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */
|
|
_exit_critical_bh(&pxmitpriv->lock, &irqL);
|
|
|
|
} else {
|
|
/* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */
|
|
_exit_critical_bh(&pxmitpriv->lock, &irqL);
|
|
|
|
/* RTW_INFO("no buffered packets to xmit\n"); */
|
|
if (rtw_tim_map_is_set(padapter, pstapriv->tim_bitmap, psta->cmn.aid)) {
|
|
if (psta->sleepq_len == 0) {
|
|
RTW_INFO("no buffered packets to xmit\n");
|
|
|
|
/* issue nulldata with More data bit = 0 to indicate we have no buffered packets */
|
|
issue_nulldata(padapter, psta->cmn.mac_addr, 0, 0, 0);
|
|
} else {
|
|
RTW_INFO("error!psta->sleepq_len=%d\n", psta->sleepq_len);
|
|
psta->sleepq_len = 0;
|
|
}
|
|
|
|
rtw_tim_map_clear(padapter, pstapriv->tim_bitmap, psta->cmn.aid);
|
|
|
|
/* upate BCN for TIM IE */
|
|
/* update_BCNTIM(padapter); */
|
|
update_beacon(padapter, _TIM_IE_, NULL, _TRUE);
|
|
}
|
|
}
|
|
}
|
|
#endif /* CONFIG_AP_MODE */
|
|
} else if (get_frame_sub_type(pframe) == WIFI_NDPA) {
|
|
#ifdef CONFIG_BEAMFORMING
|
|
rtw_beamforming_get_ndpa_frame(padapter, precv_frame);
|
|
#endif/*CONFIG_BEAMFORMING*/
|
|
} else if (get_frame_sub_type(pframe) == WIFI_BAR) {
|
|
rtw_process_bar_frame(padapter, precv_frame);
|
|
}
|
|
|
|
return _FAIL;
|
|
|
|
}
|
|
|
|
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
|
|
static sint validate_mgmt_protect(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
#define DBG_VALIDATE_MGMT_PROTECT 0
|
|
#define DBG_VALIDATE_MGMT_DEC 0
|
|
|
|
struct security_priv *sec = &adapter->securitypriv;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct sta_info *psta = precv_frame->u.hdr.psta;
|
|
u8 *ptr;
|
|
u8 type;
|
|
u8 subtype;
|
|
u8 is_bmc;
|
|
u8 category = 0xFF;
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
const u8 *igtk;
|
|
u16 igtk_id;
|
|
u64* ipn;
|
|
#endif
|
|
|
|
u8 *mgmt_DATA;
|
|
u32 data_len = 0;
|
|
|
|
sint ret;
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (MLME_IS_MESH(adapter)) {
|
|
if (!adapter->mesh_info.mesh_auth_id)
|
|
return pattrib->privacy ? _FAIL : _SUCCESS;
|
|
} else
|
|
#endif
|
|
if (SEC_IS_BIP_KEY_INSTALLED(sec) == _FALSE)
|
|
return _SUCCESS;
|
|
|
|
ptr = precv_frame->u.hdr.rx_data;
|
|
type = GetFrameType(ptr);
|
|
subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */
|
|
is_bmc = IS_MCAST(GetAddr1Ptr(ptr));
|
|
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
if (subtype == WIFI_DEAUTH) {
|
|
RTW_INFO(FUNC_ADPT_FMT" bmc:%u, deauth, privacy:%u, encrypt:%u, bdecrypted:%u\n"
|
|
, FUNC_ADPT_ARG(adapter)
|
|
, is_bmc, pattrib->privacy, pattrib->encrypt, pattrib->bdecrypted);
|
|
} else if (subtype == WIFI_DISASSOC) {
|
|
RTW_INFO(FUNC_ADPT_FMT" bmc:%u, disassoc, privacy:%u, encrypt:%u, bdecrypted:%u\n"
|
|
, FUNC_ADPT_ARG(adapter)
|
|
, is_bmc, pattrib->privacy, pattrib->encrypt, pattrib->bdecrypted);
|
|
} if (subtype == WIFI_ACTION) {
|
|
if (pattrib->privacy) {
|
|
RTW_INFO(FUNC_ADPT_FMT" bmc:%u, action(?), privacy:%u, encrypt:%u, bdecrypted:%u\n"
|
|
, FUNC_ADPT_ARG(adapter)
|
|
, is_bmc, pattrib->privacy, pattrib->encrypt, pattrib->bdecrypted);
|
|
} else {
|
|
RTW_INFO(FUNC_ADPT_FMT" bmc:%u, action(%u), privacy:%u, encrypt:%u, bdecrypted:%u\n"
|
|
, FUNC_ADPT_ARG(adapter), is_bmc
|
|
, *(ptr + sizeof(struct rtw_ieee80211_hdr_3addr))
|
|
, pattrib->privacy, pattrib->encrypt, pattrib->bdecrypted);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!pattrib->privacy) {
|
|
if (!psta || !(psta->flags & WLAN_STA_MFP)) {
|
|
/* peer is not MFP capable, no need to check */
|
|
goto exit;
|
|
}
|
|
|
|
if (subtype == WIFI_ACTION)
|
|
category = *(ptr + sizeof(struct rtw_ieee80211_hdr_3addr));
|
|
|
|
if (is_bmc) {
|
|
/* broadcast cases */
|
|
if (subtype == WIFI_ACTION) {
|
|
if (CATEGORY_IS_GROUP_PRIVACY(category)) {
|
|
/* drop broadcast group privacy action frame without encryption */
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
RTW_INFO(FUNC_ADPT_FMT" broadcast gp action(%u) w/o encrypt\n"
|
|
, FUNC_ADPT_ARG(adapter), category);
|
|
#endif
|
|
goto fail;
|
|
}
|
|
if (CATEGORY_IS_ROBUST(category)) {
|
|
/* broadcast robust action frame need BIP check */
|
|
goto bip_verify;
|
|
}
|
|
}
|
|
if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) {
|
|
/* broadcast deauth or disassoc frame need BIP check */
|
|
goto bip_verify;
|
|
}
|
|
goto exit;
|
|
|
|
} else {
|
|
/* unicast cases */
|
|
#ifdef CONFIG_IEEE80211W
|
|
if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) {
|
|
if (!MLME_IS_MESH(adapter)) {
|
|
unsigned short reason = le16_to_cpu(*(unsigned short *)(ptr + WLAN_HDR_A3_LEN));
|
|
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
RTW_INFO(FUNC_ADPT_FMT" unicast %s, reason=%d w/o encrypt\n"
|
|
, FUNC_ADPT_ARG(adapter), subtype == WIFI_DEAUTH ? "deauth" : "disassoc", reason);
|
|
#endif
|
|
if (reason == 6 || reason == 7) {
|
|
/* issue sa query request */
|
|
issue_action_SA_Query(adapter, psta->cmn.mac_addr, 0, 0, IEEE80211W_RIGHT_KEY);
|
|
}
|
|
}
|
|
goto fail;
|
|
}
|
|
#endif
|
|
|
|
if (subtype == WIFI_ACTION && CATEGORY_IS_ROBUST(category)) {
|
|
if (psta->bpairwise_key_installed == _TRUE) {
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
RTW_INFO(FUNC_ADPT_FMT" unicast robust action(%d) w/o encrypt\n"
|
|
, FUNC_ADPT_ARG(adapter), category);
|
|
#endif
|
|
goto fail;
|
|
}
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
bip_verify:
|
|
#ifdef CONFIG_IEEE80211W
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (MLME_IS_MESH(adapter)) {
|
|
if (psta->igtk_bmp) {
|
|
igtk = psta->igtk.skey;
|
|
igtk_id = psta->igtk_id;
|
|
ipn = &psta->igtk_pn.val;
|
|
} else {
|
|
/* mesh MFP without IGTK */
|
|
goto exit;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
igtk = sec->dot11wBIPKey[sec->dot11wBIPKeyid].skey;
|
|
igtk_id = sec->dot11wBIPKeyid;
|
|
ipn = &sec->dot11wBIPrxpn.val;
|
|
}
|
|
|
|
/* verify BIP MME IE */
|
|
ret = rtw_BIP_verify(adapter
|
|
, get_recvframe_data(precv_frame)
|
|
, get_recvframe_len(precv_frame)
|
|
, igtk, igtk_id, ipn);
|
|
if (ret == _FAIL) {
|
|
/* RTW_INFO("802.11w BIP verify fail\n"); */
|
|
goto fail;
|
|
|
|
} else if (ret == RTW_RX_HANDLED) {
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
RTW_INFO(FUNC_ADPT_FMT" none protected packet\n", FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
goto fail;
|
|
}
|
|
#endif /* CONFIG_IEEE80211W */
|
|
goto exit;
|
|
}
|
|
|
|
/* cases to decrypt mgmt frame */
|
|
pattrib->bdecrypted = 0;
|
|
pattrib->encrypt = _AES_;
|
|
pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
|
|
|
|
/* set iv and icv length */
|
|
SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt);
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
|
|
/* actual management data frame body */
|
|
data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len;
|
|
mgmt_DATA = rtw_zmalloc(data_len);
|
|
if (mgmt_DATA == NULL) {
|
|
RTW_INFO(FUNC_ADPT_FMT" mgmt allocate fail !!!!!!!!!\n", FUNC_ADPT_ARG(adapter));
|
|
goto fail;
|
|
}
|
|
|
|
#if DBG_VALIDATE_MGMT_DEC
|
|
/* dump the packet content before decrypt */
|
|
{
|
|
int pp;
|
|
|
|
printk("pattrib->pktlen = %d =>", pattrib->pkt_len);
|
|
for (pp = 0; pp < pattrib->pkt_len; pp++)
|
|
printk(" %02x ", ptr[pp]);
|
|
printk("\n");
|
|
}
|
|
#endif
|
|
|
|
precv_frame = decryptor(adapter, precv_frame);
|
|
/* save actual management data frame body */
|
|
_rtw_memcpy(mgmt_DATA, ptr + pattrib->hdrlen + pattrib->iv_len, data_len);
|
|
/* overwrite the iv field */
|
|
_rtw_memcpy(ptr + pattrib->hdrlen, mgmt_DATA, data_len);
|
|
/* remove the iv and icv length */
|
|
pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len;
|
|
rtw_mfree(mgmt_DATA, data_len);
|
|
|
|
#if DBG_VALIDATE_MGMT_DEC
|
|
/* print packet content after decryption */
|
|
{
|
|
int pp;
|
|
|
|
printk("after decryption pattrib->pktlen = %d @@=>", pattrib->pkt_len);
|
|
for (pp = 0; pp < pattrib->pkt_len; pp++)
|
|
printk(" %02x ", ptr[pp]);
|
|
printk("\n");
|
|
}
|
|
#endif
|
|
|
|
if (!precv_frame) {
|
|
#if DBG_VALIDATE_MGMT_PROTECT
|
|
RTW_INFO(FUNC_ADPT_FMT" mgmt descrypt fail !!!!!!!!!\n", FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
goto fail;
|
|
}
|
|
|
|
exit:
|
|
return _SUCCESS;
|
|
|
|
fail:
|
|
return _FAIL;
|
|
|
|
}
|
|
#endif /* defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH) */
|
|
|
|
union recv_frame *recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame);
|
|
|
|
sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame)
|
|
{
|
|
struct sta_info *psta = precv_frame->u.hdr.psta
|
|
= rtw_get_stainfo(&padapter->stapriv, get_addr2_ptr(precv_frame->u.hdr.rx_data));
|
|
|
|
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
|
|
if (validate_mgmt_protect(padapter, precv_frame) == _FAIL) {
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_pre_mgmt_err_80211w);
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
precv_frame = recvframe_chk_defrag(padapter, precv_frame);
|
|
if (precv_frame == NULL)
|
|
return _SUCCESS;
|
|
|
|
/* for rx pkt statistics */
|
|
if (psta) {
|
|
psta->sta_stats.last_rx_time = rtw_get_current_time();
|
|
psta->sta_stats.rx_mgnt_pkts++;
|
|
if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_BEACON)
|
|
psta->sta_stats.rx_beacon_pkts++;
|
|
else if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ)
|
|
psta->sta_stats.rx_probereq_pkts++;
|
|
else if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) {
|
|
if (_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == _TRUE)
|
|
psta->sta_stats.rx_probersp_pkts++;
|
|
else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))
|
|
|| is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)))
|
|
psta->sta_stats.rx_probersp_bm_pkts++;
|
|
else
|
|
psta->sta_stats.rx_probersp_uo_pkts++;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_INTEL_PROXIM
|
|
if (padapter->proximity.proxim_on == _TRUE) {
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct recv_stat *prxstat = (struct recv_stat *) precv_frame->u.hdr.rx_head ;
|
|
u8 *pda, *psa, *pbssid, *ptr;
|
|
ptr = precv_frame->u.hdr.rx_data;
|
|
pda = get_da(ptr);
|
|
psa = get_sa(ptr);
|
|
pbssid = get_hdr_bssid(ptr);
|
|
|
|
|
|
_rtw_memcpy(pattrib->dst, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, psa, ETH_ALEN);
|
|
|
|
_rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN);
|
|
|
|
switch (pattrib->to_fr_ds) {
|
|
case 0:
|
|
_rtw_memcpy(pattrib->ra, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, psa, ETH_ALEN);
|
|
break;
|
|
|
|
case 1:
|
|
_rtw_memcpy(pattrib->ra, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN);
|
|
break;
|
|
|
|
case 2:
|
|
_rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, psa, ETH_ALEN);
|
|
break;
|
|
|
|
case 3:
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
pattrib->priority = 0;
|
|
pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24;
|
|
|
|
padapter->proximity.proxim_rx(padapter, precv_frame);
|
|
}
|
|
#endif
|
|
mgt_dispatcher(padapter, precv_frame);
|
|
|
|
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_RTW_MESH)
|
|
exit:
|
|
#endif
|
|
return _SUCCESS;
|
|
|
|
}
|
|
|
|
sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
u8 bretry, a4_shift;
|
|
struct sta_info *psta = NULL;
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct security_priv *psecuritypriv = &adapter->securitypriv;
|
|
sint ret = _SUCCESS;
|
|
|
|
bretry = GetRetry(ptr);
|
|
a4_shift = (pattrib->to_fr_ds == 3) ? ETH_ALEN : 0;
|
|
|
|
/* some address fields are different when using AMSDU */
|
|
if (pattrib->qos)
|
|
pattrib->amsdu = GetAMsdu(ptr + WLAN_HDR_A3_LEN + a4_shift);
|
|
else
|
|
pattrib->amsdu = 0;
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (MLME_IS_MESH(adapter)) {
|
|
ret = rtw_mesh_rx_data_validate_hdr(adapter, precv_frame, &psta);
|
|
goto pre_validate_status_chk;
|
|
}
|
|
#endif
|
|
|
|
switch (pattrib->to_fr_ds) {
|
|
case 0:
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
ret = sta2sta_data_frame(adapter, precv_frame, &psta);
|
|
break;
|
|
|
|
case 1:
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, get_addr2_ptr(ptr), ETH_ALEN);
|
|
ret = ap2sta_data_frame(adapter, precv_frame, &psta);
|
|
break;
|
|
|
|
case 2:
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->dst, GetAddr3Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
ret = sta2ap_data_frame(adapter, precv_frame, &psta);
|
|
break;
|
|
|
|
case 3:
|
|
default:
|
|
/* WDS is not supported */
|
|
ret = _FAIL;
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
pre_validate_status_chk:
|
|
#endif
|
|
if (ret == _FAIL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" case:%d, res:%d, ra="MAC_FMT", ta="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), pattrib->to_fr_ds, ret, MAC_ARG(GetAddr1Ptr(ptr)), MAC_ARG(get_addr2_ptr(ptr)));
|
|
#endif
|
|
goto exit;
|
|
} else if (ret == RTW_RX_HANDLED)
|
|
goto exit;
|
|
|
|
|
|
if (psta == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" psta == NULL, ra="MAC_FMT", ta="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(GetAddr1Ptr(ptr)), MAC_ARG(get_addr2_ptr(ptr)));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
precv_frame->u.hdr.psta = psta;
|
|
precv_frame->u.hdr.preorder_ctrl = NULL;
|
|
pattrib->ack_policy = 0;
|
|
|
|
/* parsing QC field */
|
|
if (pattrib->qos == 1) {
|
|
pattrib->priority = GetPriority((ptr + WLAN_HDR_A3_LEN + a4_shift)); /* point to Qos field*/
|
|
pattrib->ack_policy = GetAckpolicy((ptr + WLAN_HDR_A3_LEN + a4_shift));
|
|
pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN + a4_shift;
|
|
if (pattrib->priority != 0 && pattrib->priority != 3)
|
|
adapter->recvpriv.is_any_non_be_pkts = _TRUE;
|
|
else
|
|
adapter->recvpriv.is_any_non_be_pkts = _FALSE;
|
|
} else {
|
|
pattrib->priority = 0;
|
|
pattrib->hdrlen = WLAN_HDR_A3_LEN + a4_shift;
|
|
}
|
|
|
|
if (pattrib->order) /* HT-CTRL 11n */
|
|
pattrib->hdrlen += 4;
|
|
|
|
/* decache, drop duplicate recv packets */
|
|
ret = recv_decache(precv_frame);
|
|
if (ret == _FAIL)
|
|
goto exit;
|
|
|
|
if (!IS_MCAST(pattrib->ra)) {
|
|
|
|
if (pattrib->qos)
|
|
precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
|
|
|
|
if (recv_ucast_pn_decache(precv_frame) == _FAIL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" recv_ucast_pn_decache return _FAIL for sta="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(psta->cmn.mac_addr));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
if (recv_bcast_pn_decache(precv_frame) == _FAIL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" recv_bcast_pn_decache return _FAIL for sta="MAC_FMT"\n"
|
|
, FUNC_ADPT_ARG(adapter), MAC_ARG(psta->cmn.mac_addr));
|
|
#endif
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (pattrib->privacy) {
|
|
#ifdef CONFIG_TDLS
|
|
if ((psta->tdls_sta_state & TDLS_LINKED_STATE) && (psta->dot118021XPrivacy == _AES_))
|
|
pattrib->encrypt = psta->dot118021XPrivacy;
|
|
else
|
|
#endif /* CONFIG_TDLS */
|
|
GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra));
|
|
|
|
|
|
SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt);
|
|
} else {
|
|
pattrib->encrypt = 0;
|
|
pattrib->iv_len = pattrib->icv_len = 0;
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (!pattrib->amsdu
|
|
&& pattrib->mesh_ctrl_present
|
|
&& (!pattrib->encrypt || pattrib->bdecrypted))
|
|
ret = rtw_mesh_rx_validate_mctrl_non_amsdu(adapter, precv_frame);
|
|
#endif
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
static inline void dump_rx_packet(u8 *ptr)
|
|
{
|
|
int i;
|
|
|
|
RTW_INFO("#############################\n");
|
|
for (i = 0; i < 64; i = i + 8)
|
|
RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i),
|
|
*(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7));
|
|
RTW_INFO("#############################\n");
|
|
}
|
|
|
|
sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame);
|
|
sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
/* shall check frame subtype, to / from ds, da, bssid */
|
|
|
|
/* then call check if rx seq/frag. duplicated. */
|
|
|
|
u8 type;
|
|
u8 subtype;
|
|
sint retval = _SUCCESS;
|
|
|
|
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
|
|
struct recv_priv *precvpriv = &adapter->recvpriv;
|
|
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
u8 ver = (unsigned char)(*ptr) & 0x3 ;
|
|
#ifdef CONFIG_FIND_BEST_CHANNEL
|
|
struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
|
|
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
|
|
#endif
|
|
|
|
#ifdef CONFIG_TDLS
|
|
struct tdls_info *ptdlsinfo = &adapter->tdlsinfo;
|
|
#endif /* CONFIG_TDLS */
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
PRT_WAPI_T pWapiInfo = &adapter->wapiInfo;
|
|
struct recv_frame_hdr *phdr = &precv_frame->u.hdr;
|
|
u8 wai_pkt = 0;
|
|
u16 sc;
|
|
u8 external_len = 0;
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_FIND_BEST_CHANNEL
|
|
if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
|
|
int ch_set_idx = rtw_chset_search_ch(rfctl->channel_set, rtw_get_oper_ch(adapter));
|
|
if (ch_set_idx >= 0)
|
|
rfctl->channel_set[ch_set_idx].rx_count++;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_TDLS
|
|
if (ptdlsinfo->ch_sensing == 1 && ptdlsinfo->cur_channel != 0)
|
|
ptdlsinfo->collect_pkt_num[ptdlsinfo->cur_channel - 1]++;
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
#ifdef RTK_DMP_PLATFORM
|
|
if (0) {
|
|
RTW_INFO("++\n");
|
|
{
|
|
int i;
|
|
for (i = 0; i < 64; i = i + 8)
|
|
RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr + i),
|
|
*(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7));
|
|
|
|
}
|
|
RTW_INFO("--\n");
|
|
}
|
|
#endif /* RTK_DMP_PLATFORM */
|
|
|
|
/* add version chk */
|
|
if (ver != 0) {
|
|
retval = _FAIL;
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_ver_err);
|
|
goto exit;
|
|
}
|
|
|
|
type = GetFrameType(ptr);
|
|
subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */
|
|
|
|
pattrib->to_fr_ds = get_tofr_ds(ptr);
|
|
|
|
pattrib->frag_num = GetFragNum(ptr);
|
|
pattrib->seq_num = GetSequence(ptr);
|
|
|
|
pattrib->pw_save = GetPwrMgt(ptr);
|
|
pattrib->mfrag = GetMFrag(ptr);
|
|
pattrib->mdata = GetMData(ptr);
|
|
pattrib->privacy = GetPrivacy(ptr);
|
|
pattrib->order = GetOrder(ptr);
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
sc = (pattrib->seq_num << 4) | pattrib->frag_num;
|
|
#endif
|
|
|
|
#if 1 /* Dump rx packets */
|
|
{
|
|
u8 bDumpRxPkt = 0;
|
|
|
|
rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
|
|
if (bDumpRxPkt == 1) /* dump all rx packets */
|
|
dump_rx_packet(ptr);
|
|
else if ((bDumpRxPkt == 2) && (type == WIFI_MGT_TYPE))
|
|
dump_rx_packet(ptr);
|
|
else if ((bDumpRxPkt == 3) && (type == WIFI_DATA_TYPE))
|
|
dump_rx_packet(ptr);
|
|
}
|
|
#endif
|
|
switch (type) {
|
|
case WIFI_MGT_TYPE: /* mgnt */
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt);
|
|
retval = validate_recv_mgnt_frame(adapter, precv_frame);
|
|
if (retval == _FAIL) {
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt_err);
|
|
}
|
|
retval = _FAIL; /* only data frame return _SUCCESS */
|
|
break;
|
|
case WIFI_CTRL_TYPE: /* ctrl */
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl);
|
|
retval = validate_recv_ctrl_frame(adapter, precv_frame);
|
|
if (retval == _FAIL) {
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl_err);
|
|
}
|
|
retval = _FAIL; /* only data frame return _SUCCESS */
|
|
break;
|
|
case WIFI_DATA_TYPE: /* data */
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_data);
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
if (pattrib->qos)
|
|
external_len = 2;
|
|
else
|
|
external_len = 0;
|
|
|
|
wai_pkt = rtw_wapi_is_wai_packet(adapter, ptr);
|
|
|
|
phdr->bIsWaiPacket = wai_pkt;
|
|
|
|
if (wai_pkt != 0) {
|
|
if (sc != adapter->wapiInfo.wapiSeqnumAndFragNum)
|
|
adapter->wapiInfo.wapiSeqnumAndFragNum = sc;
|
|
else {
|
|
retval = _FAIL;
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_wapi_seq_err);
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
if (rtw_wapi_drop_for_key_absent(adapter, get_addr2_ptr(ptr))) {
|
|
retval = _FAIL;
|
|
WAPI_TRACE(WAPI_RX, "drop for key absent for rx\n");
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_wapi_key_err);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
|
|
retval = validate_recv_data_frame(adapter, precv_frame);
|
|
if (retval == _FAIL) {
|
|
precvpriv->dbg_rx_drop_count++;
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_err);
|
|
} else if (retval == _SUCCESS) {
|
|
#ifdef DBG_RX_DUMP_EAP
|
|
if (!pattrib->encrypt || pattrib->bdecrypted) {
|
|
u8 bDumpRxPkt;
|
|
u16 eth_type;
|
|
|
|
/* dump eapol */
|
|
rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
|
|
/* get ether_type */
|
|
_rtw_memcpy(ð_type, ptr + pattrib->hdrlen + pattrib->iv_len + RATTRIB_GET_MCTRL_LEN(pattrib) + LLC_HEADER_SIZE, 2);
|
|
eth_type = ntohs((unsigned short) eth_type);
|
|
if ((bDumpRxPkt == 4) && (eth_type == 0x888e))
|
|
dump_rx_packet(ptr);
|
|
}
|
|
#endif
|
|
} else
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_handled);
|
|
break;
|
|
default:
|
|
DBG_COUNTER(adapter->rx_logs.core_rx_pre_unknown);
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" fail! type=0x%x\n"
|
|
, FUNC_ADPT_ARG(adapter), type);
|
|
#endif
|
|
retval = _FAIL;
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/* remove the wlanhdr and add the eth_hdr */
|
|
#if 1
|
|
sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
|
|
{
|
|
sint rmv_len;
|
|
u16 eth_type, len;
|
|
u8 bsnaphdr;
|
|
u8 *psnap_type;
|
|
struct ieee80211_snap_hdr *psnap;
|
|
|
|
sint ret = _SUCCESS;
|
|
_adapter *adapter = precvframe->u.hdr.adapter;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
|
|
u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */
|
|
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
|
|
|
|
|
|
if (pattrib->encrypt)
|
|
recvframe_pull_tail(precvframe, pattrib->icv_len);
|
|
|
|
psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len + RATTRIB_GET_MCTRL_LEN(pattrib));
|
|
psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + RATTRIB_GET_MCTRL_LEN(pattrib) + SNAP_SIZE;
|
|
/* convert hdr + possible LLC headers into Ethernet header */
|
|
/* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */
|
|
if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
|
|
(_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == _FALSE) &&
|
|
(_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == _FALSE)) ||
|
|
/* eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || */
|
|
_rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
|
|
/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
|
|
bsnaphdr = _TRUE;
|
|
} else {
|
|
/* Leave Ethernet header part of hdr and full payload */
|
|
bsnaphdr = _FALSE;
|
|
}
|
|
|
|
rmv_len = pattrib->hdrlen + pattrib->iv_len + RATTRIB_GET_MCTRL_LEN(pattrib) + (bsnaphdr ? SNAP_SIZE : 0);
|
|
len = precvframe->u.hdr.len - rmv_len;
|
|
|
|
|
|
_rtw_memcpy(ð_type, ptr + rmv_len, 2);
|
|
eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */
|
|
pattrib->eth_type = eth_type;
|
|
|
|
|
|
if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)) {
|
|
ptr += rmv_len ;
|
|
*ptr = 0x87;
|
|
*(ptr + 1) = 0x12;
|
|
|
|
eth_type = 0x8712;
|
|
/* append rx status for mp test packets */
|
|
ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24);
|
|
if (!ptr) {
|
|
ret = _FAIL;
|
|
goto exiting;
|
|
}
|
|
_rtw_memcpy(ptr, get_rxmem(precvframe), 24);
|
|
ptr += 24;
|
|
} else {
|
|
ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
|
|
if (!ptr) {
|
|
ret = _FAIL;
|
|
goto exiting;
|
|
}
|
|
}
|
|
|
|
if (ptr) {
|
|
_rtw_memcpy(ptr, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
|
|
|
|
if (!bsnaphdr) {
|
|
len = htons(len);
|
|
_rtw_memcpy(ptr + 12, &len, 2);
|
|
}
|
|
|
|
rtw_rframe_set_os_pkt(precvframe);
|
|
}
|
|
|
|
exiting:
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
|
static u8 SNAP_ETH_TYPE_APPLETALK_DDP[2] = {0x80, 0x9b};
|
|
/* Datagram Delivery Protocol */
|
|
static u8 SNAP_HDR_APPLETALK_DDP[3] = {0x08, 0x00, 0x07};
|
|
static u8 oui_8021h[] = {0x00, 0x00, 0xf8};
|
|
static u8 oui_rfc1042[] = {0x00, 0x00, 0x00};
|
|
|
|
sint wlanhdr_to_ethhdr(union recv_frame *precvframe)
|
|
{
|
|
sint rmv_len;
|
|
u16 eth_type;
|
|
u8 bsnaphdr;
|
|
u8 *psnap_type;
|
|
struct ieee80211_snap_hdr *psnap;
|
|
|
|
sint ret = _SUCCESS;
|
|
_adapter *adapter = precvframe->u.hdr.adapter;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
|
|
u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */
|
|
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
|
|
struct _vlan *pvlan = NULL;
|
|
|
|
|
|
psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len);
|
|
psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
|
|
if (psnap->dsap == 0xaa && psnap->ssap == 0xaa && psnap->ctrl == 0x03) {
|
|
if (_rtw_memcmp(psnap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN))
|
|
bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042; */
|
|
else if (_rtw_memcmp(psnap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) &&
|
|
_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_DDP, 2))
|
|
bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK; */
|
|
else if (_rtw_memcmp(psnap->oui, oui_8021h, WLAN_IEEE_OUI_LEN))
|
|
bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL; */
|
|
else {
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
} else
|
|
bsnaphdr = _FALSE; /* wlan_pkt_format = WLAN_PKT_FORMAT_OTHERS; */
|
|
|
|
rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
|
|
|
|
if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) {
|
|
ptr += rmv_len ;
|
|
*ptr = 0x87;
|
|
*(ptr + 1) = 0x12;
|
|
|
|
/* back to original pointer */
|
|
ptr -= rmv_len;
|
|
}
|
|
|
|
ptr += rmv_len ;
|
|
|
|
_rtw_memcpy(ð_type, ptr, 2);
|
|
eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */
|
|
ptr += 2;
|
|
|
|
if (pattrib->encrypt)
|
|
recvframe_pull_tail(precvframe, pattrib->icv_len);
|
|
|
|
if (eth_type == 0x8100) { /* vlan */
|
|
pvlan = (struct _vlan *) ptr;
|
|
|
|
/* eth_type = get_vlan_encap_proto(pvlan); */
|
|
/* eth_type = pvlan->h_vlan_encapsulated_proto; */ /* ? */
|
|
rmv_len += 4;
|
|
ptr += 4;
|
|
}
|
|
|
|
if (eth_type == 0x0800) { /* ip */
|
|
/* struct iphdr* piphdr = (struct iphdr*) ptr; */
|
|
/* __u8 tos = (unsigned char)(pattrib->priority & 0xff); */
|
|
|
|
/* piphdr->tos = tos; */
|
|
|
|
} else if (eth_type == 0x8712) { /* append rx status for mp test packets */
|
|
/* ptr -= 16; */
|
|
/* _rtw_memcpy(ptr, get_rxmem(precvframe), 16); */
|
|
} else {
|
|
#ifdef PLATFORM_OS_XP
|
|
NDIS_PACKET_8021Q_INFO VlanPriInfo;
|
|
UINT32 UserPriority = precvframe->u.hdr.attrib.priority;
|
|
UINT32 VlanID = (pvlan != NULL ? get_vlan_id(pvlan) : 0);
|
|
|
|
VlanPriInfo.Value = /* Get current value. */
|
|
NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo);
|
|
|
|
VlanPriInfo.TagHeader.UserPriority = UserPriority;
|
|
VlanPriInfo.TagHeader.VlanId = VlanID ;
|
|
|
|
VlanPriInfo.TagHeader.CanonicalFormatId = 0; /* Should be zero. */
|
|
VlanPriInfo.TagHeader.Reserved = 0; /* Should be zero. */
|
|
NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo) = VlanPriInfo.Value;
|
|
#endif
|
|
}
|
|
|
|
if (eth_type == 0x8712) { /* append rx status for mp test packets */
|
|
ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24);
|
|
_rtw_memcpy(ptr, get_rxmem(precvframe), 24);
|
|
ptr += 24;
|
|
} else
|
|
ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2));
|
|
|
|
_rtw_memcpy(ptr, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
|
|
|
|
eth_type = htons((unsigned short)eth_type) ;
|
|
_rtw_memcpy(ptr + 12, ð_type, 2);
|
|
|
|
exit:
|
|
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
|
|
#ifdef PLATFORM_LINUX
|
|
static void recvframe_expand_pkt(
|
|
PADAPTER padapter,
|
|
union recv_frame *prframe)
|
|
{
|
|
struct recv_frame_hdr *pfhdr;
|
|
_pkt *ppkt;
|
|
u8 shift_sz;
|
|
u32 alloc_sz;
|
|
u8 *ptr;
|
|
|
|
|
|
pfhdr = &prframe->u.hdr;
|
|
|
|
/* 6 is for IP header 8 bytes alignment in QoS packet case. */
|
|
if (pfhdr->attrib.qos)
|
|
shift_sz = 6;
|
|
else
|
|
shift_sz = 0;
|
|
|
|
/* for first fragment packet, need to allocate */
|
|
/* (1536 + RXDESC_SIZE + drvinfo_sz) to reassemble packet */
|
|
/* 8 is for skb->data 8 bytes alignment.
|
|
* alloc_sz = _RND(1536 + RXDESC_SIZE + pfhdr->attrib.drvinfosize + shift_sz + 8, 128); */
|
|
alloc_sz = 1664; /* round (1536 + 24 + 32 + shift_sz + 8) to 128 bytes alignment */
|
|
|
|
/* 3 1. alloc new skb */
|
|
/* prepare extra space for 4 bytes alignment */
|
|
ppkt = rtw_skb_alloc(alloc_sz);
|
|
|
|
if (!ppkt)
|
|
return; /* no way to expand */
|
|
|
|
/* 3 2. Prepare new skb to replace & release old skb */
|
|
/* force ppkt->data at 8-byte alignment address */
|
|
skb_reserve(ppkt, 8 - ((SIZE_PTR)ppkt->data & 7));
|
|
/* force ip_hdr at 8-byte alignment address according to shift_sz */
|
|
skb_reserve(ppkt, shift_sz);
|
|
|
|
/* copy data to new pkt */
|
|
ptr = skb_put(ppkt, pfhdr->len);
|
|
if (ptr)
|
|
_rtw_memcpy(ptr, pfhdr->rx_data, pfhdr->len);
|
|
|
|
rtw_skb_free(pfhdr->pkt);
|
|
|
|
/* attach new pkt to recvframe */
|
|
pfhdr->pkt = ppkt;
|
|
pfhdr->rx_head = ppkt->head;
|
|
pfhdr->rx_data = ppkt->data;
|
|
pfhdr->rx_tail = skb_tail_pointer(ppkt);
|
|
pfhdr->rx_end = skb_end_pointer(ppkt);
|
|
}
|
|
#else
|
|
#warning "recvframe_expand_pkt not implement, defrag may crash system"
|
|
#endif
|
|
#endif
|
|
|
|
/* perform defrag */
|
|
union recv_frame *recvframe_defrag(_adapter *adapter, _queue *defrag_q);
|
|
union recv_frame *recvframe_defrag(_adapter *adapter, _queue *defrag_q)
|
|
{
|
|
_list *plist, *phead;
|
|
u8 *data, wlanhdr_offset;
|
|
u8 curfragnum;
|
|
struct recv_frame_hdr *pfhdr, *pnfhdr;
|
|
union recv_frame *prframe, *pnextrframe;
|
|
_queue *pfree_recv_queue;
|
|
|
|
|
|
curfragnum = 0;
|
|
pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
|
|
|
|
phead = get_list_head(defrag_q);
|
|
plist = get_next(phead);
|
|
prframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
pfhdr = &prframe->u.hdr;
|
|
rtw_list_delete(&(prframe->u.list));
|
|
|
|
if (curfragnum != pfhdr->attrib.frag_num) {
|
|
/* the first fragment number must be 0 */
|
|
/* free the whole queue */
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI)
|
|
#ifndef CONFIG_SDIO_RX_COPY
|
|
recvframe_expand_pkt(adapter, prframe);
|
|
#endif
|
|
#endif
|
|
|
|
curfragnum++;
|
|
|
|
plist = get_list_head(defrag_q);
|
|
|
|
plist = get_next(plist);
|
|
|
|
data = get_recvframe_data(prframe);
|
|
|
|
while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
|
|
pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u);
|
|
pnfhdr = &pnextrframe->u.hdr;
|
|
|
|
|
|
/* check the fragment sequence (2nd ~n fragment frame) */
|
|
|
|
if (curfragnum != pnfhdr->attrib.frag_num) {
|
|
/* the fragment number must be increasing (after decache) */
|
|
/* release the defrag_q & prframe */
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
|
|
return NULL;
|
|
}
|
|
|
|
curfragnum++;
|
|
|
|
/* copy the 2nd~n fragment frame's payload to the first fragment */
|
|
/* get the 2nd~last fragment frame's payload */
|
|
|
|
wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
|
|
|
|
recvframe_pull(pnextrframe, wlanhdr_offset);
|
|
|
|
/* append to first fragment frame's tail (if privacy frame, pull the ICV) */
|
|
recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
|
|
|
|
/* memcpy */
|
|
_rtw_memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
|
|
|
|
recvframe_put(prframe, pnfhdr->len);
|
|
|
|
pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
|
|
plist = get_next(plist);
|
|
|
|
};
|
|
|
|
/* free the defrag_q queue and return the prframe */
|
|
rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
|
|
|
|
|
|
|
|
return prframe;
|
|
}
|
|
|
|
/* check if need to defrag, if needed queue the frame to defrag_q */
|
|
union recv_frame *recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame)
|
|
{
|
|
u8 ismfrag;
|
|
u8 fragnum;
|
|
u8 *psta_addr;
|
|
struct recv_frame_hdr *pfhdr;
|
|
struct sta_info *psta;
|
|
struct sta_priv *pstapriv;
|
|
_list *phead;
|
|
union recv_frame *prtnframe = NULL;
|
|
_queue *pfree_recv_queue, *pdefrag_q = NULL;
|
|
|
|
|
|
pstapriv = &padapter->stapriv;
|
|
|
|
pfhdr = &precv_frame->u.hdr;
|
|
|
|
pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
|
|
/* need to define struct of wlan header frame ctrl */
|
|
ismfrag = pfhdr->attrib.mfrag;
|
|
fragnum = pfhdr->attrib.frag_num;
|
|
|
|
psta_addr = pfhdr->attrib.ta;
|
|
psta = rtw_get_stainfo(pstapriv, psta_addr);
|
|
if (psta == NULL) {
|
|
u8 type = GetFrameType(pfhdr->rx_data);
|
|
if (type != WIFI_DATA_TYPE) {
|
|
psta = rtw_get_bcmc_stainfo(padapter);
|
|
if (psta)
|
|
pdefrag_q = &psta->sta_recvpriv.defrag_q;
|
|
} else
|
|
pdefrag_q = NULL;
|
|
} else
|
|
pdefrag_q = &psta->sta_recvpriv.defrag_q;
|
|
|
|
if ((ismfrag == 0) && (fragnum == 0)) {
|
|
prtnframe = precv_frame;/* isn't a fragment frame */
|
|
}
|
|
|
|
if (ismfrag == 1) {
|
|
/* 0~(n-1) fragment frame */
|
|
/* enqueue to defraf_g */
|
|
if (pdefrag_q != NULL) {
|
|
if (fragnum == 0) {
|
|
/* the first fragment */
|
|
if (_rtw_queue_empty(pdefrag_q) == _FALSE) {
|
|
/* free current defrag_q */
|
|
rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue);
|
|
}
|
|
}
|
|
|
|
|
|
/* Then enqueue the 0~(n-1) fragment into the defrag_q */
|
|
|
|
/* _rtw_spinlock(&pdefrag_q->lock); */
|
|
phead = get_list_head(pdefrag_q);
|
|
rtw_list_insert_tail(&pfhdr->list, phead);
|
|
/* _rtw_spinunlock(&pdefrag_q->lock); */
|
|
|
|
|
|
prtnframe = NULL;
|
|
|
|
} else {
|
|
/* can't find this ta's defrag_queue, so free this recv_frame */
|
|
rtw_free_recvframe(precv_frame, pfree_recv_queue);
|
|
prtnframe = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ((ismfrag == 0) && (fragnum != 0)) {
|
|
/* the last fragment frame */
|
|
/* enqueue the last fragment */
|
|
if (pdefrag_q != NULL) {
|
|
/* _rtw_spinlock(&pdefrag_q->lock); */
|
|
phead = get_list_head(pdefrag_q);
|
|
rtw_list_insert_tail(&pfhdr->list, phead);
|
|
/* _rtw_spinunlock(&pdefrag_q->lock); */
|
|
|
|
/* call recvframe_defrag to defrag */
|
|
precv_frame = recvframe_defrag(padapter, pdefrag_q);
|
|
prtnframe = precv_frame;
|
|
|
|
} else {
|
|
/* can't find this ta's defrag_queue, so free this recv_frame */
|
|
rtw_free_recvframe(precv_frame, pfree_recv_queue);
|
|
prtnframe = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
|
|
/* after defrag we must check tkip mic code */
|
|
if (recvframe_chkmic(padapter, prtnframe) == _FAIL) {
|
|
rtw_free_recvframe(prtnframe, pfree_recv_queue);
|
|
prtnframe = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
return prtnframe;
|
|
|
|
}
|
|
|
|
static int rtw_recv_indicatepkt_check(union recv_frame *rframe, u8 *ehdr_pos, u32 pkt_len)
|
|
{
|
|
_adapter *adapter = rframe->u.hdr.adapter;
|
|
struct recv_priv *recvpriv = &adapter->recvpriv;
|
|
struct ethhdr *ehdr = (struct ethhdr *)ehdr_pos;
|
|
#ifdef DBG_IP_R_MONITOR
|
|
int i;
|
|
struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
|
|
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
|
|
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
|
|
struct wlan_network *cur_network = &(pmlmepriv->cur_network);
|
|
#endif/*DBG_IP_R_MONITOR*/
|
|
int ret = _FAIL;
|
|
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
if (rtw_wapi_check_for_drop(adapter, rframe, ehdr_pos)) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" rtw_wapi_check_for_drop\n"
|
|
, FUNC_ADPT_ARG(adapter));
|
|
#endif
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
if (rframe->u.hdr.psta)
|
|
rtw_st_ctl_rx(rframe->u.hdr.psta, ehdr_pos);
|
|
|
|
if (ntohs(ehdr->h_proto) == 0x888e)
|
|
parsing_eapol_packet(adapter, ehdr_pos + ETH_HLEN, rframe->u.hdr.psta, 0);
|
|
#ifdef DBG_ARP_DUMP
|
|
else if (ntohs(ehdr->h_proto) == ETH_P_ARP)
|
|
dump_arp_pkt(RTW_DBGDUMP, ehdr->h_dest, ehdr->h_source, ehdr_pos + ETH_HLEN, 0);
|
|
#endif
|
|
|
|
if (recvpriv->sink_udpport > 0)
|
|
rtw_sink_rtp_seq_dbg(adapter, ehdr_pos);
|
|
|
|
#ifdef DBG_UDP_PKT_LOSE_11AC
|
|
#define PAYLOAD_LEN_LOC_OF_IP_HDR 0x10 /*ethernet payload length location of ip header (DA + SA+eth_type+(version&hdr_len)) */
|
|
|
|
if (ntohs(ehdr->h_proto) == ETH_P_ARP) {
|
|
/* ARP Payload length will be 42bytes or 42+18(tailer)=60bytes*/
|
|
if (pkt_len != 42 && pkt_len != 60)
|
|
RTW_INFO("Error !!%s,ARP Payload length %u not correct\n" , __func__ , pkt_len);
|
|
} else if (ntohs(ehdr->h_proto) == ETH_P_IP) {
|
|
if (be16_to_cpu(*((u16 *)(ehdr_pos + PAYLOAD_LEN_LOC_OF_IP_HDR))) != (pkt_len) - ETH_HLEN) {
|
|
RTW_INFO("Error !!%s,Payload length not correct\n" , __func__);
|
|
RTW_INFO("%s, IP header describe Total length=%u\n" , __func__ , be16_to_cpu(*((u16 *)(ehdr_pos + PAYLOAD_LEN_LOC_OF_IP_HDR))));
|
|
RTW_INFO("%s, Pkt real length=%u\n" , __func__ , (pkt_len) - ETH_HLEN);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBG_IP_R_MONITOR
|
|
#define LEN_ARP_OP_HDR 7 /*ARP OERATION */
|
|
if (ntohs(ehdr->h_proto) == ETH_P_ARP) {
|
|
|
|
if(check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE){
|
|
if(ehdr_pos[ETHERNET_HEADER_SIZE+LEN_ARP_OP_HDR] == 2) {
|
|
RTW_INFO("%s,[DBG_ARP] Rx ARP RSP Packet with Dst= "MAC_FMT" ;SeqNum = %d !\n",
|
|
__FUNCTION__, MAC_ARG(pattrib->dst), pattrib->seq_num);
|
|
for(i=0;i<(pkt_len -ETHERNET_HEADER_SIZE);i++)
|
|
RTW_INFO("0x%x ",ehdr_pos[i+ETHERNET_HEADER_SIZE]);
|
|
RTW_INFO("\n");
|
|
}
|
|
}
|
|
}
|
|
#endif/*DBG_IP_R_MONITOR*/
|
|
|
|
#ifdef CONFIG_AUTO_AP_MODE
|
|
if (ntohs(ehdr->h_proto) == 0x8899)
|
|
rtw_auto_ap_rx_msg_dump(adapter, rframe, ehdr_pos);
|
|
#endif
|
|
|
|
ret = _SUCCESS;
|
|
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
exit:
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static void recv_free_fwd_resource(_adapter *adapter, struct xmit_frame *fwd_frame, _list *b2u_list)
|
|
{
|
|
struct xmit_priv *xmitpriv = &adapter->xmitpriv;
|
|
|
|
if (fwd_frame)
|
|
rtw_free_xmitframe(xmitpriv, fwd_frame);
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
|
|
if (!rtw_is_list_empty(b2u_list)) {
|
|
struct xmit_frame *b2uframe;
|
|
_list *list;
|
|
|
|
list = get_next(b2u_list);
|
|
while (rtw_end_of_queue_search(b2u_list, list) == _FALSE) {
|
|
b2uframe = LIST_CONTAINOR(list, struct xmit_frame, list);
|
|
list = get_next(list);
|
|
rtw_list_delete(&b2uframe->list);
|
|
rtw_free_xmitframe(xmitpriv, b2uframe);
|
|
}
|
|
}
|
|
#endif
|
|
#endif /* CONFIG_RTW_MESH */
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
static void recv_fwd_pkt_hdl(_adapter *adapter, _pkt *pkt
|
|
, u8 act, struct xmit_frame *fwd_frame, _list *b2u_list)
|
|
{
|
|
struct xmit_priv *xmitpriv = &adapter->xmitpriv;
|
|
_pkt *fwd_pkt = pkt;
|
|
|
|
if (act & RTW_RX_MSDU_ACT_INDICATE) {
|
|
fwd_pkt = rtw_os_pkt_copy(pkt);
|
|
if (!fwd_pkt) {
|
|
#ifdef DBG_TX_DROP_FRAME
|
|
RTW_INFO("DBG_TX_DROP_FRAME %s rtw_os_pkt_copy fail\n", __func__);
|
|
#endif
|
|
recv_free_fwd_resource(adapter, fwd_frame, b2u_list);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
#if CONFIG_RTW_MESH_DATA_BMC_TO_UC
|
|
if (!rtw_is_list_empty(b2u_list)) {
|
|
_list *list = get_next(b2u_list);
|
|
struct xmit_frame *b2uframe;
|
|
|
|
while (rtw_end_of_queue_search(b2u_list, list) == _FALSE) {
|
|
b2uframe = LIST_CONTAINOR(list, struct xmit_frame, list);
|
|
list = get_next(list);
|
|
rtw_list_delete(&b2uframe->list);
|
|
|
|
if (!fwd_frame && rtw_is_list_empty(b2u_list)) /* the last fwd_pkt */
|
|
b2uframe->pkt = fwd_pkt;
|
|
else
|
|
b2uframe->pkt = rtw_os_pkt_copy(fwd_pkt);
|
|
if (!b2uframe->pkt) {
|
|
rtw_free_xmitframe(xmitpriv, b2uframe);
|
|
continue;
|
|
}
|
|
|
|
rtw_xmit_posthandle(adapter, b2uframe, b2uframe->pkt);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (fwd_frame) {
|
|
fwd_frame->pkt = fwd_pkt;
|
|
if (rtw_xmit_posthandle(adapter, fwd_frame, fwd_pkt) < 0) {
|
|
#ifdef DBG_TX_DROP_FRAME
|
|
RTW_INFO("DBG_TX_DROP_FRAME %s rtw_xmit_posthandle fail\n", __func__);
|
|
#endif
|
|
xmitpriv->tx_drop++;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
#endif /* CONFIG_RTW_MESH */
|
|
|
|
int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
struct rx_pkt_attrib *rattrib = &prframe->u.hdr.attrib;
|
|
int a_len, padding_len;
|
|
u16 nSubframe_Length;
|
|
u8 nr_subframes, i;
|
|
u8 *pdata;
|
|
_pkt *sub_pkt, *subframes[MAX_SUBFRAME_COUNT];
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
_queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
|
|
const u8 *da, *sa;
|
|
int act;
|
|
struct xmit_frame *fwd_frame;
|
|
_list b2u_list;
|
|
u8 mctrl_len = 0;
|
|
int ret = _SUCCESS;
|
|
|
|
nr_subframes = 0;
|
|
|
|
recvframe_pull(prframe, rattrib->hdrlen);
|
|
|
|
if (rattrib->iv_len > 0)
|
|
recvframe_pull(prframe, rattrib->iv_len);
|
|
|
|
a_len = prframe->u.hdr.len;
|
|
pdata = prframe->u.hdr.rx_data;
|
|
|
|
while (a_len > ETH_HLEN) {
|
|
/* Offset 12 denote 2 mac address */
|
|
nSubframe_Length = RTW_GET_BE16(pdata + 12);
|
|
if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
|
|
RTW_INFO("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length);
|
|
break;
|
|
}
|
|
|
|
act = RTW_RX_MSDU_ACT_INDICATE;
|
|
fwd_frame = NULL;
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (MLME_IS_MESH(padapter)) {
|
|
u8 *mda = pdata, *msa = pdata + ETH_ALEN;
|
|
struct rtw_ieee80211s_hdr *mctrl = (struct rtw_ieee80211s_hdr *)(pdata + ETH_HLEN);
|
|
int v_ret;
|
|
|
|
v_ret = rtw_mesh_rx_data_validate_mctrl(padapter, prframe
|
|
, mctrl, mda, msa, &mctrl_len, &da, &sa);
|
|
if (v_ret != _SUCCESS)
|
|
goto move_to_next;
|
|
|
|
act = rtw_mesh_rx_msdu_act_check(prframe
|
|
, mda, msa, da, sa, mctrl, &fwd_frame, &b2u_list);
|
|
} else
|
|
#endif
|
|
{
|
|
da = pdata;
|
|
sa = pdata + ETH_ALEN;
|
|
}
|
|
|
|
if (!act)
|
|
goto move_to_next;
|
|
|
|
rtw_led_rx_control(padapter, da);
|
|
|
|
sub_pkt = rtw_os_alloc_msdu_pkt(prframe, da, sa
|
|
, pdata + ETH_HLEN + mctrl_len, nSubframe_Length - mctrl_len);
|
|
if (sub_pkt == NULL) {
|
|
if (act & RTW_RX_MSDU_ACT_INDICATE) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME %s rtw_os_alloc_msdu_pkt fail\n", __func__);
|
|
#endif
|
|
}
|
|
if (act & RTW_RX_MSDU_ACT_FORWARD) {
|
|
#ifdef DBG_TX_DROP_FRAME
|
|
RTW_INFO("DBG_TX_DROP_FRAME %s rtw_os_alloc_msdu_pkt fail\n", __func__);
|
|
#endif
|
|
recv_free_fwd_resource(padapter, fwd_frame, &b2u_list);
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (act & RTW_RX_MSDU_ACT_FORWARD) {
|
|
recv_fwd_pkt_hdl(padapter, sub_pkt, act, fwd_frame, &b2u_list);
|
|
if (!(act & RTW_RX_MSDU_ACT_INDICATE))
|
|
goto move_to_next;
|
|
}
|
|
#endif
|
|
|
|
if (rtw_recv_indicatepkt_check(prframe, rtw_os_pkt_data(sub_pkt), rtw_os_pkt_len(sub_pkt)) == _SUCCESS)
|
|
subframes[nr_subframes++] = sub_pkt;
|
|
else
|
|
rtw_os_pkt_free(sub_pkt);
|
|
|
|
move_to_next:
|
|
/* move the data point to data content */
|
|
pdata += ETH_HLEN;
|
|
a_len -= ETH_HLEN;
|
|
|
|
if (nr_subframes >= MAX_SUBFRAME_COUNT) {
|
|
RTW_WARN("ParseSubframe(): Too many Subframes! Packets dropped!\n");
|
|
break;
|
|
}
|
|
|
|
pdata += nSubframe_Length;
|
|
a_len -= nSubframe_Length;
|
|
if (a_len != 0) {
|
|
padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4 - 1));
|
|
if (padding_len == 4)
|
|
padding_len = 0;
|
|
|
|
if (a_len < padding_len) {
|
|
RTW_INFO("ParseSubframe(): a_len < padding_len !\n");
|
|
break;
|
|
}
|
|
pdata += padding_len;
|
|
a_len -= padding_len;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < nr_subframes; i++) {
|
|
sub_pkt = subframes[i];
|
|
|
|
/* Indicat the packets to upper layer */
|
|
if (sub_pkt)
|
|
rtw_os_recv_indicate_pkt(padapter, sub_pkt, prframe);
|
|
}
|
|
|
|
prframe->u.hdr.len = 0;
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int recv_process_mpdu(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
int ret;
|
|
|
|
if (pattrib->amsdu) {
|
|
ret = amsdu_to_msdu(padapter, prframe);
|
|
if (ret != _SUCCESS) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" amsdu_to_msdu fail\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
goto exit;
|
|
}
|
|
} else {
|
|
int act = RTW_RX_MSDU_ACT_INDICATE;
|
|
struct xmit_frame *fwd_frame = NULL;
|
|
_list b2u_list;
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (MLME_IS_MESH(padapter) && pattrib->mesh_ctrl_present) {
|
|
act = rtw_mesh_rx_msdu_act_check(prframe
|
|
, pattrib->mda, pattrib->msa
|
|
, pattrib->dst, pattrib->src
|
|
, (struct rtw_ieee80211s_hdr *)(get_recvframe_data(prframe) + pattrib->hdrlen + pattrib->iv_len)
|
|
, &fwd_frame, &b2u_list);
|
|
}
|
|
#endif
|
|
|
|
if (!act) {
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
rtw_led_rx_control(padapter, pattrib->dst);
|
|
|
|
ret = wlanhdr_to_ethhdr(prframe);
|
|
if (ret != _SUCCESS) {
|
|
if (act & RTW_RX_MSDU_ACT_INDICATE) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" wlanhdr_to_ethhdr: drop pkt\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
}
|
|
if (act & RTW_RX_MSDU_ACT_FORWARD) {
|
|
#ifdef DBG_TX_DROP_FRAME
|
|
RTW_INFO("DBG_TX_DROP_FRAME %s wlanhdr_to_ethhdr fail\n", __func__);
|
|
#endif
|
|
recv_free_fwd_resource(padapter, fwd_frame, &b2u_list);
|
|
}
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef CONFIG_RTW_MESH
|
|
if (act & RTW_RX_MSDU_ACT_FORWARD) {
|
|
recv_fwd_pkt_hdl(padapter, prframe->u.hdr.pkt, act, fwd_frame, &b2u_list);
|
|
if (!(act & RTW_RX_MSDU_ACT_INDICATE)) {
|
|
prframe->u.hdr.pkt = NULL;
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!RTW_CANNOT_RUN(padapter)) {
|
|
ret = rtw_recv_indicatepkt_check(prframe
|
|
, get_recvframe_data(prframe), get_recvframe_len(prframe));
|
|
if (ret != _SUCCESS) {
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
goto exit;
|
|
}
|
|
|
|
/* indicate this recv_frame */
|
|
ret = rtw_recv_indicatepkt(padapter, prframe);
|
|
if (ret != _SUCCESS) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" rtw_recv_indicatepkt fail!\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
goto exit;
|
|
}
|
|
} else {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DS:%u SR:%u\n"
|
|
, FUNC_ADPT_ARG(padapter)
|
|
, rtw_is_drv_stopped(padapter)
|
|
, rtw_is_surprise_removed(padapter));
|
|
#endif
|
|
ret = _SUCCESS; /* don't count as packet drop */
|
|
rtw_free_recvframe(prframe, pfree_recv_queue);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
#if defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL)
|
|
static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num)
|
|
{
|
|
PADAPTER padapter = preorder_ctrl->padapter;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
u8 wsize = preorder_ctrl->wsize_b;
|
|
u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF; /* % 4096; */
|
|
|
|
/* Rx Reorder initialize condition. */
|
|
if (preorder_ctrl->indicate_seq == 0xFFFF) {
|
|
preorder_ctrl->indicate_seq = seq_num;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_INIT indicate_seq:%d, seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
}
|
|
|
|
/* Drop out the packet which SeqNum is smaller than WinStart */
|
|
if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO(FUNC_ADPT_FMT" tid:%u indicate_seq:%d > seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
return _FALSE;
|
|
}
|
|
|
|
/*
|
|
* Sliding window manipulation. Conditions includes:
|
|
* 1. Incoming SeqNum is equal to WinStart =>Window shift 1
|
|
* 2. Incoming SeqNum is larger than the WinEnd => Window shift N
|
|
*/
|
|
if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) {
|
|
preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_EQUAL indicate_seq:%d, seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
|
|
} else if (SN_LESS(wend, seq_num)) {
|
|
/* boundary situation, when seq_num cross 0xFFF */
|
|
if (seq_num >= (wsize - 1))
|
|
preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
|
|
else
|
|
preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1;
|
|
|
|
precvpriv->dbg_rx_ampdu_window_shift_cnt++;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_LESS(wend, seq_num) indicate_seq:%d, seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
}
|
|
|
|
return _TRUE;
|
|
}
|
|
|
|
static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe)
|
|
{
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
_queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
|
|
_list *phead, *plist;
|
|
union recv_frame *pnextrframe;
|
|
struct rx_pkt_attrib *pnextattrib;
|
|
|
|
/* DbgPrint("+enqueue_reorder_recvframe()\n"); */
|
|
|
|
/* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */
|
|
|
|
|
|
phead = get_list_head(ppending_recvframe_queue);
|
|
plist = get_next(phead);
|
|
|
|
while (rtw_end_of_queue_search(phead, plist) == _FALSE) {
|
|
pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
pnextattrib = &pnextrframe->u.hdr.attrib;
|
|
|
|
if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
|
|
plist = get_next(plist);
|
|
else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) {
|
|
/* Duplicate entry is found!! Do not insert current entry. */
|
|
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
|
|
return _FALSE;
|
|
} else
|
|
break;
|
|
|
|
/* DbgPrint("enqueue_reorder_recvframe():while\n"); */
|
|
|
|
}
|
|
|
|
|
|
/* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */
|
|
|
|
rtw_list_delete(&(prframe->u.hdr.list));
|
|
|
|
rtw_list_insert_tail(&(prframe->u.hdr.list), plist);
|
|
|
|
/* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
|
|
|
|
return _TRUE;
|
|
|
|
}
|
|
|
|
static void recv_indicatepkts_pkt_loss_cnt(_adapter *padapter, u64 prev_seq, u64 current_seq)
|
|
{
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
|
|
if (current_seq < prev_seq) {
|
|
precvpriv->dbg_rx_ampdu_loss_count += (4096 + current_seq - prev_seq);
|
|
precvpriv->rx_drop += (4096 + current_seq - prev_seq);
|
|
} else {
|
|
precvpriv->dbg_rx_ampdu_loss_count += (current_seq - prev_seq);
|
|
precvpriv->rx_drop += (current_seq - prev_seq);
|
|
}
|
|
}
|
|
|
|
static int recv_indicatepkts_in_order(_adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced)
|
|
{
|
|
/* _irqL irql; */
|
|
_list *phead, *plist;
|
|
union recv_frame *prframe;
|
|
struct rx_pkt_attrib *pattrib;
|
|
/* u8 index = 0; */
|
|
int bPktInBuf = _FALSE;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
_queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
|
|
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_in_oder);
|
|
|
|
/* DbgPrint("+recv_indicatepkts_in_order\n"); */
|
|
|
|
/* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */
|
|
|
|
phead = get_list_head(ppending_recvframe_queue);
|
|
plist = get_next(phead);
|
|
|
|
#if 0
|
|
/* Check if there is any other indication thread running. */
|
|
if (pTS->RxIndicateState == RXTS_INDICATE_PROCESSING)
|
|
return;
|
|
#endif
|
|
|
|
/* Handling some condition for forced indicate case. */
|
|
if (bforced == _TRUE) {
|
|
precvpriv->dbg_rx_ampdu_forced_indicate_count++;
|
|
if (rtw_is_list_empty(phead)) {
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */
|
|
return _TRUE;
|
|
}
|
|
|
|
prframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
pattrib = &prframe->u.hdr.attrib;
|
|
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u FORCE indicate_seq:%d, seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, pattrib->seq_num);
|
|
#endif
|
|
recv_indicatepkts_pkt_loss_cnt(padapter, preorder_ctrl->indicate_seq, pattrib->seq_num);
|
|
preorder_ctrl->indicate_seq = pattrib->seq_num;
|
|
}
|
|
|
|
/* Prepare indication list and indication. */
|
|
/* Check if there is any packet need indicate. */
|
|
while (!rtw_is_list_empty(phead)) {
|
|
|
|
prframe = LIST_CONTAINOR(plist, union recv_frame, u);
|
|
pattrib = &prframe->u.hdr.attrib;
|
|
|
|
if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
|
|
|
|
#if 0
|
|
/* This protect buffer from overflow. */
|
|
if (index >= REORDER_WIN_SIZE) {
|
|
RT_ASSERT(FALSE, ("IndicateRxReorderList(): Buffer overflow!!\n"));
|
|
bPktInBuf = TRUE;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
plist = get_next(plist);
|
|
rtw_list_delete(&(prframe->u.hdr.list));
|
|
|
|
if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
|
|
preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ "FUNC_ADPT_FMT" tid:%u SN_EQUAL indicate_seq:%d, seq_num:%d\n"
|
|
, FUNC_ADPT_ARG(padapter), preorder_ctrl->tid, preorder_ctrl->indicate_seq, pattrib->seq_num);
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
index++;
|
|
if (index == 1) {
|
|
/* Cancel previous pending timer. */
|
|
/* PlatformCancelTimer(Adapter, &pTS->RxPktPendingTimer); */
|
|
if (bforced != _TRUE) {
|
|
/* RTW_INFO("_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);\n"); */
|
|
_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Set this as a lock to make sure that only one thread is indicating packet. */
|
|
/* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */
|
|
|
|
/* Indicate packets */
|
|
/* RT_ASSERT((index<=REORDER_WIN_SIZE), ("RxReorderIndicatePacket(): Rx Reorder buffer full!!\n")); */
|
|
|
|
|
|
/* indicate this recv_frame */
|
|
/* DbgPrint("recv_indicatepkts_in_order, indicate_seq=%d, seq_num=%d\n", precvpriv->indicate_seq, pattrib->seq_num); */
|
|
if (recv_process_mpdu(padapter, prframe) != _SUCCESS)
|
|
precvpriv->dbg_rx_drop_count++;
|
|
|
|
/* Update local variables. */
|
|
bPktInBuf = _FALSE;
|
|
|
|
} else {
|
|
bPktInBuf = _TRUE;
|
|
break;
|
|
}
|
|
|
|
/* DbgPrint("recv_indicatepkts_in_order():while\n"); */
|
|
|
|
}
|
|
|
|
/* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
|
|
#if 0
|
|
/* Release the indication lock and set to new indication step. */
|
|
if (bPktInBuf) {
|
|
/* Set new pending timer. */
|
|
/* pTS->RxIndicateState = RXTS_INDICATE_REORDER; */
|
|
/* PlatformSetTimer(Adapter, &pTS->RxPktPendingTimer, pHTInfo->RxReorderPendingTime); */
|
|
|
|
_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
|
|
} else {
|
|
/* pTS->RxIndicateState = RXTS_INDICATE_IDLE; */
|
|
}
|
|
#endif
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
|
|
/* return _TRUE; */
|
|
return bPktInBuf;
|
|
|
|
}
|
|
|
|
static int recv_indicatepkt_reorder(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
_irqL irql;
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
|
|
_queue *ppending_recvframe_queue = preorder_ctrl ? &preorder_ctrl->pending_recvframe_queue : NULL;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
|
|
if (!pattrib->qos || !preorder_ctrl || preorder_ctrl->enable == _FALSE)
|
|
goto _success_exit;
|
|
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_reoder);
|
|
|
|
_enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
|
|
/* s2. check if winstart_b(indicate_seq) needs to been updated */
|
|
if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) {
|
|
precvpriv->dbg_rx_ampdu_drop_count++;
|
|
/* pHTInfo->RxReorderDropCounter++; */
|
|
/* ReturnRFDList(Adapter, pRfd); */
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* return _FAIL; */
|
|
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" check_indicate_seq fail\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
#if 0
|
|
rtw_recv_indicatepkt(padapter, prframe);
|
|
|
|
_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
|
|
goto _success_exit;
|
|
#else
|
|
goto _err_exit;
|
|
#endif
|
|
}
|
|
|
|
|
|
/* s3. Insert all packet into Reorder Queue to maintain its ordering. */
|
|
if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) {
|
|
/* DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); */
|
|
/* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */
|
|
/* return _FAIL; */
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" enqueue_reorder_recvframe fail\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
goto _err_exit;
|
|
}
|
|
|
|
|
|
/* s4. */
|
|
/* Indication process. */
|
|
/* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */
|
|
/* with the SeqNum smaller than latest WinStart and buffer other packets. */
|
|
/* */
|
|
/* For Rx Reorder condition: */
|
|
/* 1. All packets with SeqNum smaller than WinStart => Indicate */
|
|
/* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */
|
|
/* */
|
|
|
|
/* recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE); */
|
|
if (recv_indicatepkts_in_order(padapter, preorder_ctrl, _FALSE) == _TRUE) {
|
|
if (!preorder_ctrl->bReorderWaiting) {
|
|
preorder_ctrl->bReorderWaiting = _TRUE;
|
|
_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
|
|
}
|
|
_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
} else {
|
|
preorder_ctrl->bReorderWaiting = _FALSE;
|
|
_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
|
|
}
|
|
|
|
return RTW_RX_HANDLED;
|
|
|
|
_success_exit:
|
|
|
|
return _SUCCESS;
|
|
|
|
_err_exit:
|
|
|
|
_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
|
|
return _FAIL;
|
|
}
|
|
|
|
|
|
void rtw_reordering_ctrl_timeout_handler(void *pcontext)
|
|
{
|
|
_irqL irql;
|
|
struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext;
|
|
_adapter *padapter = preorder_ctrl->padapter;
|
|
_queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
|
|
|
|
|
|
if (RTW_CANNOT_RUN(padapter))
|
|
return;
|
|
|
|
/* RTW_INFO("+rtw_reordering_ctrl_timeout_handler()=>\n"); */
|
|
|
|
_enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
|
|
if (preorder_ctrl)
|
|
preorder_ctrl->bReorderWaiting = _FALSE;
|
|
|
|
if (recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE) == _TRUE)
|
|
_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
|
|
|
|
_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
|
|
|
|
}
|
|
#endif /* defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL) */
|
|
|
|
static void recv_set_iseq_before_mpdu_process(union recv_frame *rframe, u16 seq_num, const char *caller)
|
|
{
|
|
#if defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL)
|
|
struct recv_reorder_ctrl *reorder_ctrl = rframe->u.hdr.preorder_ctrl;
|
|
|
|
if (reorder_ctrl) {
|
|
reorder_ctrl->indicate_seq = seq_num;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ %s("ADPT_FMT")-B tid:%u indicate_seq:%d, seq_num:%d\n"
|
|
, caller, ADPT_ARG(reorder_ctrl->padapter)
|
|
, reorder_ctrl->tid, reorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void recv_set_iseq_after_mpdu_process(union recv_frame *rframe, u16 seq_num, const char *caller)
|
|
{
|
|
#if defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL)
|
|
struct recv_reorder_ctrl *reorder_ctrl = rframe->u.hdr.preorder_ctrl;
|
|
|
|
if (reorder_ctrl) {
|
|
reorder_ctrl->indicate_seq = (reorder_ctrl->indicate_seq + 1) % 4096;
|
|
#ifdef DBG_RX_SEQ
|
|
RTW_INFO("DBG_RX_SEQ %s("ADPT_FMT")-A tid:%u indicate_seq:%d, seq_num:%d\n"
|
|
, caller, ADPT_ARG(reorder_ctrl->padapter)
|
|
, reorder_ctrl->tid, reorder_ctrl->indicate_seq, seq_num);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
int validate_mp_recv_frame(_adapter *adapter, union recv_frame *precv_frame)
|
|
{
|
|
int ret = _SUCCESS;
|
|
u8 *ptr = precv_frame->u.hdr.rx_data;
|
|
u8 type, subtype;
|
|
struct mp_priv *pmppriv = &adapter->mppriv;
|
|
struct mp_tx *pmptx;
|
|
unsigned char *sa , *da, *bs;
|
|
|
|
pmptx = &pmppriv->tx;
|
|
|
|
#if 0
|
|
if (1) {
|
|
u8 bDumpRxPkt;
|
|
type = GetFrameType(ptr);
|
|
subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */
|
|
|
|
rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
|
|
if (bDumpRxPkt == 1) { /* dump all rx packets */
|
|
int i;
|
|
RTW_INFO("############ type:0x%02x subtype:0x%02x #################\n", type, subtype);
|
|
|
|
for (i = 0; i < 64; i = i + 8)
|
|
RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i),
|
|
*(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7));
|
|
RTW_INFO("#############################\n");
|
|
}
|
|
}
|
|
#endif
|
|
if (pmppriv->bloopback) {
|
|
if (_rtw_memcmp(ptr + 24, pmptx->buf + 24, precv_frame->u.hdr.len - 24) == _FALSE) {
|
|
RTW_INFO("Compare payload content Fail !!!\n");
|
|
ret = _FAIL;
|
|
}
|
|
}
|
|
if (pmppriv->bSetRxBssid == _TRUE) {
|
|
|
|
sa = get_addr2_ptr(ptr);
|
|
da = GetAddr1Ptr(ptr);
|
|
bs = GetAddr3Ptr(ptr);
|
|
type = GetFrameType(ptr);
|
|
subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */
|
|
|
|
if (_rtw_memcmp(bs, adapter->mppriv.network_macaddr, ETH_ALEN) == _FALSE)
|
|
ret = _FAIL;
|
|
|
|
RTW_DBG("############ type:0x%02x subtype:0x%02x #################\n", type, subtype);
|
|
RTW_DBG("A2 sa %02X:%02X:%02X:%02X:%02X:%02X \n", *(sa) , *(sa + 1), *(sa+ 2), *(sa + 3), *(sa + 4), *(sa + 5));
|
|
RTW_DBG("A1 da %02X:%02X:%02X:%02X:%02X:%02X \n", *(da) , *(da + 1), *(da+ 2), *(da + 3), *(da + 4), *(da + 5));
|
|
RTW_DBG("A3 bs %02X:%02X:%02X:%02X:%02X:%02X \n --------------------------\n", *(bs) , *(bs + 1), *(bs+ 2), *(bs + 3), *(bs + 4), *(bs + 5));
|
|
}
|
|
|
|
if (!adapter->mppriv.bmac_filter)
|
|
return ret;
|
|
|
|
if (_rtw_memcmp(get_addr2_ptr(ptr), adapter->mppriv.mac_filter, ETH_ALEN) == _FALSE)
|
|
ret = _FAIL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static sint MPwlanhdr_to_ethhdr(union recv_frame *precvframe)
|
|
{
|
|
sint rmv_len;
|
|
u16 eth_type, len;
|
|
u8 bsnaphdr;
|
|
u8 *psnap_type;
|
|
u8 mcastheadermac[] = {0x01, 0x00, 0x5e};
|
|
|
|
struct ieee80211_snap_hdr *psnap;
|
|
|
|
sint ret = _SUCCESS;
|
|
_adapter *adapter = precvframe->u.hdr.adapter;
|
|
|
|
u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */
|
|
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
|
|
|
|
|
|
if (pattrib->encrypt)
|
|
recvframe_pull_tail(precvframe, pattrib->icv_len);
|
|
|
|
psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len);
|
|
psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
|
|
/* convert hdr + possible LLC headers into Ethernet header */
|
|
/* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */
|
|
if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
|
|
(_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == _FALSE) &&
|
|
(_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == _FALSE)) ||
|
|
/* eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || */
|
|
_rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
|
|
/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
|
|
bsnaphdr = _TRUE;
|
|
} else {
|
|
/* Leave Ethernet header part of hdr and full payload */
|
|
bsnaphdr = _FALSE;
|
|
}
|
|
|
|
rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
|
|
len = precvframe->u.hdr.len - rmv_len;
|
|
|
|
|
|
_rtw_memcpy(ð_type, ptr + rmv_len, 2);
|
|
eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */
|
|
pattrib->eth_type = eth_type;
|
|
|
|
{
|
|
ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
|
|
}
|
|
|
|
_rtw_memcpy(ptr, pattrib->dst, ETH_ALEN);
|
|
_rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
|
|
|
|
if (!bsnaphdr) {
|
|
len = htons(len);
|
|
_rtw_memcpy(ptr + 12, &len, 2);
|
|
}
|
|
|
|
|
|
len = htons(pattrib->seq_num);
|
|
/* RTW_INFO("wlan seq = %d ,seq_num =%x\n",len,pattrib->seq_num); */
|
|
_rtw_memcpy(ptr + 12, &len, 2);
|
|
if (adapter->mppriv.bRTWSmbCfg == _TRUE) {
|
|
/* if(_rtw_memcmp(mcastheadermac, pattrib->dst, 3) == _TRUE) */ /* SimpleConfig Dest. */
|
|
/* _rtw_memcpy(ptr+ETH_ALEN, pattrib->bssid, ETH_ALEN); */
|
|
|
|
if (_rtw_memcmp(mcastheadermac, pattrib->bssid, 3) == _TRUE) /* SimpleConfig Dest. */
|
|
_rtw_memcpy(ptr, pattrib->bssid, ETH_ALEN);
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
int mp_recv_frame(_adapter *padapter, union recv_frame *rframe)
|
|
{
|
|
int ret = _SUCCESS;
|
|
struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
|
|
_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
|
|
struct mp_priv *pmppriv = &padapter->mppriv;
|
|
#endif /* CONFIG_MP_INCLUDED */
|
|
u8 type;
|
|
u8 *ptr = rframe->u.hdr.rx_data;
|
|
u8 *psa, *pda, *pbssid;
|
|
struct sta_info *psta = NULL;
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_pre);
|
|
|
|
if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */
|
|
if (pattrib->crc_err == 1)
|
|
padapter->mppriv.rx_crcerrpktcount++;
|
|
else {
|
|
if (_SUCCESS == validate_mp_recv_frame(padapter, rframe))
|
|
padapter->mppriv.rx_pktcount++;
|
|
else
|
|
padapter->mppriv.rx_pktcount_filter_out++;
|
|
}
|
|
|
|
if (pmppriv->rx_bindicatePkt == _FALSE) {
|
|
ret = _FAIL;
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
goto exit;
|
|
} else {
|
|
type = GetFrameType(ptr);
|
|
pattrib->to_fr_ds = get_tofr_ds(ptr);
|
|
pattrib->frag_num = GetFragNum(ptr);
|
|
pattrib->seq_num = GetSequence(ptr);
|
|
pattrib->pw_save = GetPwrMgt(ptr);
|
|
pattrib->mfrag = GetMFrag(ptr);
|
|
pattrib->mdata = GetMData(ptr);
|
|
pattrib->privacy = GetPrivacy(ptr);
|
|
pattrib->order = GetOrder(ptr);
|
|
|
|
if (type == WIFI_DATA_TYPE) {
|
|
pda = get_da(ptr);
|
|
psa = get_sa(ptr);
|
|
pbssid = get_hdr_bssid(ptr);
|
|
|
|
_rtw_memcpy(pattrib->dst, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->src, psa, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN);
|
|
|
|
switch (pattrib->to_fr_ds) {
|
|
case 0:
|
|
_rtw_memcpy(pattrib->ra, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, psa, ETH_ALEN);
|
|
ret = sta2sta_data_frame(padapter, rframe, &psta);
|
|
break;
|
|
|
|
case 1:
|
|
|
|
_rtw_memcpy(pattrib->ra, pda, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN);
|
|
ret = ap2sta_data_frame(padapter, rframe, &psta);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
_rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, psa, ETH_ALEN);
|
|
ret = sta2ap_data_frame(padapter, rframe, &psta);
|
|
break;
|
|
|
|
case 3:
|
|
_rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
|
|
_rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN);
|
|
ret = _FAIL;
|
|
break;
|
|
|
|
default:
|
|
ret = _FAIL;
|
|
break;
|
|
}
|
|
|
|
ret = MPwlanhdr_to_ethhdr(rframe);
|
|
|
|
if (ret != _SUCCESS) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" wlanhdr_to_ethhdr: drop pkt\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
ret = _FAIL;
|
|
goto exit;
|
|
}
|
|
if (!RTW_CANNOT_RUN(padapter)) {
|
|
/* indicate this recv_frame */
|
|
ret = rtw_recv_indicatepkt(padapter, rframe);
|
|
if (ret != _SUCCESS) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" rtw_recv_indicatepkt fail!\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
ret = _FAIL;
|
|
|
|
goto exit;
|
|
}
|
|
} else {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
|
|
, FUNC_ADPT_ARG(padapter)
|
|
, rtw_is_drv_stopped(padapter) ? "True" : "False"
|
|
, rtw_is_surprise_removed(padapter) ? "True" : "False");
|
|
#endif
|
|
ret = _FAIL;
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
ret = _FAIL;
|
|
|
|
exit:
|
|
return ret;
|
|
|
|
}
|
|
#endif
|
|
|
|
static sint fill_radiotap_hdr(_adapter *padapter, union recv_frame *precvframe, u8 *buf)
|
|
{
|
|
#define CHAN2FREQ(a) ((a < 14) ? (2407+5*a) : (5000+5*a))
|
|
|
|
#if 0
|
|
#define RTW_RX_RADIOTAP_PRESENT (\
|
|
(1 << IEEE80211_RADIOTAP_TSFT) | \
|
|
(1 << IEEE80211_RADIOTAP_FLAGS) | \
|
|
(1 << IEEE80211_RADIOTAP_RATE) | \
|
|
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
|
|
(0 << IEEE80211_RADIOTAP_FHSS) | \
|
|
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
|
|
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
|
|
(0 << IEEE80211_RADIOTAP_LOCK_QUALITY) | \
|
|
(0 << IEEE80211_RADIOTAP_TX_ATTENUATION) | \
|
|
(0 << IEEE80211_RADIOTAP_DB_TX_ATTENUATION) | \
|
|
(0 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
|
|
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
|
|
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
|
|
(0 << IEEE80211_RADIOTAP_DB_ANTNOISE) | \
|
|
(0 << IEEE80211_RADIOTAP_RX_FLAGS) | \
|
|
(0 << IEEE80211_RADIOTAP_TX_FLAGS) | \
|
|
(0 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
|
|
(0 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
|
|
(0 << IEEE80211_RADIOTAP_MCS) | \
|
|
(0 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE)| \
|
|
(0 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | \
|
|
(0 << IEEE80211_RADIOTAP_EXT) | \
|
|
0)
|
|
|
|
/* (0 << IEEE80211_RADIOTAP_AMPDU_STATUS) | \ */
|
|
/* (0 << IEEE80211_RADIOTAP_VHT) | \ */
|
|
#endif
|
|
|
|
#ifndef IEEE80211_RADIOTAP_RX_FLAGS
|
|
#define IEEE80211_RADIOTAP_RX_FLAGS 14
|
|
#endif
|
|
|
|
#ifndef IEEE80211_RADIOTAP_MCS
|
|
#define IEEE80211_RADIOTAP_MCS 19
|
|
#endif
|
|
#ifndef IEEE80211_RADIOTAP_VHT
|
|
#define IEEE80211_RADIOTAP_VHT 21
|
|
#endif
|
|
|
|
#ifndef IEEE80211_RADIOTAP_F_BADFCS
|
|
#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */
|
|
#endif
|
|
|
|
sint ret = _SUCCESS;
|
|
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
|
|
|
|
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
|
|
|
|
u16 tmp_16bit = 0;
|
|
|
|
u8 data_rate[] = {
|
|
2, 4, 11, 22, /* CCK */
|
|
12, 18, 24, 36, 48, 72, 93, 108, /* OFDM */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* HT MCS index */
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 1 */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 2 */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 3 */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 4 */
|
|
};
|
|
|
|
_pkt *pskb = NULL;
|
|
|
|
struct ieee80211_radiotap_header *rtap_hdr = NULL;
|
|
u8 *ptr = NULL;
|
|
|
|
u8 hdr_buf[64] = {0};
|
|
u16 rt_len = 8;
|
|
|
|
/* create header */
|
|
rtap_hdr = (struct ieee80211_radiotap_header *)&hdr_buf[0];
|
|
rtap_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
|
|
|
|
/* tsft */
|
|
if (pattrib->tsfl) {
|
|
u64 tmp_64bit;
|
|
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_TSFT);
|
|
tmp_64bit = cpu_to_le64(pattrib->tsfl);
|
|
memcpy(&hdr_buf[rt_len], &tmp_64bit, 8);
|
|
rt_len += 8;
|
|
}
|
|
|
|
/* flags */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_FLAGS);
|
|
if (0)
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_CFP;
|
|
|
|
if (0)
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_SHORTPRE;
|
|
|
|
if ((pattrib->encrypt == 1) || (pattrib->encrypt == 5))
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_WEP;
|
|
|
|
if (pattrib->mfrag)
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_FRAG;
|
|
|
|
/* always append FCS */
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_FCS;
|
|
|
|
|
|
if (0)
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_DATAPAD;
|
|
|
|
if (pattrib->crc_err)
|
|
hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_BADFCS;
|
|
|
|
if (pattrib->sgi) {
|
|
/* Currently unspecified but used */
|
|
hdr_buf[rt_len] |= 0x80;
|
|
}
|
|
rt_len += 1;
|
|
|
|
/* rate */
|
|
if (pattrib->data_rate <= DESC_RATE54M) {
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
|
|
if (pattrib->data_rate <= DESC_RATE11M) {
|
|
/* CCK */
|
|
hdr_buf[rt_len] = data_rate[pattrib->data_rate];
|
|
} else {
|
|
/* OFDM */
|
|
hdr_buf[rt_len] = data_rate[pattrib->data_rate];
|
|
}
|
|
}
|
|
rt_len += 1; /* force padding 1 byte for aligned */
|
|
|
|
/* channel */
|
|
tmp_16bit = 0;
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL);
|
|
tmp_16bit = CHAN2FREQ(rtw_get_oper_ch(padapter));
|
|
/*tmp_16bit = CHAN2FREQ(pHalData->current_channel);*/
|
|
memcpy(&hdr_buf[rt_len], &tmp_16bit, 2);
|
|
rt_len += 2;
|
|
|
|
/* channel flags */
|
|
tmp_16bit = 0;
|
|
if (pHalData->current_band_type == 0)
|
|
tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_2GHZ);
|
|
else
|
|
tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_5GHZ);
|
|
|
|
if (pattrib->data_rate <= DESC_RATE54M) {
|
|
if (pattrib->data_rate <= DESC_RATE11M) {
|
|
/* CCK */
|
|
tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_CCK);
|
|
} else {
|
|
/* OFDM */
|
|
tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_OFDM);
|
|
}
|
|
} else
|
|
tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_DYN);
|
|
memcpy(&hdr_buf[rt_len], &tmp_16bit, 2);
|
|
rt_len += 2;
|
|
|
|
/* dBm Antenna Signal */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
|
|
hdr_buf[rt_len] = pattrib->phy_info.recv_signal_power;
|
|
rt_len += 1;
|
|
|
|
#if 0
|
|
/* dBm Antenna Noise */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
|
|
hdr_buf[rt_len] = 0;
|
|
rt_len += 1;
|
|
|
|
/* Signal Quality */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_LOCK_QUALITY);
|
|
hdr_buf[rt_len] = pattrib->phy_info.signal_quality;
|
|
rt_len += 1;
|
|
#endif
|
|
|
|
/* Antenna */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_ANTENNA);
|
|
hdr_buf[rt_len] = 0; /* pHalData->rf_type; */
|
|
rt_len += 1;
|
|
|
|
/* RX flags */
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_RX_FLAGS);
|
|
#if 0
|
|
tmp_16bit = cpu_to_le16(0);
|
|
memcpy(ptr, &tmp_16bit, 1);
|
|
#endif
|
|
rt_len += 2;
|
|
|
|
/* MCS information */
|
|
if (pattrib->data_rate >= DESC_RATEMCS0 && pattrib->data_rate <= DESC_RATEMCS31) {
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_MCS);
|
|
/* known, flag */
|
|
hdr_buf[rt_len] |= BIT1; /* MCS index known */
|
|
|
|
/* bandwidth */
|
|
hdr_buf[rt_len] |= BIT0;
|
|
hdr_buf[rt_len + 1] |= (pattrib->bw & 0x03);
|
|
|
|
/* guard interval */
|
|
hdr_buf[rt_len] |= BIT2;
|
|
hdr_buf[rt_len + 1] |= (pattrib->sgi & 0x01) << 2;
|
|
|
|
/* STBC */
|
|
hdr_buf[rt_len] |= BIT5;
|
|
hdr_buf[rt_len + 1] |= (pattrib->stbc & 0x03) << 5;
|
|
|
|
rt_len += 2;
|
|
|
|
/* MCS rate index */
|
|
hdr_buf[rt_len] = data_rate[pattrib->data_rate];
|
|
rt_len += 1;
|
|
}
|
|
|
|
/* VHT */
|
|
if (pattrib->data_rate >= DESC_RATEVHTSS1MCS0 && pattrib->data_rate <= DESC_RATEVHTSS4MCS9) {
|
|
rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_VHT);
|
|
|
|
/* known 16 bit, flag 8 bit */
|
|
tmp_16bit = 0;
|
|
|
|
/* Bandwidth */
|
|
tmp_16bit |= BIT6;
|
|
|
|
/* Group ID */
|
|
tmp_16bit |= BIT7;
|
|
|
|
/* Partial AID */
|
|
tmp_16bit |= BIT8;
|
|
|
|
/* STBC */
|
|
tmp_16bit |= BIT0;
|
|
hdr_buf[rt_len + 2] |= (pattrib->stbc & 0x01);
|
|
|
|
/* Guard interval */
|
|
tmp_16bit |= BIT2;
|
|
hdr_buf[rt_len + 2] |= (pattrib->sgi & 0x01) << 2;
|
|
|
|
/* LDPC extra OFDM symbol */
|
|
tmp_16bit |= BIT4;
|
|
hdr_buf[rt_len + 2] |= (pattrib->ldpc & 0x01) << 4;
|
|
|
|
memcpy(&hdr_buf[rt_len], &tmp_16bit, 2);
|
|
rt_len += 3;
|
|
|
|
/* bandwidth */
|
|
if (pattrib->bw == 0)
|
|
hdr_buf[rt_len] |= 0;
|
|
else if (pattrib->bw == 1)
|
|
hdr_buf[rt_len] |= 1;
|
|
else if (pattrib->bw == 2)
|
|
hdr_buf[rt_len] |= 4;
|
|
else if (pattrib->bw == 3)
|
|
hdr_buf[rt_len] |= 11;
|
|
rt_len += 1;
|
|
|
|
/* mcs_nss */
|
|
if (pattrib->data_rate >= DESC_RATEVHTSS1MCS0 && pattrib->data_rate <= DESC_RATEVHTSS1MCS9) {
|
|
hdr_buf[rt_len] |= 1;
|
|
hdr_buf[rt_len] |= data_rate[pattrib->data_rate] << 4;
|
|
} else if (pattrib->data_rate >= DESC_RATEVHTSS2MCS0 && pattrib->data_rate <= DESC_RATEVHTSS2MCS9) {
|
|
hdr_buf[rt_len + 1] |= 2;
|
|
hdr_buf[rt_len + 1] |= data_rate[pattrib->data_rate] << 4;
|
|
} else if (pattrib->data_rate >= DESC_RATEVHTSS3MCS0 && pattrib->data_rate <= DESC_RATEVHTSS3MCS9) {
|
|
hdr_buf[rt_len + 2] |= 3;
|
|
hdr_buf[rt_len + 2] |= data_rate[pattrib->data_rate] << 4;
|
|
} else if (pattrib->data_rate >= DESC_RATEVHTSS4MCS0 && pattrib->data_rate <= DESC_RATEVHTSS4MCS9) {
|
|
hdr_buf[rt_len + 3] |= 4;
|
|
hdr_buf[rt_len + 3] |= data_rate[pattrib->data_rate] << 4;
|
|
}
|
|
rt_len += 4;
|
|
|
|
/* coding */
|
|
hdr_buf[rt_len] = 0;
|
|
rt_len += 1;
|
|
|
|
/* group_id */
|
|
hdr_buf[rt_len] = 0;
|
|
rt_len += 1;
|
|
|
|
/* partial_aid */
|
|
tmp_16bit = 0;
|
|
memcpy(&hdr_buf[rt_len], &tmp_16bit, 2);
|
|
rt_len += 2;
|
|
}
|
|
|
|
/* push to skb */
|
|
pskb = (_pkt *)buf;
|
|
if (skb_headroom(pskb) < rt_len) {
|
|
RTW_INFO("%s:%d %s headroom is too small.\n", __FILE__, __LINE__, __func__);
|
|
ret = _FAIL;
|
|
return ret;
|
|
}
|
|
|
|
ptr = skb_push(pskb, rt_len);
|
|
if (ptr) {
|
|
rtap_hdr->it_len = cpu_to_le16(rt_len);
|
|
rtap_hdr->it_present = cpu_to_le32(rtap_hdr->it_present);
|
|
memcpy(ptr, rtap_hdr, rt_len);
|
|
} else
|
|
ret = _FAIL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
|
|
int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe)
|
|
{
|
|
int ret = _SUCCESS;
|
|
_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
_pkt *pskb = NULL;
|
|
|
|
/* read skb information from recv frame */
|
|
pskb = rframe->u.hdr.pkt;
|
|
pskb->len = rframe->u.hdr.len;
|
|
pskb->data = rframe->u.hdr.rx_data;
|
|
skb_set_tail_pointer(pskb, rframe->u.hdr.len);
|
|
|
|
#ifndef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
/* fill radiotap header */
|
|
if (fill_radiotap_hdr(padapter, rframe, (u8 *)pskb) == _FAIL) {
|
|
ret = _FAIL;
|
|
rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
/* write skb information to recv frame */
|
|
skb_reset_mac_header(pskb);
|
|
rframe->u.hdr.len = pskb->len;
|
|
rframe->u.hdr.rx_data = pskb->data;
|
|
rframe->u.hdr.rx_head = pskb->head;
|
|
rframe->u.hdr.rx_tail = skb_tail_pointer(pskb);
|
|
rframe->u.hdr.rx_end = skb_end_pointer(pskb);
|
|
|
|
if (!RTW_CANNOT_RUN(padapter)) {
|
|
/* indicate this recv_frame */
|
|
ret = rtw_recv_monitor(padapter, rframe);
|
|
if (ret != _SUCCESS) {
|
|
ret = _FAIL;
|
|
rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */
|
|
goto exit;
|
|
}
|
|
} else {
|
|
ret = _FAIL;
|
|
rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
#endif
|
|
int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe)
|
|
{
|
|
int ret = _SUCCESS;
|
|
#ifdef DBG_RX_COUNTER_DUMP
|
|
struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
|
|
#endif
|
|
_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
|
|
#ifdef DBG_RX_COUNTER_DUMP
|
|
if (padapter->dump_rx_cnt_mode & DUMP_DRV_RX_COUNTER) {
|
|
if (pattrib->crc_err == 1)
|
|
padapter->drv_rx_cnt_crcerror++;
|
|
else
|
|
padapter->drv_rx_cnt_ok++;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
if (padapter->registrypriv.mp_mode == 1 || padapter->mppriv.bRTWSmbCfg == _TRUE) {
|
|
mp_recv_frame(padapter, rframe);
|
|
ret = _FAIL;
|
|
goto exit;
|
|
} else
|
|
#endif
|
|
{
|
|
/* check the frame crtl field and decache */
|
|
ret = validate_recv_frame(padapter, rframe);
|
|
if (ret != _SUCCESS) {
|
|
rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
|
|
goto exit;
|
|
}
|
|
}
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
/*#define DBG_RX_BMC_FRAME*/
|
|
int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
int ret = _SUCCESS;
|
|
union recv_frame *orig_prframe = prframe;
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
|
|
#ifdef CONFIG_TDLS
|
|
u8 *psnap_type, *pcategory;
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post);
|
|
|
|
prframe = decryptor(padapter, prframe);
|
|
if (prframe == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" decryptor: drop pkt\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
ret = _FAIL;
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_err);
|
|
goto _recv_data_drop;
|
|
}
|
|
|
|
#ifdef DBG_RX_BMC_FRAME
|
|
if (IS_MCAST(pattrib->ra))
|
|
RTW_INFO("%s =>"ADPT_FMT" Rx BC/MC from "MAC_FMT"\n", __func__, ADPT_ARG(padapter), MAC_ARG(pattrib->ta));
|
|
#endif
|
|
|
|
#if 0
|
|
if (is_primary_adapter(padapter)) {
|
|
RTW_INFO("+++\n");
|
|
{
|
|
int i;
|
|
u8 *ptr = get_recvframe_data(prframe);
|
|
for (i = 0; i < 140; i = i + 8)
|
|
RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr + i),
|
|
*(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7));
|
|
|
|
}
|
|
RTW_INFO("---\n");
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_TDLS
|
|
/* check TDLS frame */
|
|
psnap_type = get_recvframe_data(orig_prframe) + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE;
|
|
pcategory = psnap_type + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN;
|
|
|
|
if ((_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, ETH_TYPE_LEN)) &&
|
|
((*pcategory == RTW_WLAN_CATEGORY_TDLS) || (*pcategory == RTW_WLAN_CATEGORY_P2P))) {
|
|
ret = OnTDLS(padapter, prframe);
|
|
if (ret == _FAIL)
|
|
goto _exit_recv_func;
|
|
}
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
prframe = recvframe_chk_defrag(padapter, prframe);
|
|
if (prframe == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" recvframe_chk_defrag: drop pkt\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_defrag_err);
|
|
goto _recv_data_drop;
|
|
}
|
|
|
|
prframe = portctrl(padapter, prframe);
|
|
if (prframe == NULL) {
|
|
#ifdef DBG_RX_DROP_FRAME
|
|
RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" portctrl: drop pkt\n"
|
|
, FUNC_ADPT_ARG(padapter));
|
|
#endif
|
|
ret = _FAIL;
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_post_portctrl_err);
|
|
goto _recv_data_drop;
|
|
}
|
|
|
|
count_rx_stats(padapter, prframe, NULL);
|
|
|
|
#ifdef CONFIG_WAPI_SUPPORT
|
|
rtw_wapi_update_info(padapter, prframe);
|
|
#endif
|
|
|
|
#if defined(CONFIG_80211N_HT) && defined(CONFIG_RECV_REORDERING_CTRL)
|
|
/* including perform A-MPDU Rx Ordering Buffer Control */
|
|
ret = recv_indicatepkt_reorder(padapter, prframe);
|
|
if (ret == _FAIL) {
|
|
rtw_free_recvframe(orig_prframe, pfree_recv_queue);
|
|
goto _recv_data_drop;
|
|
} else if (ret == RTW_RX_HANDLED) /* queued OR indicated in order */
|
|
goto _exit_recv_func;
|
|
#endif
|
|
|
|
recv_set_iseq_before_mpdu_process(prframe, pattrib->seq_num, __func__);
|
|
ret = recv_process_mpdu(padapter, prframe);
|
|
recv_set_iseq_after_mpdu_process(prframe, pattrib->seq_num, __func__);
|
|
if (ret == _FAIL)
|
|
goto _recv_data_drop;
|
|
|
|
_exit_recv_func:
|
|
return ret;
|
|
|
|
_recv_data_drop:
|
|
precvpriv->dbg_rx_drop_count++;
|
|
return ret;
|
|
}
|
|
|
|
int recv_func(_adapter *padapter, union recv_frame *rframe)
|
|
{
|
|
int ret;
|
|
struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib;
|
|
struct recv_priv *recvpriv = &padapter->recvpriv;
|
|
struct security_priv *psecuritypriv = &padapter->securitypriv;
|
|
struct mlme_priv *mlmepriv = &padapter->mlmepriv;
|
|
#ifdef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
u8 type;
|
|
u8 *ptr = rframe->u.hdr.rx_data;
|
|
#endif
|
|
if (check_fwstate(mlmepriv, WIFI_MONITOR_STATE)) {
|
|
/* monitor mode */
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
|
|
recv_frame_monitor(padapter, rframe);
|
|
#endif
|
|
ret = _SUCCESS;
|
|
goto exit;
|
|
} else
|
|
{}
|
|
#ifdef CONFIG_CUSTOMER_ALIBABA_GENERAL
|
|
type = GetFrameType(ptr);
|
|
if ((type == WIFI_DATA_TYPE)&& check_fwstate(mlmepriv, WIFI_STATION_STATE)) {
|
|
struct wlan_network *cur_network = &(mlmepriv->cur_network);
|
|
if ( _rtw_memcmp(get_addr2_ptr(ptr), cur_network->network.MacAddress, ETH_ALEN)==0) {
|
|
recv_frame_monitor(padapter, rframe);
|
|
ret = _SUCCESS;
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif
|
|
/* check if need to handle uc_swdec_pending_queue*/
|
|
if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) {
|
|
union recv_frame *pending_frame;
|
|
int cnt = 0;
|
|
|
|
while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) {
|
|
cnt++;
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_dequeue);
|
|
recv_func_posthandle(padapter, pending_frame);
|
|
}
|
|
|
|
if (cnt)
|
|
RTW_INFO(FUNC_ADPT_FMT" dequeue %d from uc_swdec_pending_queue\n",
|
|
FUNC_ADPT_ARG(padapter), cnt);
|
|
}
|
|
|
|
DBG_COUNTER(padapter->rx_logs.core_rx);
|
|
ret = recv_func_prehandle(padapter, rframe);
|
|
|
|
if (ret == _SUCCESS) {
|
|
|
|
/* check if need to enqueue into uc_swdec_pending_queue*/
|
|
if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
|
|
!IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 &&
|
|
(prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt == _TRUE) &&
|
|
psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK &&
|
|
!psecuritypriv->busetkipkey) {
|
|
DBG_COUNTER(padapter->rx_logs.core_rx_enqueue);
|
|
rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue);
|
|
/* RTW_INFO("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); */
|
|
|
|
if (recvpriv->free_recvframe_cnt < NR_RECVFRAME / 4) {
|
|
/* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */
|
|
rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue);
|
|
if (rframe)
|
|
goto do_posthandle;
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
do_posthandle:
|
|
ret = recv_func_posthandle(padapter, rframe);
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
|
|
s32 rtw_recv_entry(union recv_frame *precvframe)
|
|
{
|
|
_adapter *padapter;
|
|
struct recv_priv *precvpriv;
|
|
s32 ret = _SUCCESS;
|
|
|
|
|
|
|
|
padapter = precvframe->u.hdr.adapter;
|
|
|
|
precvpriv = &padapter->recvpriv;
|
|
|
|
|
|
ret = recv_func(padapter, precvframe);
|
|
if (ret == _FAIL) {
|
|
goto _recv_entry_drop;
|
|
}
|
|
|
|
|
|
precvpriv->rx_pkts++;
|
|
|
|
|
|
return ret;
|
|
|
|
_recv_entry_drop:
|
|
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
if (padapter->registrypriv.mp_mode == 1)
|
|
padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
static void rtw_signal_stat_timer_hdl(void *ctx)
|
|
{
|
|
_adapter *adapter = (_adapter *)ctx;
|
|
struct recv_priv *recvpriv = &adapter->recvpriv;
|
|
|
|
u32 tmp_s, tmp_q;
|
|
u8 avg_signal_strength = 0;
|
|
u8 avg_signal_qual = 0;
|
|
u32 num_signal_strength = 0;
|
|
u32 num_signal_qual = 0;
|
|
u8 ratio_pre_stat = 0, ratio_curr_stat = 0, ratio_total = 0, ratio_profile = SIGNAL_STAT_CALC_PROFILE_0;
|
|
|
|
if (adapter->recvpriv.is_signal_dbg) {
|
|
/* update the user specific value, signal_strength_dbg, to signal_strength, rssi */
|
|
adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg;
|
|
adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg);
|
|
} else {
|
|
|
|
if (recvpriv->signal_strength_data.update_req == 0) { /* update_req is clear, means we got rx */
|
|
avg_signal_strength = recvpriv->signal_strength_data.avg_val;
|
|
num_signal_strength = recvpriv->signal_strength_data.total_num;
|
|
/* after avg_vals are accquired, we can re-stat the signal values */
|
|
recvpriv->signal_strength_data.update_req = 1;
|
|
}
|
|
|
|
if (recvpriv->signal_qual_data.update_req == 0) { /* update_req is clear, means we got rx */
|
|
avg_signal_qual = recvpriv->signal_qual_data.avg_val;
|
|
num_signal_qual = recvpriv->signal_qual_data.total_num;
|
|
/* after avg_vals are accquired, we can re-stat the signal values */
|
|
recvpriv->signal_qual_data.update_req = 1;
|
|
}
|
|
|
|
if (num_signal_strength == 0) {
|
|
if (rtw_get_on_cur_ch_time(adapter) == 0
|
|
|| rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval
|
|
)
|
|
goto set_timer;
|
|
}
|
|
|
|
if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == _TRUE
|
|
|| check_fwstate(&adapter->mlmepriv, _FW_LINKED) == _FALSE
|
|
)
|
|
goto set_timer;
|
|
|
|
#ifdef CONFIG_CONCURRENT_MODE
|
|
if (rtw_mi_buddy_check_fwstate(adapter, _FW_UNDER_SURVEY) == _TRUE)
|
|
goto set_timer;
|
|
#endif
|
|
|
|
if (RTW_SIGNAL_STATE_CALC_PROFILE < SIGNAL_STAT_CALC_PROFILE_MAX)
|
|
ratio_profile = RTW_SIGNAL_STATE_CALC_PROFILE;
|
|
|
|
ratio_pre_stat = signal_stat_calc_profile[ratio_profile][0];
|
|
ratio_curr_stat = signal_stat_calc_profile[ratio_profile][1];
|
|
ratio_total = ratio_pre_stat + ratio_curr_stat;
|
|
|
|
/* update value of signal_strength, rssi, signal_qual */
|
|
tmp_s = (ratio_curr_stat * avg_signal_strength + ratio_pre_stat * recvpriv->signal_strength);
|
|
if (tmp_s % ratio_total)
|
|
tmp_s = tmp_s / ratio_total + 1;
|
|
else
|
|
tmp_s = tmp_s / ratio_total;
|
|
if (tmp_s > 100)
|
|
tmp_s = 100;
|
|
|
|
tmp_q = (ratio_curr_stat * avg_signal_qual + ratio_pre_stat * recvpriv->signal_qual);
|
|
if (tmp_q % ratio_total)
|
|
tmp_q = tmp_q / ratio_total + 1;
|
|
else
|
|
tmp_q = tmp_q / ratio_total;
|
|
if (tmp_q > 100)
|
|
tmp_q = 100;
|
|
|
|
recvpriv->signal_strength = tmp_s;
|
|
recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
|
|
recvpriv->signal_qual = tmp_q;
|
|
|
|
#if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1
|
|
RTW_INFO(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u"
|
|
", num_signal_strength:%u, num_signal_qual:%u"
|
|
", on_cur_ch_ms:%d"
|
|
"\n"
|
|
, FUNC_ADPT_ARG(adapter)
|
|
, recvpriv->signal_strength
|
|
, recvpriv->rssi
|
|
, recvpriv->signal_qual
|
|
, num_signal_strength, num_signal_qual
|
|
, rtw_get_on_cur_ch_time(adapter) ? rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) : 0
|
|
);
|
|
#endif
|
|
}
|
|
|
|
set_timer:
|
|
rtw_set_signal_stat_timer(recvpriv);
|
|
|
|
}
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
static void rx_process_rssi(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data;
|
|
#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
u32 last_rssi, tmp_val;
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
/* RTW_INFO("process_rssi=> pattrib->rssil(%d) signal_strength(%d)\n ",pattrib->recv_signal_power,pattrib->signal_strength); */
|
|
/* if(pRfd->Status.bPacketToSelf || pRfd->Status.bPacketBeacon) */
|
|
{
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
if (signal_stat->update_req) {
|
|
signal_stat->total_num = 0;
|
|
signal_stat->total_val = 0;
|
|
signal_stat->update_req = 0;
|
|
}
|
|
|
|
signal_stat->total_num++;
|
|
signal_stat->total_val += pattrib->phy_info.signal_strength;
|
|
signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
|
|
#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
/* Adapter->RxStats.RssiCalculateCnt++; */ /* For antenna Test */
|
|
if (padapter->recvpriv.signal_strength_data.total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
|
|
padapter->recvpriv.signal_strength_data.total_num = PHY_RSSI_SLID_WIN_MAX;
|
|
last_rssi = padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index];
|
|
padapter->recvpriv.signal_strength_data.total_val -= last_rssi;
|
|
}
|
|
padapter->recvpriv.signal_strength_data.total_val += pattrib->phy_info.signal_strength;
|
|
|
|
padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index++] = pattrib->phy_info.signal_strength;
|
|
if (padapter->recvpriv.signal_strength_data.index >= PHY_RSSI_SLID_WIN_MAX)
|
|
padapter->recvpriv.signal_strength_data.index = 0;
|
|
|
|
|
|
tmp_val = padapter->recvpriv.signal_strength_data.total_val / padapter->recvpriv.signal_strength_data.total_num;
|
|
|
|
if (padapter->recvpriv.is_signal_dbg) {
|
|
padapter->recvpriv.signal_strength = padapter->recvpriv.signal_strength_dbg;
|
|
padapter->recvpriv.rssi = (s8)translate_percentage_to_dbm(padapter->recvpriv.signal_strength_dbg);
|
|
} else {
|
|
padapter->recvpriv.signal_strength = tmp_val;
|
|
padapter->recvpriv.rssi = (s8)translate_percentage_to_dbm(tmp_val);
|
|
}
|
|
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
}
|
|
}
|
|
|
|
static void rx_process_link_qual(_adapter *padapter, union recv_frame *prframe)
|
|
{
|
|
struct rx_pkt_attrib *pattrib;
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
struct signal_stat *signal_stat;
|
|
#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
u32 last_evm = 0, tmpVal;
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
if (prframe == NULL || padapter == NULL)
|
|
return;
|
|
|
|
pattrib = &prframe->u.hdr.attrib;
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
signal_stat = &padapter->recvpriv.signal_qual_data;
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
|
|
/* RTW_INFO("process_link_qual=> pattrib->signal_qual(%d)\n ",pattrib->signal_qual); */
|
|
|
|
#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
|
|
if (signal_stat->update_req) {
|
|
signal_stat->total_num = 0;
|
|
signal_stat->total_val = 0;
|
|
signal_stat->update_req = 0;
|
|
}
|
|
|
|
signal_stat->total_num++;
|
|
signal_stat->total_val += pattrib->phy_info.signal_quality;
|
|
signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
|
|
|
|
#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
if (pattrib->phy_info.signal_quality != 0) {
|
|
/* */
|
|
/* 1. Record the general EVM to the sliding window. */
|
|
/* */
|
|
if (padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) {
|
|
padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX;
|
|
last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index];
|
|
padapter->recvpriv.signal_qual_data.total_val -= last_evm;
|
|
}
|
|
padapter->recvpriv.signal_qual_data.total_val += pattrib->phy_info.signal_quality;
|
|
|
|
padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = pattrib->phy_info.signal_quality;
|
|
if (padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX)
|
|
padapter->recvpriv.signal_qual_data.index = 0;
|
|
|
|
|
|
/* <1> Showed on UI for user, in percentage. */
|
|
tmpVal = padapter->recvpriv.signal_qual_data.total_val / padapter->recvpriv.signal_qual_data.total_num;
|
|
padapter->recvpriv.signal_qual = (u8)tmpVal;
|
|
|
|
}
|
|
#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */
|
|
}
|
|
|
|
void rx_process_phy_info(_adapter *padapter, union recv_frame *rframe)
|
|
{
|
|
/* Check RSSI */
|
|
rx_process_rssi(padapter, rframe);
|
|
|
|
/* Check PWDB */
|
|
/* process_PWDB(padapter, rframe); */
|
|
|
|
/* UpdateRxSignalStatistics8192C(Adapter, pRfd); */
|
|
|
|
/* Check EVM */
|
|
rx_process_link_qual(padapter, rframe);
|
|
rtw_store_phy_info(padapter, rframe);
|
|
}
|
|
|
|
void rx_query_phy_status(
|
|
union recv_frame *precvframe,
|
|
u8 *pphy_status)
|
|
{
|
|
PADAPTER padapter = precvframe->u.hdr.adapter;
|
|
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
|
|
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
|
|
struct phydm_phyinfo_struct *p_phy_info = &pattrib->phy_info;
|
|
u8 *wlanhdr;
|
|
struct phydm_perpkt_info_struct pkt_info;
|
|
u8 *ta, *ra;
|
|
u8 is_ra_bmc;
|
|
struct sta_priv *pstapriv;
|
|
struct sta_info *psta = NULL;
|
|
struct recv_priv *precvpriv = &padapter->recvpriv;
|
|
/* _irqL irqL; */
|
|
|
|
pkt_info.is_packet_match_bssid = _FALSE;
|
|
pkt_info.is_packet_to_self = _FALSE;
|
|
pkt_info.is_packet_beacon = _FALSE;
|
|
pkt_info.ppdu_cnt = pattrib->ppdu_cnt;
|
|
pkt_info.station_id = 0xFF;
|
|
|
|
wlanhdr = get_recvframe_data(precvframe);
|
|
|
|
ta = get_ta(wlanhdr);
|
|
ra = get_ra(wlanhdr);
|
|
is_ra_bmc = IS_MCAST(ra);
|
|
|
|
if (_rtw_memcmp(adapter_mac_addr(padapter), ta, ETH_ALEN) == _TRUE) {
|
|
static systime start_time = 0;
|
|
|
|
#if 0 /*For debug */
|
|
if (IsFrameTypeCtrl(wlanhdr)) {
|
|
RTW_INFO("-->Control frame: Y\n");
|
|
RTW_INFO("-->pkt_len: %d\n", pattrib->pkt_len);
|
|
RTW_INFO("-->Sub Type = 0x%X\n", get_frame_sub_type(wlanhdr));
|
|
}
|
|
|
|
/* Dump first 40 bytes of header */
|
|
int i = 0;
|
|
|
|
for (i = 0; i < 40; i++)
|
|
RTW_INFO("%d: %X\n", i, *((u8 *)wlanhdr + i));
|
|
|
|
RTW_INFO("\n");
|
|
#endif
|
|
|
|
if ((start_time == 0) || (rtw_get_passing_time_ms(start_time) > 5000)) {
|
|
RTW_PRINT("Warning!!! %s: Confilc mac addr!!\n", __func__);
|
|
start_time = rtw_get_current_time();
|
|
}
|
|
precvpriv->dbg_rx_conflic_mac_addr_cnt++;
|
|
} else {
|
|
pstapriv = &padapter->stapriv;
|
|
psta = rtw_get_stainfo(pstapriv, ta);
|
|
if (psta)
|
|
pkt_info.station_id = psta->cmn.mac_id;
|
|
}
|
|
|
|
pkt_info.is_packet_match_bssid = (!IsFrameTypeCtrl(wlanhdr))
|
|
&& (!pattrib->icv_err) && (!pattrib->crc_err)
|
|
&& ((!MLME_IS_MESH(padapter) && _rtw_memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN))
|
|
|| (MLME_IS_MESH(padapter) && psta));
|
|
|
|
pkt_info.is_to_self = (!pattrib->icv_err) && (!pattrib->crc_err)
|
|
&& _rtw_memcmp(ra, adapter_mac_addr(padapter), ETH_ALEN);
|
|
|
|
pkt_info.is_packet_to_self = pkt_info.is_packet_match_bssid
|
|
&& _rtw_memcmp(ra, adapter_mac_addr(padapter), ETH_ALEN);
|
|
|
|
pkt_info.is_packet_beacon = pkt_info.is_packet_match_bssid
|
|
&& (get_frame_sub_type(wlanhdr) == WIFI_BEACON);
|
|
|
|
if (psta && IsFrameTypeData(wlanhdr)) {
|
|
if (is_ra_bmc)
|
|
psta->curr_rx_rate_bmc = pattrib->data_rate;
|
|
else
|
|
psta->curr_rx_rate = pattrib->data_rate;
|
|
}
|
|
pkt_info.data_rate = pattrib->data_rate;
|
|
|
|
odm_phy_status_query(&pHalData->odmpriv, p_phy_info, pphy_status, &pkt_info);
|
|
|
|
/* If bw is initial value, get from phy status */
|
|
if (pattrib->bw == CHANNEL_WIDTH_MAX)
|
|
pattrib->bw = p_phy_info->band_width;
|
|
|
|
{
|
|
precvframe->u.hdr.psta = NULL;
|
|
if (padapter->registrypriv.mp_mode != 1) {
|
|
if ((!MLME_IS_MESH(padapter) && pkt_info.is_packet_match_bssid)
|
|
|| (MLME_IS_MESH(padapter) && psta)) {
|
|
if (psta) {
|
|
precvframe->u.hdr.psta = psta;
|
|
rx_process_phy_info(padapter, precvframe);
|
|
}
|
|
} else if (pkt_info.is_packet_to_self || pkt_info.is_packet_beacon) {
|
|
if (psta)
|
|
precvframe->u.hdr.psta = psta;
|
|
rx_process_phy_info(padapter, precvframe);
|
|
}
|
|
} else {
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
if (padapter->mppriv.brx_filter_beacon == _TRUE) {
|
|
if (pkt_info.is_packet_beacon) {
|
|
RTW_INFO("in MP Rx is_packet_beacon\n");
|
|
if (psta)
|
|
precvframe->u.hdr.psta = psta;
|
|
rx_process_phy_info(padapter, precvframe);
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
if (psta)
|
|
precvframe->u.hdr.psta = psta;
|
|
rx_process_phy_info(padapter, precvframe);
|
|
}
|
|
}
|
|
}
|
|
|
|
rtw_odm_parse_rx_phy_status_chinfo(precvframe, pphy_status);
|
|
}
|
|
/*
|
|
* Increase and check if the continual_no_rx_packet of this @param pmlmepriv is larger than MAX_CONTINUAL_NORXPACKET_COUNT
|
|
* @return _TRUE:
|
|
* @return _FALSE:
|
|
*/
|
|
int rtw_inc_and_chk_continual_no_rx_packet(struct sta_info *sta, int tid_index)
|
|
{
|
|
|
|
int ret = _FALSE;
|
|
int value = atomic_inc_return(&sta->continual_no_rx_packet[tid_index]);
|
|
|
|
if (value >= MAX_CONTINUAL_NORXPACKET_COUNT)
|
|
ret = _TRUE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Set the continual_no_rx_packet of this @param pmlmepriv to 0
|
|
*/
|
|
void rtw_reset_continual_no_rx_packet(struct sta_info *sta, int tid_index)
|
|
{
|
|
atomic_set(&sta->continual_no_rx_packet[tid_index], 0);
|
|
}
|
|
|
|
u8 adapter_allow_bmc_data_rx(_adapter *adapter)
|
|
{
|
|
if (check_fwstate(&adapter->mlmepriv, WIFI_MONITOR_STATE | WIFI_MP_STATE) == _TRUE)
|
|
return 1;
|
|
|
|
if (MLME_IS_AP(adapter))
|
|
return 0;
|
|
|
|
if (rtw_linked_check(adapter) == _FALSE)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
s32 pre_recv_entry(union recv_frame *precvframe, u8 *pphy_status)
|
|
{
|
|
s32 ret = _SUCCESS;
|
|
u8 *pbuf = precvframe->u.hdr.rx_data;
|
|
u8 *pda = get_ra(pbuf);
|
|
u8 ra_is_bmc = IS_MCAST(pda);
|
|
_adapter *primary_padapter = precvframe->u.hdr.adapter;
|
|
#ifdef CONFIG_CONCURRENT_MODE
|
|
_adapter *iface = NULL;
|
|
|
|
#ifdef CONFIG_MP_INCLUDED
|
|
if (rtw_mp_mode_check(primary_padapter))
|
|
goto bypass_concurrent_hdl;
|
|
#endif
|
|
|
|
if (ra_is_bmc == _FALSE) { /*unicast packets*/
|
|
iface = rtw_get_iface_by_macddr(primary_padapter , pda);
|
|
if (NULL == iface) {
|
|
#ifdef CONFIG_RTW_CFGVENDOR_RANDOM_MAC_OUI
|
|
if (_rtw_memcmp(pda, adapter_pno_mac_addr(primary_padapter),
|
|
ETH_ALEN) != _TRUE)
|
|
#endif
|
|
RTW_INFO("%s [WARN] Cannot find appropriate adapter - mac_addr : "MAC_FMT"\n", __func__, MAC_ARG(pda));
|
|
/*rtw_warn_on(1);*/
|
|
} else
|
|
precvframe->u.hdr.adapter = iface;
|
|
} else /* Handle BC/MC Packets */
|
|
rtw_mi_buddy_clone_bcmc_packet(primary_padapter, precvframe, pphy_status);
|
|
bypass_concurrent_hdl:
|
|
#endif /* CONFIG_CONCURRENT_MODE */
|
|
if (primary_padapter->registrypriv.mp_mode != 1) {
|
|
/* skip unnecessary bmc data frame for primary adapter */
|
|
if (ra_is_bmc == _TRUE && GetFrameType(pbuf) == WIFI_DATA_TYPE
|
|
&& !adapter_allow_bmc_data_rx(precvframe->u.hdr.adapter)
|
|
) {
|
|
rtw_free_recvframe(precvframe, &precvframe->u.hdr.adapter->recvpriv.free_recv_queue);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (pphy_status)
|
|
rx_query_phy_status(precvframe, pphy_status);
|
|
ret = rtw_recv_entry(precvframe);
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_RECV_THREAD_MODE
|
|
thread_return rtw_recv_thread(thread_context context)
|
|
{
|
|
_adapter *adapter = (_adapter *)context;
|
|
struct recv_priv *recvpriv = &adapter->recvpriv;
|
|
s32 err = _SUCCESS;
|
|
#ifdef RTW_RECV_THREAD_HIGH_PRIORITY
|
|
#ifdef PLATFORM_LINUX
|
|
struct sched_param param = { .sched_priority = 1 };
|
|
|
|
sched_setscheduler(current, SCHED_FIFO, ¶m);
|
|
#endif /* PLATFORM_LINUX */
|
|
#endif /*RTW_RECV_THREAD_HIGH_PRIORITY*/
|
|
thread_enter("RTW_RECV_THREAD");
|
|
|
|
RTW_INFO(FUNC_ADPT_FMT" enter\n", FUNC_ADPT_ARG(adapter));
|
|
|
|
do {
|
|
err = _rtw_down_sema(&recvpriv->recv_sema);
|
|
if (_FAIL == err) {
|
|
RTW_ERR(FUNC_ADPT_FMT" down recv_sema fail!\n", FUNC_ADPT_ARG(adapter));
|
|
goto exit;
|
|
}
|
|
|
|
if (RTW_CANNOT_RUN(adapter)) {
|
|
RTW_DBG(FUNC_ADPT_FMT "- bDriverStopped(%s) bSurpriseRemoved(%s)\n",
|
|
FUNC_ADPT_ARG(adapter),
|
|
rtw_is_drv_stopped(adapter) ? "True" : "False",
|
|
rtw_is_surprise_removed(adapter) ? "True" : "False");
|
|
goto exit;
|
|
}
|
|
|
|
err = rtw_hal_recv_hdl(adapter);
|
|
|
|
if (err == RTW_RFRAME_UNAVAIL
|
|
|| err == RTW_RFRAME_PKT_UNAVAIL
|
|
) {
|
|
msleep(1);
|
|
_rtw_up_sema(&recvpriv->recv_sema);
|
|
}
|
|
|
|
flush_signals_thread();
|
|
|
|
} while (err != _FAIL);
|
|
|
|
exit:
|
|
|
|
RTW_INFO(FUNC_ADPT_FMT " Exit\n", FUNC_ADPT_ARG(adapter));
|
|
|
|
rtw_thread_wait_stop();
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_RECV_THREAD_MODE */
|
|
|
|
#if DBG_RX_BH_TRACKING
|
|
void rx_bh_tk_set_stage(struct recv_priv *recv, u32 s)
|
|
{
|
|
recv->rx_bh_stage = s;
|
|
}
|
|
|
|
void rx_bh_tk_set_buf(struct recv_priv *recv, void *buf, void *data, u32 dlen)
|
|
{
|
|
if (recv->rx_bh_cbuf)
|
|
recv->rx_bh_lbuf = recv->rx_bh_cbuf;
|
|
recv->rx_bh_cbuf = buf;
|
|
if (buf) {
|
|
recv->rx_bh_cbuf_data = data;
|
|
recv->rx_bh_cbuf_dlen = dlen;
|
|
recv->rx_bh_buf_dq_cnt++;
|
|
} else {
|
|
recv->rx_bh_cbuf_data = NULL;
|
|
recv->rx_bh_cbuf_dlen = 0;
|
|
}
|
|
}
|
|
|
|
void rx_bh_tk_set_buf_pos(struct recv_priv *recv, void *pos)
|
|
{
|
|
if (recv->rx_bh_cbuf) {
|
|
recv->rx_bh_cbuf_pos = pos - recv->rx_bh_cbuf_data;
|
|
} else {
|
|
rtw_warn_on(1);
|
|
recv->rx_bh_cbuf_pos = 0;
|
|
}
|
|
}
|
|
|
|
void rx_bh_tk_set_frame(struct recv_priv *recv, void *frame)
|
|
{
|
|
recv->rx_bh_cframe = frame;
|
|
}
|
|
|
|
void dump_rx_bh_tk(void *sel, struct recv_priv *recv)
|
|
{
|
|
RTW_PRINT_SEL(sel, "[RXBHTK]s:%u, buf_dqc:%u, lbuf:%p, cbuf:%p, dlen:%u, pos:%u, cframe:%p\n"
|
|
, recv->rx_bh_stage
|
|
, recv->rx_bh_buf_dq_cnt
|
|
, recv->rx_bh_lbuf
|
|
, recv->rx_bh_cbuf
|
|
, recv->rx_bh_cbuf_dlen
|
|
, recv->rx_bh_cbuf_pos
|
|
, recv->rx_bh_cframe
|
|
);
|
|
}
|
|
#endif /* DBG_RX_BH_TRACKING */
|
|
|