10234 lines
282 KiB
C
Executable File
10234 lines
282 KiB
C
Executable File
/*
|
|
* RX handle routines
|
|
*
|
|
* $Id: 8192cd_rx.c,v 1.27.2.31 2010/12/31 08:37:43 davidhsu Exp $
|
|
*
|
|
* Copyright (c) 2009 Realtek Semiconductor Corp.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#define _8192CD_RX_C_
|
|
|
|
#ifdef __KERNEL__
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <net/ip.h>
|
|
#include <linux/ipv6.h>
|
|
#include <linux/icmpv6.h>
|
|
|
|
|
|
#elif defined(__ECOS)
|
|
#include <cyg/io/eth/rltk/819x/wrapper/sys_support.h>
|
|
#include <cyg/io/eth/rltk/819x/wrapper/skbuff.h>
|
|
#include <cyg/io/eth/rltk/819x/wrapper/timer.h>
|
|
#include <cyg/io/eth/rltk/819x/wrapper/wrapper.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/ip6.h>
|
|
#endif
|
|
|
|
#include "./8192cd_cfg.h"
|
|
#include "./8192cd.h"
|
|
#include "./8192cd_hw.h"
|
|
#include "./8192cd_headers.h"
|
|
#include "./8192cd_rx.h"
|
|
#include "./8192cd_debug.h"
|
|
|
|
#ifdef __LINUX_2_6__
|
|
#ifdef CONFIG_RTL8672
|
|
#include "./romeperf.h"
|
|
#else
|
|
#if !defined(NOT_RTK_BSP)
|
|
#ifdef CONFIG_OPENWRT_SDK
|
|
#include "./rtl_types.h" //mark_wrt
|
|
#else
|
|
#include <net/rtl/rtl_types.h>
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _BROADLIGHT_FASTPATH_
|
|
extern int (*send_packet_to_upper_layer)(struct sk_buff *skb);
|
|
#endif
|
|
|
|
#ifdef PREVENT_ARP_SPOOFING
|
|
#include <linux/inetdevice.h>
|
|
#include <linux/if_arp.h>
|
|
static int check_arp_spoofing(struct rtl8192cd_priv *priv, struct sk_buff *pskb);
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
#include "../mesh_ext/mesh_route.h"
|
|
#endif
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
#include "wapiCrypto.h"
|
|
#endif
|
|
#if defined(CONFIG_RTL_FASTBRIDGE)
|
|
#include <net/rtl/features/fast_bridge.h>
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL867X_VLAN_MAPPING
|
|
#include "../../re_vlan.h"
|
|
#endif
|
|
#ifdef CONFIG_RTL_VLAN_8021Q
|
|
#include <linux/if_vlan.h>
|
|
#endif
|
|
|
|
#ifdef PERF_DUMP
|
|
#include "romeperf.h"
|
|
#endif
|
|
|
|
#ifdef __ECOS
|
|
#define uint32 unsigned int
|
|
#define uint16 unsigned short
|
|
#define int16 short
|
|
#endif
|
|
|
|
#ifdef BR_SHORTCUT
|
|
#ifdef WDS
|
|
__DRAM_IN_865X unsigned char cached_wds_mac[MACADDRLEN];
|
|
__DRAM_IN_865X struct net_device *cached_wds_dev = NULL;
|
|
#endif
|
|
#ifdef CONFIG_RTK_MESH
|
|
__DRAM_IN_865X unsigned char cached_mesh_mac[2][MACADDRLEN];
|
|
__DRAM_IN_865X struct net_device *cached_mesh_dev[2] = {NULL,NULL};
|
|
#endif
|
|
#ifdef CLIENT_MODE
|
|
__DRAM_IN_865X unsigned char cached_sta_mac[MAX_REPEATER_SC_NUM][MACADDRLEN];
|
|
__DRAM_IN_865X struct net_device *cached_sta_dev[MAX_REPEATER_SC_NUM] = {NULL,NULL};
|
|
#endif
|
|
|
|
#ifdef RTL_CACHED_BR_STA
|
|
//__DRAM_IN_865X unsigned char cached_br_sta_mac[MACADDRLEN];
|
|
//__DRAM_IN_865X struct net_device *cached_br_sta_dev = NULL;
|
|
__DRAM_IN_865X struct brsc_cache_t brsc_cache_arr[MAX_BRSC_NUM];
|
|
#endif
|
|
#endif // BR_SHORTCUT
|
|
|
|
//for 8671 IGMP snooping
|
|
#ifdef CONFIG_RTL8672
|
|
#define wlan_igmp_tag 0x1f
|
|
extern int enable_IGMP_SNP;
|
|
#ifdef CONFIG_EXT_SWITCH
|
|
extern void check_IGMP_snoop_rx(struct sk_buff *skb, int tag);
|
|
#endif
|
|
#endif
|
|
|
|
#if 0//def CONFIG_RTL_STP
|
|
unsigned char STPmac[6] = { 1, 0x80, 0xc2, 0,0,0};
|
|
static struct net_device* wlan_pseudo_dev;
|
|
#define WLAN_INTERFACE_NAME "wlan0"
|
|
#endif
|
|
|
|
#if defined(__LINUX_2_6__) && defined(CONFIG_RTK_VLAN_SUPPORT)
|
|
extern int rtk_vlan_support_enable;
|
|
#endif
|
|
#ifdef CONFIG_RTL_VLAN_8021Q
|
|
extern int linux_vlan_enable;
|
|
extern linux_vlan_ctl_t *vlan_ctl_p;
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL_EAP_RELAY) || defined(CONFIG_RTK_INBAND_HOST_HACK)
|
|
extern unsigned char inband_Hostmac[]; //it's from br.c
|
|
#endif
|
|
|
|
#if defined(__ECOS)
|
|
extern unsigned char freebsd_Hostmac[];
|
|
#endif
|
|
|
|
/* ======================== RX procedure declarations ======================== */
|
|
static void rtl8192cd_rx_ctrlframe(struct rtl8192cd_priv *priv,
|
|
struct list_head *list, struct rx_frinfo *inputPfrinfo);
|
|
#ifndef CONFIG_RTK_MESH
|
|
static
|
|
#endif
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
void rtl8192cd_rx_dataframe(struct rtl8192cd_priv *priv,
|
|
struct list_head *list, struct rx_frinfo *inputPfrinfo);
|
|
|
|
|
|
static int auth_filter(struct rtl8192cd_priv *priv, struct stat_info *pstat,
|
|
struct rx_frinfo *pfrinfo);
|
|
static void ctrl_handler(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo);
|
|
|
|
static void process_amsdu(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct rx_frinfo *pfrinfo);
|
|
|
|
|
|
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
|
|
static unsigned char QueryRxPwrPercentage(signed char AntPower)
|
|
{
|
|
if ((AntPower <= -100) || (AntPower >= 20))
|
|
return 0;
|
|
else if (AntPower >= 0)
|
|
return 100;
|
|
else
|
|
return (100+AntPower);
|
|
}
|
|
#endif
|
|
|
|
int SignalScaleMapping(int CurrSig)
|
|
{
|
|
int RetSig;
|
|
|
|
// Step 1. Scale mapping.
|
|
if(CurrSig >= 61 && CurrSig <= 100)
|
|
{
|
|
RetSig = 90 + ((CurrSig - 60) / 4);
|
|
}
|
|
else if(CurrSig >= 41 && CurrSig <= 60)
|
|
{
|
|
RetSig = 78 + ((CurrSig - 40) / 2);
|
|
}
|
|
else if(CurrSig >= 31 && CurrSig <= 40)
|
|
{
|
|
RetSig = 66 + (CurrSig - 30);
|
|
}
|
|
else if(CurrSig >= 21 && CurrSig <= 30)
|
|
{
|
|
RetSig = 54 + (CurrSig - 20);
|
|
}
|
|
else if(CurrSig >= 5 && CurrSig <= 20)
|
|
{
|
|
RetSig = 42 + (((CurrSig - 5) * 2) / 3);
|
|
}
|
|
else if(CurrSig == 4)
|
|
{
|
|
RetSig = 36;
|
|
}
|
|
else if(CurrSig == 3)
|
|
{
|
|
RetSig = 27;
|
|
}
|
|
else if(CurrSig == 2)
|
|
{
|
|
RetSig = 18;
|
|
}
|
|
else if(CurrSig == 1)
|
|
{
|
|
RetSig = 9;
|
|
}
|
|
else
|
|
{
|
|
RetSig = CurrSig;
|
|
}
|
|
|
|
return RetSig;
|
|
}
|
|
|
|
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
|
|
static unsigned char EVMdbToPercentage(signed char Value)
|
|
{
|
|
signed char ret_val;
|
|
|
|
ret_val = Value;
|
|
|
|
if (ret_val >= 0)
|
|
ret_val = 0;
|
|
if (ret_val <= -33)
|
|
ret_val = -33;
|
|
ret_val = 0 - ret_val;
|
|
ret_val*=3;
|
|
if (ret_val == 99)
|
|
ret_val = 100;
|
|
return(ret_val);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef MP_SWITCH_LNA
|
|
|
|
#define ss_threshold_H 0x28
|
|
#define ss_threshold_L 0x17
|
|
|
|
static __inline__ void dynamic_switch_lna(struct rtl8192cd_priv *priv)
|
|
{
|
|
|
|
unsigned int tmp_b30 = PHY_QueryBBReg(priv, 0xb30, bMaskDWord);
|
|
|
|
|
|
unsigned int tmp_dd0 = PHY_QueryBBReg(priv, 0xdd0, bMaskDWord);
|
|
unsigned int tmp_dd0_a = (tmp_dd0 & 0x3f);
|
|
unsigned int tmp_dd0_b = ((tmp_dd0 & 0x3f00) >> 8);
|
|
|
|
//======= PATH A ============
|
|
|
|
if((tmp_dd0_a >= ss_threshold_H) && (!(tmp_b30 & BIT(21))))
|
|
{
|
|
if(priv->pshare->rx_packet_ss_a >= 10)
|
|
priv->pshare->rx_packet_ss_a = 0;
|
|
|
|
priv->pshare->rx_packet_ss_a = (priv->pshare->rx_packet_ss_a+1);
|
|
|
|
if(priv->pshare->rx_packet_ss_a > 3)
|
|
priv->pshare->rx_packet_ss_a = 3;
|
|
|
|
if( priv->pshare->rx_packet_ss_a == 3)
|
|
{
|
|
tmp_b30 = (tmp_b30 | BIT(21)) ;
|
|
PHY_SetBBReg(priv, 0xb30, bMaskDWord, tmp_b30 );
|
|
printk("!!!! UP 3 PACKETS !!!! PATH A dd0[0x%x] > 0x%x, Change b30 = 0x%x!!!!\n\n",
|
|
tmp_dd0_a , ss_threshold_H, tmp_b30 );
|
|
}
|
|
|
|
}
|
|
else if((tmp_dd0_a <= ss_threshold_L) && (tmp_b30 & BIT(21)))
|
|
{
|
|
if(priv->pshare->rx_packet_ss_a < 10)
|
|
priv->pshare->rx_packet_ss_a = 10;
|
|
|
|
priv->pshare->rx_packet_ss_a = (priv->pshare->rx_packet_ss_a+1) ;
|
|
|
|
if(priv->pshare->rx_packet_ss_a > 13)
|
|
priv->pshare->rx_packet_ss_a = 13;
|
|
|
|
if(priv->pshare->rx_packet_ss_a == 13)
|
|
{
|
|
tmp_b30 = (tmp_b30 & ~(BIT(21))) ;
|
|
PHY_SetBBReg(priv, 0xb30, bMaskDWord, tmp_b30 );
|
|
printk("!!!! UP 3 PACKETS !!!! PATH A dd0[0x%x] < 0x%x, Change b30 = 0x%x!!!!\n\n",
|
|
tmp_dd0_a , ss_threshold_L, tmp_b30 );
|
|
|
|
}
|
|
}
|
|
|
|
//======= PATH B ============
|
|
|
|
if((tmp_dd0_b >= ss_threshold_H) && (!(tmp_b30 & BIT(23))))
|
|
{
|
|
if(priv->pshare->rx_packet_ss_b >= 10)
|
|
priv->pshare->rx_packet_ss_b = 0;
|
|
|
|
priv->pshare->rx_packet_ss_b = (priv->pshare->rx_packet_ss_b+1);
|
|
|
|
if(priv->pshare->rx_packet_ss_b > 3)
|
|
priv->pshare->rx_packet_ss_b = 3;
|
|
|
|
if( priv->pshare->rx_packet_ss_b == 3)
|
|
{
|
|
tmp_b30 = (tmp_b30 | BIT(23)) ;
|
|
PHY_SetBBReg(priv, 0xb30, bMaskDWord, tmp_b30 );
|
|
printk("!!!! UP 3 PACKETS !!!! PATH B dd0[0x%x] > 0x%x, Change b30 = 0x%x!!!!\n\n",
|
|
tmp_dd0_b , ss_threshold_H, tmp_b30 );
|
|
}
|
|
|
|
}
|
|
else if((tmp_dd0_b <= ss_threshold_L) && (tmp_b30 & BIT(23)))
|
|
{
|
|
if(priv->pshare->rx_packet_ss_b < 10)
|
|
priv->pshare->rx_packet_ss_b = 10;
|
|
|
|
priv->pshare->rx_packet_ss_b = (priv->pshare->rx_packet_ss_b+1) ;
|
|
|
|
if(priv->pshare->rx_packet_ss_b > 13)
|
|
priv->pshare->rx_packet_ss_b = 13;
|
|
|
|
if(priv->pshare->rx_packet_ss_b == 13)
|
|
{
|
|
tmp_b30 = (tmp_b30 & ~(BIT(23))) ;
|
|
PHY_SetBBReg(priv, 0xb30, bMaskDWord, tmp_b30 );
|
|
printk("!!!! UP 3 PACKETS !!!! PATH B dd0[0x%x] < 0x%x, Change b30 = 0x%x!!!!\n\n",
|
|
tmp_dd0_b , ss_threshold_L, tmp_b30 );
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef USE_OUT_SRC
|
|
/*static*/ __inline__ void translate_rssi_sq_outsrc(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo, char rate)
|
|
{
|
|
PODM_PHY_INFO_T pPhyInfo= (PODM_PHY_INFO_T) &(pfrinfo->rssi);
|
|
ODM_PACKET_INFO_T pktinfo;
|
|
#if defined(CONFIG_PCI_HCI)
|
|
unsigned char *frame = get_pframe(pfrinfo) + (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
unsigned char *frame = get_pframe(pfrinfo);
|
|
#endif
|
|
struct stat_info *pstat = get_stainfo(priv, GetAddr2Ptr(frame));
|
|
|
|
#ifdef HW_FILL_MACID //eric-8814
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
pktinfo.DataRate = rate;
|
|
pktinfo.bPacketToSelf = 1;
|
|
pktinfo.bPacketMatchBSSID =1;
|
|
pktinfo.StationID = (pstat ? pstat->aid : 0);
|
|
|
|
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL_8881A)
|
|
if ((GET_CHIP_VER(priv) == VERSION_8812E) || (GET_CHIP_VER(priv) == VERSION_8881A)) {
|
|
unsigned short *t = (unsigned short *)(get_pframe(pfrinfo)+2);
|
|
*t = le16_to_cpu(*t);
|
|
}
|
|
#endif
|
|
|
|
ODM_PhyStatusQuery(ODMPTR, pPhyInfo, (u1Byte *)pfrinfo->driver_info, &pktinfo);
|
|
|
|
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL_8881A) || defined(CONFIG_WLAN_HAL_8814AE)
|
|
if ((GET_CHIP_VER(priv) == VERSION_8812E && !IS_C_CUT_8812(priv))
|
|
|| (GET_CHIP_VER(priv) == VERSION_8881A)
|
|
|| (GET_CHIP_VER(priv) == VERSION_8814A)
|
|
) {
|
|
PPHY_STATUS_RPT_8812_T pPhyStaRpt = (PPHY_STATUS_RPT_8812_T)pfrinfo->driver_info;
|
|
pfrinfo->rx_bw = pPhyStaRpt->r_RFMOD;
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_WLAN_HAL_8192EE
|
|
if (GET_CHIP_VER(priv) == VERSION_8192E) {
|
|
PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pfrinfo->driver_info;
|
|
pfrinfo->rx_bw = (pPhyStaRpt->rxsc == 3) ? 1 : 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
}
|
|
#ifdef CONFIG_PCI_HCI
|
|
static
|
|
#endif
|
|
__inline__ void translate_CRC32_outsrc(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo, BOOLEAN CRC32,u2Byte PKT_LEN)
|
|
{
|
|
//unsigned char *frame = get_pframe(pfrinfo) + (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
//struct stat_info *pstat = get_stainfo(priv, GetAddr2Ptr(frame));
|
|
//u1Byte StationID;
|
|
|
|
//StationID = (pstat ? pstat->aid : 0); //MAC ID
|
|
|
|
//if(StationID!=0)
|
|
#ifdef CONFIG_HW_ANTENNA_DIVERSITY
|
|
u4Byte weighting;
|
|
|
|
if(PKT_LEN>1538 || PKT_LEN<30)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if(CRC32==CRC32_FAIL)
|
|
{
|
|
weighting=0;
|
|
}
|
|
else if(CRC32==CRC32_OK)
|
|
{
|
|
if(PKT_LEN>1000)
|
|
weighting=10;
|
|
else if(PKT_LEN>500)
|
|
weighting=5;
|
|
else if(PKT_LEN>100)
|
|
weighting=3;
|
|
else
|
|
weighting=1;
|
|
}
|
|
}
|
|
|
|
odm_AntselStatistics(ODMPTR, 1, 1 , weighting , CRC32_METHOD);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
|
|
/*static*/ __inline__ void translate_rssi_sq(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
typedef signed char s1Byte;
|
|
typedef unsigned char u1Byte;
|
|
typedef int s4Byte;
|
|
typedef unsigned int u4Byte;
|
|
|
|
PHY_STS_OFDM_8192CD_T *pOfdm_buf;
|
|
PHY_STS_CCK_8192CD_T *pCck_buf;
|
|
u1Byte *prxpkt;
|
|
u1Byte i, Max_spatial_stream, tmp_rxsnr, tmp_rxevm; //, tmp_rxrssi;
|
|
s1Byte rx_pwr[4], rx_pwr_all=0;
|
|
s1Byte rx_snrX, rx_evmX; //, rx_rssiX;
|
|
u1Byte EVM, PWDB_ALL;
|
|
u4Byte RSSI;
|
|
u1Byte isCCKrate=0;
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT)
|
|
u1Byte report;
|
|
#endif
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
unsigned int ofdm_max_rssi=0, ofdm_min_rssi=0xff;
|
|
#endif
|
|
|
|
/* 2007/07/04 MH For OFDM RSSI. For high power or not. */
|
|
//static u1Byte check_reg824 = 0;
|
|
//static u4Byte reg824_bit9 = 0;
|
|
|
|
isCCKrate = is_CCK_rate(pfrinfo->rx_rate);
|
|
|
|
#ifdef CONFIG_PCI_HCI
|
|
/*2007.08.30 requested by SD3 Jerry */
|
|
if (priv->pshare->phw->check_reg824 == 0) {
|
|
priv->pshare->phw->reg824_bit9 = PHY_QueryBBReg(priv, rFPGA0_XA_HSSIParameter2, 0x200);
|
|
priv->pshare->phw->check_reg824 = 1;
|
|
}
|
|
#endif
|
|
|
|
prxpkt = (u1Byte *)pfrinfo->driver_info;
|
|
|
|
/* Initial the cck and ofdm buffer pointer */
|
|
pCck_buf = (PHY_STS_CCK_8192CD_T *)prxpkt;
|
|
pOfdm_buf = (PHY_STS_OFDM_8192CD_T *)prxpkt;
|
|
|
|
memset(&pfrinfo->rf_info, 0, sizeof(struct rf_misc_info));
|
|
pfrinfo->rf_info.mimosq[0] = -1;
|
|
pfrinfo->rf_info.mimosq[1] = -1;
|
|
|
|
if (isCCKrate) {
|
|
/*
|
|
//
|
|
// (1)Hardware does not provide RSSI for CCK
|
|
//
|
|
if ((get_rf_mimo_mode(priv) == MIMO_2T4R) && (priv->pshare->rf_ft_var.cck_sel_ver == 2)) {
|
|
for (i=RF92CD_PATH_A; i<RF92CD_PATH_MAX; i++) {
|
|
tmp_rxrssi = pCck_buf->adc_pwdb_X[i];
|
|
rx_rssiX = (s1Byte)(tmp_rxrssi);
|
|
rx_rssiX /= 2;
|
|
pfrinfo->cck_mimorssi[i] = rx_rssiX;
|
|
}
|
|
}
|
|
*/
|
|
//
|
|
// (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive)
|
|
//
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT)
|
|
if (
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
(GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)
|
|
#endif
|
|
#ifdef CONFIG_RTL_92D_SUPPORT
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
||
|
|
#endif
|
|
(GET_CHIP_VER(priv) == VERSION_8192D)
|
|
#endif
|
|
) {
|
|
if (!priv->pshare->phw->reg824_bit9) {
|
|
report = pCck_buf->cck_agc_rpt & 0xc0;
|
|
report = report>>6;
|
|
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) {
|
|
switch (report) {
|
|
case 0x3:
|
|
rx_pwr_all = -46 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x2:
|
|
rx_pwr_all = -26 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x1:
|
|
rx_pwr_all = -12 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x0:
|
|
rx_pwr_all = 16 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
switch (report) {
|
|
//Fixed by Wish and BB Cherry 2013.12.04
|
|
case 0x3:
|
|
rx_pwr_all = -46 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x2:
|
|
rx_pwr_all = -26 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x1:
|
|
rx_pwr_all = -12 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
case 0x0:
|
|
rx_pwr_all = 16 - (pCck_buf->cck_agc_rpt & 0x3e);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
report = pCck_buf->cck_agc_rpt & 0x60;
|
|
report = report>>5;
|
|
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) {
|
|
switch (report) {
|
|
case 0x3:
|
|
rx_pwr_all = -46 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1) ;
|
|
break;
|
|
case 0x2:
|
|
rx_pwr_all = -26 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
|
|
break;
|
|
case 0x1:
|
|
rx_pwr_all = -12 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1) ;
|
|
break;
|
|
case 0x0:
|
|
rx_pwr_all = 16 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1) ;
|
|
break;
|
|
}
|
|
} else
|
|
#endif
|
|
{
|
|
switch (report) {
|
|
//Fixed by Wish and BB Cherry 2013.12.04
|
|
case 0x3:
|
|
rx_pwr_all = -46 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
|
|
break;
|
|
case 0x2:
|
|
rx_pwr_all = -26 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
|
|
break;
|
|
case 0x1:
|
|
rx_pwr_all = -12 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
|
|
break;
|
|
case 0x0:
|
|
rx_pwr_all = 16 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
PWDB_ALL = QueryRxPwrPercentage(rx_pwr_all);
|
|
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
if ((GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)) {
|
|
#ifdef HIGH_POWER_EXT_LNA
|
|
if (priv->pshare->rf_ft_var.use_ext_lna) {
|
|
if (!(pCck_buf->cck_agc_rpt>>7))
|
|
PWDB_ALL = (PWDB_ALL>94)?100:(PWDB_ALL + 6);
|
|
else
|
|
PWDB_ALL = (PWDB_ALL<16)?0:(PWDB_ALL -16);
|
|
|
|
/* CCK Modification */
|
|
if (PWDB_ALL > 25 && PWDB_ALL <= 60)
|
|
PWDB_ALL += 6;
|
|
/*
|
|
else if (PWDB_ALL <= 25)
|
|
PWDB_ALL += 8;
|
|
*/
|
|
} else
|
|
#endif
|
|
{
|
|
if (PWDB_ALL > 99)
|
|
PWDB_ALL -= 8;
|
|
else if (PWDB_ALL > 50 && PWDB_ALL <= 68)
|
|
PWDB_ALL += 4;
|
|
}
|
|
|
|
pfrinfo->rssi = PWDB_ALL;
|
|
#ifdef HIGH_POWER_EXT_LNA
|
|
if (priv->pshare->rf_ft_var.use_ext_lna)
|
|
pfrinfo->rssi+=10;
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
pfrinfo->rssi = PWDB_ALL;
|
|
pfrinfo->rssi+=3;
|
|
}
|
|
|
|
if (pfrinfo->rssi > 100)
|
|
pfrinfo->rssi = 100;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
unsigned int LNA_idx = ((pCck_buf->cck_agc_rpt & 0xE0) >>5);
|
|
unsigned int VGA_idx = (pCck_buf->cck_agc_rpt & 0x1F);
|
|
switch(LNA_idx) {
|
|
case 7:
|
|
if(VGA_idx <= 27)
|
|
rx_pwr_all = -100 + 2*(27-VGA_idx); //VGA_idx = 27~2
|
|
else
|
|
rx_pwr_all = -100;
|
|
break;
|
|
case 6:
|
|
rx_pwr_all = -48 + 2*(2-VGA_idx); //VGA_idx = 2~0
|
|
break;
|
|
case 5:
|
|
rx_pwr_all = -42 + 2*(7-VGA_idx); //VGA_idx = 7~5
|
|
break;
|
|
case 4:
|
|
rx_pwr_all = -36 + 2*(7-VGA_idx); //VGA_idx = 7~4
|
|
break;
|
|
case 3:
|
|
//rx_pwr_all = -28 + 2*(7-VGA_idx); //VGA_idx = 7~0
|
|
rx_pwr_all = -24 + 2*(7-VGA_idx); //VGA_idx = 7~0
|
|
break;
|
|
case 2:
|
|
if(priv->pshare->phw->reg824_bit9)
|
|
rx_pwr_all = -12 + 2*(5-VGA_idx); //VGA_idx = 5~0
|
|
else
|
|
rx_pwr_all = -6+ 2*(5-VGA_idx);
|
|
break;
|
|
case 1:
|
|
rx_pwr_all = 8-2*VGA_idx;
|
|
break;
|
|
case 0:
|
|
rx_pwr_all = 14-2*VGA_idx;
|
|
break;
|
|
default:
|
|
printk("%s %d, CCK Exception default\n", __FUNCTION__, __LINE__);
|
|
break;
|
|
}
|
|
rx_pwr_all += 6;
|
|
PWDB_ALL = QueryRxPwrPercentage(rx_pwr_all);
|
|
|
|
if(!priv->pshare->phw->reg824_bit9) {
|
|
if(PWDB_ALL >= 80)
|
|
PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80;
|
|
else if((PWDB_ALL <= 78) && (PWDB_ALL >= 20))
|
|
PWDB_ALL += 3;
|
|
if(PWDB_ALL>100)
|
|
PWDB_ALL = 100;
|
|
}
|
|
|
|
pfrinfo->rssi = PWDB_ALL;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// (3) Get Signal Quality (EVM)
|
|
//
|
|
// if(bPacketMatchBSSID)
|
|
{
|
|
u1Byte SQ;
|
|
|
|
if (pfrinfo->rssi > 40) {
|
|
SQ = 100;
|
|
} else {
|
|
SQ = pCck_buf->SQ_rpt;
|
|
|
|
if (pCck_buf->SQ_rpt > 64)
|
|
SQ = 0;
|
|
else if (pCck_buf->SQ_rpt < 20)
|
|
SQ = 100;
|
|
else
|
|
SQ = ((64-SQ) * 100) / 44;
|
|
}
|
|
pfrinfo->sq = SQ;
|
|
pfrinfo->rf_info.mimosq[0] = SQ;
|
|
}
|
|
} else {
|
|
//
|
|
// (1)Get RSSI for HT rate
|
|
//
|
|
for (i=RF92CD_PATH_A; i<RF92CD_PATH_MAX; i++) {
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
if (
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
(GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
||
|
|
#endif
|
|
(GET_CHIP_VER(priv) == VERSION_8188E)
|
|
#endif
|
|
)
|
|
rx_pwr[i] = ((pOfdm_buf->trsw_gain_X[i]&0x3F)*2) - 110;
|
|
else
|
|
#endif
|
|
rx_pwr[i] = ((pOfdm_buf->trsw_gain_X[i]&0x3F)*2) - 106;
|
|
|
|
//Get Rx snr value in DB
|
|
if (priv->pshare->rf_ft_var.rssi_dump) {
|
|
tmp_rxsnr = pOfdm_buf->rxsnr_X[i];
|
|
rx_snrX = (s1Byte)(tmp_rxsnr);
|
|
rx_snrX >>= 1;
|
|
pfrinfo->rf_info.RxSNRdB[i] = (s4Byte)rx_snrX;
|
|
}
|
|
|
|
/* Translate DBM to percentage. */
|
|
RSSI = QueryRxPwrPercentage(rx_pwr[i]);
|
|
//total_rssi += RSSI;
|
|
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
if ((
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
(GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
||
|
|
#endif
|
|
(GET_CHIP_VER(priv) == VERSION_8188E)
|
|
#endif
|
|
)
|
|
#ifdef HIGH_POWER_EXT_LNA
|
|
&& (priv->pshare->rf_ft_var.use_ext_lna)
|
|
#endif
|
|
) {
|
|
if ((pOfdm_buf->trsw_gain_X[i]>>7) == 1)
|
|
RSSI = (RSSI>94)?100:(RSSI + 6);
|
|
else
|
|
RSSI = (RSSI<16)?0:(RSSI -16);
|
|
|
|
if (RSSI <= 34 && RSSI >= 4)
|
|
RSSI -= 4;
|
|
}
|
|
#endif
|
|
|
|
/* Record Signal Strength for next packet */
|
|
//if(bPacketMatchBSSID)
|
|
{
|
|
pfrinfo->rf_info.mimorssi[i] = (u1Byte)RSSI;
|
|
}
|
|
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
if (
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
(GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
||
|
|
#endif
|
|
(GET_CHIP_VER(priv) == VERSION_8188E)
|
|
#endif
|
|
) {
|
|
if (RSSI > ofdm_max_rssi)
|
|
ofdm_max_rssi = RSSI;
|
|
if (RSSI < ofdm_min_rssi)
|
|
ofdm_min_rssi = RSSI;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive)
|
|
//
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
if (
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
(GET_CHIP_VER(priv) == VERSION_8192C)||(GET_CHIP_VER(priv) == VERSION_8188C)
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
#ifdef CONFIG_RTL_92C_SUPPORT
|
|
||
|
|
#endif
|
|
(GET_CHIP_VER(priv) == VERSION_8188E)
|
|
#endif
|
|
) {
|
|
if ((ofdm_max_rssi - ofdm_min_rssi) < 3)
|
|
PWDB_ALL = ofdm_max_rssi;
|
|
else if ((ofdm_max_rssi - ofdm_min_rssi) < 6)
|
|
PWDB_ALL = ofdm_max_rssi - 1;
|
|
else if ((ofdm_max_rssi - ofdm_min_rssi) < 10)
|
|
PWDB_ALL = ofdm_max_rssi - 2;
|
|
else
|
|
PWDB_ALL = ofdm_max_rssi - 3;
|
|
} else
|
|
#endif
|
|
{
|
|
rx_pwr_all = (((pOfdm_buf->pwdb_all ) >> 1 )& 0x7f) -106;
|
|
PWDB_ALL = QueryRxPwrPercentage(rx_pwr_all);
|
|
}
|
|
|
|
pfrinfo->rssi = PWDB_ALL;
|
|
|
|
//
|
|
// (3)EVM of HT rate
|
|
//
|
|
//eric_8814 ?? 3 spatial stream ??
|
|
if ((pfrinfo->rx_rate >= _MCS8_RATE_) && (pfrinfo->rx_rate <= _MCS15_RATE_))
|
|
Max_spatial_stream = 2; //both spatial stream make sense
|
|
else
|
|
Max_spatial_stream = 1; //only spatial stream 1 makes sense
|
|
|
|
for (i=0; i<Max_spatial_stream; i++) {
|
|
tmp_rxevm = pOfdm_buf->rxevm_X[i];
|
|
rx_evmX = (s1Byte)(tmp_rxevm);
|
|
|
|
// Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment
|
|
// fill most significant bit to "zero" when doing shifting operation which may change a negative
|
|
// value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore.
|
|
rx_evmX /= 2; //dbm
|
|
|
|
EVM = EVMdbToPercentage(rx_evmX);
|
|
|
|
//if(bPacketMatchBSSID)
|
|
{
|
|
if (i==0) // Fill value in RFD, Get the first spatial stream only
|
|
{
|
|
pfrinfo->sq = (u1Byte)(EVM & 0xff);
|
|
}
|
|
pfrinfo->rf_info.mimosq[i] = (u1Byte)(EVM & 0xff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0//def CONFIG_RTL_STP
|
|
int rtl865x_wlanIF_Init(struct net_device *dev)
|
|
{
|
|
if (dev == NULL)
|
|
return FALSE;
|
|
else
|
|
{
|
|
wlan_pseudo_dev = dev;
|
|
printk("init wlan pseudo dev =====> %s\n", wlan_pseudo_dev->name);
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef SUPPORT_RX_UNI2MCAST
|
|
static unsigned int check_mcastL2L3Diff(struct sk_buff *skb)
|
|
{
|
|
unsigned int DaIpAddr;
|
|
struct iphdr* iph = SKB_IP_HEADER(skb);
|
|
|
|
#ifdef _LITTLE_ENDIAN_
|
|
DaIpAddr = ntohl(iph->daddr);
|
|
#else
|
|
DaIpAddr = iph->daddr;
|
|
#endif
|
|
//printk("ip:%d, %d ,%d ,%d\n",(DaIpAddr>>24) ,(DaIpAddr<<8)>>24,(DaIpAddr<<16)>>24,(DaIpAddr<<24)>>24);
|
|
|
|
if (((DaIpAddr & 0xFF000000) >= 0xE0000000) && ((DaIpAddr & 0xFF000000) <= 0xEF000000)) {
|
|
if (!IP_MCAST_MAC(SKB_MAC_HEADER(skb)))
|
|
return DaIpAddr;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void ConvertMCastIPtoMMac(unsigned int group, unsigned char *gmac)
|
|
{
|
|
unsigned int u32tmp, tmp;
|
|
static int i;
|
|
|
|
u32tmp = group & 0x007FFFFF;
|
|
gmac[0] = 0x01;
|
|
gmac[1] = 0x00;
|
|
gmac[2] = 0x5e;
|
|
|
|
for (i=5; i>=3; i--) {
|
|
tmp = u32tmp & 0xFF;
|
|
gmac[i] = tmp;
|
|
u32tmp >>= 8;
|
|
}
|
|
}
|
|
|
|
|
|
static void CheckUDPandU2M(struct sk_buff *pskb)
|
|
{
|
|
int MultiIP;
|
|
|
|
MultiIP = check_mcastL2L3Diff(pskb);
|
|
if (MultiIP) {
|
|
unsigned char mactmp[6];
|
|
ConvertMCastIPtoMMac(MultiIP, mactmp);
|
|
//printk("%02x%02x%02x:%02x%02x%02x\n", mactmp[0],mactmp[1],mactmp[2],
|
|
// mactmp[3],mactmp[4],mactmp[5]);
|
|
memcpy(SKB_MAC_HEADER(pskb), mactmp, 6);
|
|
#if defined(__LINUX_2_6__)
|
|
/*added by qinjunjie,warning:should not remove next line*/
|
|
pskb->pkt_type = PACKET_MULTICAST;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void CheckV6UDPandU2M(struct sk_buff *pskb)
|
|
{
|
|
#ifdef __ECOS
|
|
struct ip6_hdr *iph = (struct ip6_hdr *)(pskb->data + ETH_HLEN);
|
|
unsigned char *DDA=pskb->data;
|
|
#else
|
|
struct ipv6hdr *iph;
|
|
unsigned char *DDA;
|
|
|
|
iph = (struct ipv6hdr *)SKB_IP_HEADER(pskb);
|
|
DDA = (unsigned char *)SKB_MAC_HEADER(pskb);
|
|
#endif
|
|
|
|
/*ip(v6) format is multicast ip*/
|
|
#ifdef __ECOS
|
|
if (iph->ip6_dst.s6_addr[0] == 0xff){
|
|
#else
|
|
if (iph->daddr.s6_addr[0] == 0xff){
|
|
#endif
|
|
|
|
/*mac is not ipv6 multicase mac*/
|
|
if(!ICMPV6_MCAST_MAC(DDA) ){
|
|
/*change mac (DA) to (ipv6 multicase mac) format by (ipv6 multicast ip)*/
|
|
DDA[0] = 0x33;
|
|
DDA[1] = 0x33;
|
|
#ifdef __ECOS
|
|
memcpy(DDA+2, &iph->ip6_dst.s6_addr[12], 4);
|
|
#else
|
|
memcpy(DDA+2, &iph->daddr.s6_addr[12], 4);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT)
|
|
/* 88C, 92C, and 92D need to check privacy algorithm and accept icv error packet when using CCMP,
|
|
because hw may report wrong icv status when using CCMP privacy*/
|
|
static __inline__ unsigned int check_icverr_drop(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo) {/*return 0: accept packet, 1: drop packet*/
|
|
unsigned int privacy;
|
|
struct stat_info *pstat;
|
|
if((GET_CHIP_VER(priv)== VERSION_8192C) || (GET_CHIP_VER(priv)== VERSION_8192D) || (GET_CHIP_VER(priv)== VERSION_8188C)){
|
|
privacy = 0;
|
|
pstat = NULL;
|
|
#if defined(WDS) || defined(CONFIG_RTK_MESH) || defined(A4_STA)
|
|
if (get_tofr_ds((unsigned char *)get_pframe(pfrinfo)) == 3) {
|
|
pstat = get_stainfo(priv, (unsigned char *)GetAddr2Ptr((unsigned char *)get_pframe(pfrinfo)));
|
|
} else
|
|
#endif
|
|
{
|
|
pstat = get_stainfo(priv, (unsigned char *)get_sa((unsigned char *)get_pframe(pfrinfo)));
|
|
}
|
|
|
|
if (pstat) {
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#if defined(WDS) || defined(CONFIG_RTK_MESH)
|
|
if (get_tofr_ds((unsigned char *)get_pframe(pfrinfo)) == 3){
|
|
#if defined(CONFIG_RTK_MESH)
|
|
if(priv->pmib->dot1180211sInfo.mesh_enable) {
|
|
privacy = (IS_MCAST(GetAddr1Ptr((unsigned char *)get_pframe(pfrinfo)))) ? _NO_PRIVACY_ : priv->pmib->dot11sKeysTable.dot11Privacy;
|
|
} else
|
|
#endif
|
|
{privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;}
|
|
}
|
|
else
|
|
#endif /* defined(WDS) || defined(CONFIG_RTK_MESH) */
|
|
{privacy = get_sta_encrypt_algthm(priv, pstat);}
|
|
}
|
|
#if defined(CLIENT_MODE)
|
|
else {
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
}
|
|
#endif
|
|
|
|
if (privacy == _CCMP_PRIVACY_)
|
|
return 0; /* do not drop this packet*/
|
|
}
|
|
}
|
|
return 1;/* drop this packet*/
|
|
}
|
|
#endif
|
|
|
|
#ifdef A4_STA
|
|
static void add_a4_client(struct rtl8192cd_priv *priv, struct stat_info *pstat)
|
|
{
|
|
struct list_head *phead, *plist;
|
|
struct stat_info *sta;
|
|
|
|
if (!netif_running(priv->dev))
|
|
return;
|
|
|
|
phead = &priv->a4_sta_list;
|
|
plist = phead->next;
|
|
|
|
while (plist != phead) {
|
|
sta = list_entry(plist, struct stat_info, a4_sta_list);
|
|
if (!memcmp(sta->hwaddr, pstat->hwaddr, WLAN_ADDR_LEN)) {
|
|
ASSERT(pstat == sta);
|
|
break;
|
|
}
|
|
plist = plist->next;
|
|
}
|
|
|
|
if (plist == phead)
|
|
list_add_tail(&pstat->a4_sta_list, &priv->a4_sta_list);
|
|
|
|
pstat->state |= WIFI_A4_STA;
|
|
}
|
|
#endif
|
|
|
|
#ifdef BR_SHORTCUT
|
|
#ifdef CONFIG_RTL8672
|
|
extern struct net_device *get_eth_cached_dev(unsigned char *da);
|
|
#else
|
|
#ifdef CONFIG_RTL_819X
|
|
__inline__ struct net_device *get_eth_cached_dev(unsigned char *da)
|
|
{
|
|
extern unsigned char cached_eth_addr[MACADDRLEN];
|
|
extern struct net_device *cached_dev;
|
|
|
|
#ifndef NOT_RTK_BSP
|
|
extern unsigned char cached_eth_addr2[MACADDRLEN];
|
|
extern struct net_device *cached_dev2;
|
|
|
|
extern unsigned char cached_eth_addr3[MACADDRLEN];
|
|
extern struct net_device *cached_dev3;
|
|
|
|
extern unsigned char cached_eth_addr4[MACADDRLEN];
|
|
extern struct net_device *cached_dev4;
|
|
#endif // !NOT_RTK_BSP
|
|
if (cached_dev && !memcmp(da, cached_eth_addr, MACADDRLEN))
|
|
return cached_dev;
|
|
#ifndef NOT_RTK_BSP
|
|
else if (cached_dev2 && !memcmp(da, cached_eth_addr2, MACADDRLEN))
|
|
return cached_dev2;
|
|
else if (cached_dev3 && !memcmp(da, cached_eth_addr3, MACADDRLEN))
|
|
return cached_dev3;
|
|
else if (cached_dev4 && !memcmp(da, cached_eth_addr4, MACADDRLEN))
|
|
return cached_dev4;
|
|
#endif // !NOT_RTK_BSP
|
|
else
|
|
return NULL;
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if ((defined(CONFIG_RTK_VLAN_SUPPORT) && defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM)) || defined(MCAST2UI_REFINE))
|
|
extern struct net_device* re865x_get_netdev_by_name(const char* name);
|
|
#endif
|
|
|
|
#ifdef _SINUX_
|
|
extern int g_sc_enable_brsc;
|
|
#endif
|
|
|
|
#ifdef _FULLY_WIFI_IGMP_SNOOPING_SUPPORT_
|
|
#include <linux/igmp.h>
|
|
static void ___ConvertMulticatIPtoMacAddr(__u32 group, unsigned char *gmac)
|
|
{
|
|
__u32 u32tmp, tmp;
|
|
int i;
|
|
|
|
u32tmp = group & 0x007FFFFF;
|
|
gmac[0]=0x01; gmac[1]=0x00; gmac[2]=0x5e;
|
|
for (i=5; i>=3; i--) {
|
|
tmp=u32tmp&0xFF;
|
|
gmac[i]=tmp;
|
|
u32tmp >>= 8;
|
|
}
|
|
}
|
|
|
|
static char __igmp3_report_simple_check(struct sk_buff *skb, unsigned char *gmac, struct igmphdr *igmph)
|
|
{
|
|
struct igmpv3_report *igmpv3;
|
|
struct igmpv3_grec *igmpv3grec;
|
|
unsigned int IGMP_Group;// add for fit igmp v3
|
|
__u16 rec_id =0;
|
|
int srcnum=0;
|
|
int op = 0;
|
|
|
|
igmpv3 = (struct igmpv3_report *)igmph;
|
|
igmpv3grec = &igmpv3->grec[0];
|
|
|
|
while( rec_id < ntohs(igmpv3->ngrec) )
|
|
{
|
|
IGMP_Group = be32_to_cpu(igmpv3grec->grec_mca);
|
|
srcnum = ntohs(igmpv3grec->grec_nsrcs);
|
|
|
|
/*check if it's protocol reserved group */
|
|
if(IN_MULTICAST(IGMP_Group))
|
|
{
|
|
___ConvertMulticatIPtoMacAddr(IGMP_Group, gmac);
|
|
switch( igmpv3grec->grec_type )
|
|
{
|
|
case IGMPV3_MODE_IS_INCLUDE:
|
|
case IGMPV3_CHANGE_TO_INCLUDE:
|
|
if (srcnum == 0){
|
|
op = 0x8B81; // SIOCGIMCAST_DEL;
|
|
} else {
|
|
op =0x8B80; // SIOCGIMCAST_ADD;
|
|
}
|
|
break;
|
|
case IGMPV3_MODE_IS_EXCLUDE:
|
|
case IGMPV3_CHANGE_TO_EXCLUDE:
|
|
case IGMPV3_ALLOW_NEW_SOURCES:
|
|
op =0x8B80; // SIOCGIMCAST_ADD;
|
|
break;
|
|
case IGMPV3_BLOCK_OLD_SOURCES:
|
|
op = 0x8B81; // SIOCGIMCAST_DEL;
|
|
break;
|
|
default:
|
|
//printk("%s> Not support Group Record Types [%x]\n", __FUNCTION__, igmpv3grec->grec_type );
|
|
break;
|
|
}
|
|
} /*else {
|
|
printk("%s> Mcast err addr, group:%s, rec_id:%d, srcnum:%d\n", __FUNCTION__, inet_ntoa(IGMP_Group), rec_id, srcnum);
|
|
}*/
|
|
|
|
if (op != 0) {
|
|
memcpy(gmac+6, SKB_MAC_HEADER(skb)+6, 6);
|
|
ioctl_AddDelMCASTGroup2STA(skb->dev, (struct ifreq*)gmac, op);
|
|
op =0;
|
|
}
|
|
|
|
rec_id++;
|
|
igmpv3grec = (struct igmpv3_grec *)( (char*)igmpv3grec + sizeof( struct igmpv3_grec ) + (igmpv3grec->grec_auxwords+srcnum)*sizeof( __u32 ) );
|
|
}
|
|
|
|
return 3;
|
|
}
|
|
|
|
static char ___igmp_type_check(struct sk_buff *skb, unsigned char *gmac)
|
|
{
|
|
struct iphdr *iph;
|
|
__u8 hdrlen;
|
|
struct igmphdr *igmph;
|
|
unsigned int IGMP_Group;// add for fit igmp v3
|
|
|
|
/* check IP header information */
|
|
iph = SKB_IP_HEADER(skb);
|
|
hdrlen = iph->ihl << 2;
|
|
if ((iph->version != 4) && (hdrlen < 20))
|
|
return -1;
|
|
|
|
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
|
|
return -2;
|
|
|
|
{ /* check the length */
|
|
__u32 len = ntohs(iph->tot_len);
|
|
if (skb->len < len || len < hdrlen)
|
|
return -3;
|
|
}
|
|
|
|
/* parsing the igmp packet */
|
|
igmph = (struct igmphdr *)((u8*)iph+hdrlen);
|
|
|
|
/*IGMP-V3 type Report*/
|
|
if(igmph->type == IGMPV3_HOST_MEMBERSHIP_REPORT)
|
|
{
|
|
return __igmp3_report_simple_check(skb, gmac, igmph);
|
|
|
|
}else{ //4 V2 or V1
|
|
IGMP_Group = be32_to_cpu(igmph->group);
|
|
}
|
|
|
|
/*check if it's protocol reserved group */
|
|
if(!IN_MULTICAST(IGMP_Group))
|
|
{
|
|
return -4;
|
|
}
|
|
|
|
___ConvertMulticatIPtoMacAddr(IGMP_Group, gmac);
|
|
|
|
if ((igmph->type==IGMP_HOST_MEMBERSHIP_REPORT) ||
|
|
(igmph->type==IGMPV2_HOST_MEMBERSHIP_REPORT))
|
|
{
|
|
return 1; /* report and add it */
|
|
}
|
|
else if (igmph->type==IGMP_HOST_LEAVE_MESSAGE)
|
|
{
|
|
return 2; /* leave and delete it */
|
|
}
|
|
|
|
return -5;
|
|
}
|
|
|
|
static void rtl_igmp_notify(struct sk_buff *skb, void *igmp_header)
|
|
{
|
|
int op;
|
|
char type;
|
|
//struct igmphdr *ih = (struct igmphdr *)igmp_header;
|
|
unsigned char StaMacAndGroup[20];
|
|
|
|
type = ___igmp_type_check(skb,StaMacAndGroup);
|
|
|
|
switch (type) {
|
|
case 1:
|
|
op = 0x8B80; // SIOCGIMCAST_ADD;
|
|
break;
|
|
case 2:
|
|
op = 0x8B81; // SIOCGIMCAST_DEL;
|
|
break;
|
|
case 3://igmpv3 report
|
|
return;
|
|
default:
|
|
printk("IGMP Error type=%d\n",type);
|
|
return;
|
|
|
|
}
|
|
memcpy(StaMacAndGroup+6, SKB_MAC_HEADER(skb)+6, 6);
|
|
ioctl_AddDelMCASTGroup2STA(skb->dev, (struct ifreq*)StaMacAndGroup, op);
|
|
}
|
|
|
|
static void check_igmp_snooping_pkt( struct sk_buff *pskb )
|
|
{
|
|
unsigned char *dest = eth_hdr(pskb)->h_dest;
|
|
struct iphdr *iph;
|
|
int vlanTag = 0;
|
|
|
|
if (IS_MCAST(dest))
|
|
{
|
|
if (unlikely((*(unsigned short *)(SKB_MAC_HEADER(pskb) + ETH_ALEN * 2) == __constant_htons(ETH_P_8021Q))))
|
|
vlanTag = 4;
|
|
if (unlikely((*(unsigned short *)(SKB_MAC_HEADER(pskb) + ETH_ALEN * 2 + vlanTag) == __constant_htons(ETH_P_IP))))
|
|
{
|
|
iph = SKB_IP_HEADER(pskb);
|
|
if (vlanTag)
|
|
iph = (struct iphdr *)((unsigned char*)iph + vlanTag);
|
|
#if defined(LINUX_2_6_22_)
|
|
skb_set_network_header(pskb, ETH_HLEN+vlanTag);
|
|
#else
|
|
pskb->nh.raw = (unsigned char *)iph;
|
|
#endif
|
|
if (unlikely(iph->protocol == IPPROTO_IGMP))
|
|
{
|
|
//printk("dest=%02x-%02x-%02x-%02x-%02x-%02x\n",dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]);
|
|
#if defined(LINUX_2_6_22_)
|
|
pskb->transport_header = pskb->network_header + (iph->ihl * 4);
|
|
rtl_igmp_notify(pskb, skb_transport_header(pskb));
|
|
#else
|
|
pskb->h.raw = pskb->nh.raw + (iph->ihl * 4);
|
|
rtl_igmp_notify(pskb, pskb->h.raw);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endif //_FULLY_WIFI_IGMP_SNOOPING_SUPPORT_
|
|
|
|
#ifdef _FULLY_WIFI_MLD_SNOOPING_SUPPORT_
|
|
#define IPV6_ROUTER_ALTER_OPTION 0x05020000
|
|
#define HOP_BY_HOP_OPTIONS_HEADER 0
|
|
#define ROUTING_HEADER 43
|
|
#define FRAGMENT_HEADER 44
|
|
#define DESTINATION_OPTION_HEADER 60
|
|
|
|
#define ICMP_PROTOCOL 58
|
|
|
|
#define MLD_QUERY 130
|
|
#define MLDV1_REPORT 131
|
|
#define MLDV1_DONE 132
|
|
#define MLDV2_REPORT 143
|
|
|
|
#define MLD2_CHANGE_TO_INCLUDE 3
|
|
#define MLD2_CHANGE_TO_EXCLUDE 4
|
|
|
|
/*Convert MultiCatst IPV6_Addr to MAC_Addr*/
|
|
static void ___ConvertMulticatIPv6toMacAddr(unsigned char* icmpv6_McastAddr, unsigned char *gmac)
|
|
{
|
|
/*ICMPv6 valid addr 2^32 -1*/
|
|
gmac[0] = 0x33;
|
|
gmac[1] = 0x33;
|
|
gmac[2] = icmpv6_McastAddr[12];
|
|
gmac[3] = icmpv6_McastAddr[13];
|
|
gmac[4] = icmpv6_McastAddr[14];
|
|
gmac[5] = icmpv6_McastAddr[15];
|
|
}
|
|
|
|
static char ___mld_type_check(struct sk_buff *skb, unsigned char *gmac)
|
|
{
|
|
unsigned char *ptr;
|
|
#ifdef __ECOS
|
|
struct ip6_hdr *ipv6h;
|
|
#else
|
|
struct ipv6hdr *ipv6h;
|
|
#endif
|
|
|
|
unsigned char *startPtr = NULL;
|
|
unsigned char *lastPtr = NULL;
|
|
unsigned char nextHeader = 0;
|
|
unsigned short extensionHdrLen = 0;
|
|
|
|
#if defined(LINUX_2_6_22_)
|
|
ptr = (unsigned char *)skb_network_header(skb);
|
|
#else
|
|
ptr = (unsigned char *)skb->nh.raw;
|
|
#endif
|
|
|
|
#ifdef __ECOS
|
|
ipv6h = (struct ip6_hdr *)ptr;
|
|
if (ipv6h->ip6_vfc != IPV6_VERSION)
|
|
#else
|
|
ipv6h = (struct ipv6hdr *)ptr;
|
|
if (ipv6h->version != 6)
|
|
#endif
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
startPtr = (unsigned char *)ptr;
|
|
#ifdef __ECOS
|
|
lastPtr = startPtr + sizeof(struct ip6_hdr) + ntohs(ipv6h->ip6_plen);
|
|
nextHeader = ipv6h->ip6_nxt;
|
|
ptr = startPtr + sizeof(struct ip6_hdr);
|
|
#else
|
|
lastPtr = startPtr + sizeof(struct ipv6hdr) + ntohs(ipv6h->payload_len);
|
|
nextHeader = ipv6h->nexthdr;
|
|
ptr = startPtr + sizeof(struct ipv6hdr);
|
|
#endif
|
|
|
|
while (ptr < lastPtr)
|
|
{
|
|
switch (nextHeader)
|
|
{
|
|
//printk("nextHeader : %d\n", nextHeader);
|
|
|
|
case HOP_BY_HOP_OPTIONS_HEADER:
|
|
/*parse hop-by-hop option*/
|
|
nextHeader = ptr[0];
|
|
extensionHdrLen = ((u16)(ptr[1]) + 1) * 8;
|
|
ptr = ptr + extensionHdrLen;
|
|
break;
|
|
|
|
case ROUTING_HEADER:
|
|
nextHeader = ptr[0];
|
|
extensionHdrLen = ((u16)(ptr[1]) + 1) * 8;
|
|
ptr = ptr + extensionHdrLen;
|
|
break;
|
|
|
|
case FRAGMENT_HEADER:
|
|
nextHeader = ptr[0];
|
|
ptr = ptr + 8;
|
|
break;
|
|
|
|
case DESTINATION_OPTION_HEADER:
|
|
nextHeader = ptr[0];
|
|
extensionHdrLen = ((u16)(ptr[1]) + 1) * 8;
|
|
ptr = ptr + extensionHdrLen;
|
|
break;
|
|
|
|
case ICMP_PROTOCOL:
|
|
if (ptr[0] == MLDV2_REPORT) {
|
|
//printk("MLDV2_REPORT\n");
|
|
___ConvertMulticatIPv6toMacAddr(ptr + 12, gmac);
|
|
|
|
if (ptr[8] == MLD2_CHANGE_TO_EXCLUDE)
|
|
{
|
|
//printk("MLD2_CHANGE_TO_EXCLUDE\n");
|
|
return 1; /* report and add it */
|
|
}
|
|
|
|
if (ptr[8] == MLD2_CHANGE_TO_INCLUDE)
|
|
{
|
|
//printk("MLD2_CHANGE_TO_INCLUDE\n");
|
|
return 2; /* leave and delete it */
|
|
}
|
|
} else if (ptr[0] == MLDV1_REPORT) {
|
|
//printk("MLDV1_REPORT\n");
|
|
___ConvertMulticatIPv6toMacAddr(ptr + 8, gmac);
|
|
return 1; /* report and add it */
|
|
} else if (ptr[0] == MLDV1_DONE) {
|
|
//printk("MLDV1_DONE\n");
|
|
___ConvertMulticatIPv6toMacAddr(ptr + 8, gmac);
|
|
return 2; /* leave and delete it */
|
|
}
|
|
|
|
return -2;
|
|
break;
|
|
|
|
default:
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
return -4;
|
|
}
|
|
|
|
static void rtl_mld_notify(struct sk_buff *skb)
|
|
{
|
|
int op;
|
|
char type;
|
|
unsigned char StaMacAndGroup[20];
|
|
|
|
type = ___mld_type_check(skb, StaMacAndGroup);
|
|
//printk("MLD type = %d\n", type);
|
|
|
|
switch (type) {
|
|
case 1:
|
|
op = 0x8B80; // SIOCGIMCAST_ADD;
|
|
break;
|
|
case 2:
|
|
op = 0x8B81; // SIOCGIMCAST_DEL;
|
|
break;
|
|
default:
|
|
//printk("MLD Error type = %d\n", type);
|
|
return;
|
|
}
|
|
|
|
memcpy(StaMacAndGroup + 6, SKB_MAC_HEADER(skb) + 6, 6);
|
|
ioctl_AddDelMCASTGroup2STA(skb->dev, (struct ifreq*)StaMacAndGroup, op);
|
|
//printk("StaMacAndGroup[0] = %02x-%02x-%02x-%02x-%02x-%02x\n", StaMacAndGroup[0], StaMacAndGroup[1], StaMacAndGroup[2], StaMacAndGroup[3], StaMacAndGroup[4], StaMacAndGroup[5]);
|
|
//printk("StaMacAndGroup[6] = %02x-%02x-%02x-%02x-%02x-%02x\n", StaMacAndGroup[0+6], StaMacAndGroup[1+6], StaMacAndGroup[2+6], StaMacAndGroup[3+6], StaMacAndGroup[4+6], StaMacAndGroup[5+6]);
|
|
}
|
|
|
|
static void check_mld_snooping_pkt(struct sk_buff *pskb)
|
|
{
|
|
unsigned char *dest = eth_hdr(pskb)->h_dest;
|
|
struct iphdr *iph;
|
|
int vlanTag = 0;
|
|
|
|
if (IPV6_MCAST_MAC(dest))
|
|
{
|
|
if (unlikely((*(unsigned short *)(SKB_MAC_HEADER(pskb) + ETH_ALEN * 2) == __constant_htons(ETH_P_8021Q))))
|
|
vlanTag = 4;
|
|
|
|
if (unlikely((*(unsigned short *)(SKB_MAC_HEADER(pskb) + ETH_ALEN * 2 + vlanTag) == __constant_htons(ETH_P_IPV6))))
|
|
{
|
|
iph = SKB_IP_HEADER(pskb);
|
|
if (vlanTag)
|
|
iph = (struct iphdr *)((unsigned char*)iph + vlanTag);
|
|
|
|
#if defined(LINUX_2_6_22_)
|
|
skb_set_network_header(pskb, ETH_HLEN+vlanTag);
|
|
#else
|
|
pskb->nh.raw = (unsigned char *)iph;
|
|
#endif
|
|
//printk("dest = %02x-%02x-%02x-%02x-%02x-%02x\n", dest[0], dest[1], dest[2], dest[3], dest[4], dest[5]);
|
|
rtl_mld_notify(pskb);
|
|
}
|
|
}
|
|
}
|
|
#endif //_FULLY_WIFI_MLD_SNOOPING_SUPPORT_
|
|
|
|
#if defined(BR_SHORTCUT)
|
|
|
|
int rtl_IsMcastIP(struct sk_buff *pskb)
|
|
{
|
|
int ret=0;
|
|
unsigned short L3_protocol;
|
|
L3_protocol = *(unsigned short *)(pskb->data+ETH_ALEN*2);
|
|
|
|
if( L3_protocol == __constant_htons(0x0800) )
|
|
{
|
|
unsigned int DaIpAddr;
|
|
struct iphdr* iph = (struct iphdr *)(pskb->data + ETH_HLEN);
|
|
|
|
DaIpAddr = iph->daddr;
|
|
//panic_printk("[%s]:[%d],pskb:%x.\n",__FUNCTION__,__LINE__,DaIpAddr);
|
|
|
|
if((DaIpAddr & 0xF0000000) == 0xE0000000)
|
|
{
|
|
ret=1;
|
|
}
|
|
}
|
|
else if(L3_protocol == __constant_htons(0x86dd))
|
|
{
|
|
#ifdef __ECOS
|
|
struct ip6_hdr *iph;
|
|
iph = (struct ip6_hdr *)(pskb->data + ETH_HLEN);
|
|
#else
|
|
struct ipv6hdr *iph;
|
|
iph = (struct ipv6hdr *)(pskb->data + ETH_HLEN);
|
|
#endif
|
|
/*ip(v6) format is multicast ip*/
|
|
#ifdef __ECOS
|
|
if (iph->ip6_dst.s6_addr[0] == 0xff)
|
|
#else
|
|
if (iph->daddr.s6_addr[0] == 0xff)
|
|
#endif
|
|
{
|
|
ret=1;
|
|
}
|
|
}
|
|
|
|
//panic_printk("[%s]:[%d],ret:%x,pskb:%x-%x-%x-%x-%x-%x.\n",__FUNCTION__,__LINE__,ret,pskb->data[0],pskb->data[1],pskb->data[2],pskb->data[3],pskb->data[4],pskb->data[5]);
|
|
return ret;
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_RTL_8196E
|
|
__MIPS16
|
|
#endif
|
|
__IRAM_IN_865X
|
|
void rtl_netif_rx(struct rtl8192cd_priv *priv, struct sk_buff *pskb, struct stat_info *pstat)
|
|
{
|
|
#ifdef CLIENT_MODE
|
|
#ifdef SUPPORT_RX_UNI2MCAST
|
|
unsigned short L3_protocol;
|
|
unsigned char *DA_START;
|
|
#endif
|
|
#ifdef VIDEO_STREAMING_REFINE
|
|
// for video streaming refine
|
|
extern struct net_device *is_eth_streaming_only(struct sk_buff *skb);
|
|
struct net_device *dev;
|
|
#endif
|
|
#endif
|
|
struct vlan_info *vlan=NULL;
|
|
#ifdef CONFIG_RTL_VLAN_8021Q
|
|
int index;
|
|
#endif
|
|
|
|
struct net_bridge_port *br_port=NULL;
|
|
|
|
static unsigned char* cached_sta_macPtr=NULL;
|
|
static struct net_device *cached_sta_devPtr=NULL;
|
|
|
|
#ifdef __KERNEL__
|
|
br_port = GET_BR_PORT(priv->dev);
|
|
#endif
|
|
#ifdef CONFIG_POWER_SAVE
|
|
rtw_ap_ps_recv_monitor(priv);
|
|
#endif
|
|
|
|
#ifdef PREVENT_BROADCAST_STORM
|
|
if ((OPMODE & WIFI_AP_STATE) && ((unsigned char)pskb->data[0] == 0xff) && pstat) {
|
|
if (pstat->rx_pkts_bc > BROADCAST_STORM_THRESHOLD) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Broadcast storm happened!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTK_VLAN_WAN_TAG
|
|
extern int rtl865x_same_root(struct net_device *dev1,struct net_device *dev2);
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL_CUSTOM_PASSTHRU)
|
|
#ifdef __ECOS
|
|
if (SUCCESS==rtl_isWlanPassthruFrame(pskb->data))
|
|
#else
|
|
if (SUCCESS==rtl_isPassthruFrame(pskb->data))
|
|
#endif
|
|
{
|
|
#ifdef CLIENT_MODE
|
|
if(priv &&((GET_MIB(priv))->dot11OperationEntry.opmode)& WIFI_STATION_STATE)
|
|
{
|
|
#if defined(CONFIG_RTL_92D_SUPPORT)||defined (CONFIG_RTL_8881A)
|
|
unsigned int wispWlanIndex=(passThruStatusWlan&WISP_WLAN_IDX_MASK)>>WISP_WLAN_IDX_RIGHT_SHIFT;
|
|
if(
|
|
#ifdef SMART_REPEATER_MODE
|
|
(priv==(GET_VXD_PRIV((wlan_device[wispWlanIndex].priv))))||
|
|
#endif
|
|
(priv == wlan_device[wispWlanIndex].priv))
|
|
{
|
|
pskb->dev = wlan_device[passThruWanIdx].priv->pWlanDev;
|
|
}
|
|
#else
|
|
pskb->dev = wlan_device[passThruWanIdx].priv->pWlanDev;
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef GBWC
|
|
if (priv->pmib->gbwcEntry.GBWCMode && pstat) {
|
|
if (((priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_MAC_INNER) && (pstat->GBWC_in_group)) ||
|
|
((priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_MAC_OUTTER) && !(pstat->GBWC_in_group)) ||
|
|
(priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_IF_RX) ||
|
|
(priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_IF_TRX)) {
|
|
if ((priv->GBWC_rx_count + pskb->len) > ((priv->pmib->gbwcEntry.GBWCThrd_rx * 1024 / 8) / (100 / GBWC_TO))) {
|
|
// over the bandwidth
|
|
if (priv->GBWC_consuming_Q) {
|
|
// in rtl8192cd_GBWC_timer context
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: BWC bandwidth over!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
}
|
|
else {
|
|
// normal Rx path
|
|
int ret = enque(priv, &(priv->GBWC_rx_queue.head), &(priv->GBWC_rx_queue.tail),
|
|
(unsigned long)(priv->GBWC_rx_queue.pSkb), NUM_TXPKT_QUEUE, (void *)pskb);
|
|
if (ret == FALSE) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: BWC rx queue full!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
}
|
|
else
|
|
*(unsigned int *)&(pskb->cb[4]) = (unsigned int)pstat; // backup pstat pointer
|
|
}
|
|
return;
|
|
}
|
|
else {
|
|
// not over the bandwidth
|
|
if (CIRC_CNT(priv->GBWC_rx_queue.head, priv->GBWC_rx_queue.tail, NUM_TXPKT_QUEUE) &&
|
|
!priv->GBWC_consuming_Q) {
|
|
// there are already packets in queue, put in queue too for order
|
|
int ret = enque(priv, &(priv->GBWC_rx_queue.head), &(priv->GBWC_rx_queue.tail),
|
|
(unsigned long)(priv->GBWC_rx_queue.pSkb), NUM_TXPKT_QUEUE, (void *)pskb);
|
|
if (ret == FALSE) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: BWC rx queue full!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
}
|
|
else
|
|
*(unsigned int *)&(pskb->cb[4]) = (unsigned int)pstat; // backup pstat pointer
|
|
return;
|
|
}
|
|
else {
|
|
// can pass up directly
|
|
priv->GBWC_rx_count += pskb->len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
|
|
#if defined(MULTI_MAC_CLONE) && !defined(__ECOS)
|
|
if ((OPMODE & WIFI_AP_STATE) && pskb->dev && (pskb->dev->base_addr != 0)) {
|
|
*(unsigned int *)&(pskb->cb[40]) = 0x86518192; // means from wlan interface
|
|
}
|
|
#endif
|
|
|
|
#ifdef HS2_SUPPORT
|
|
/* Hotspot 2.0 Release 1 */
|
|
if ((priv->proxy_arp) && (IS_MCAST(pskb->data)) && pstat)
|
|
{
|
|
if (ICMPV6_MCAST_SOLI_MAC(pskb->data))
|
|
stav6ip_snooping_bynsolic(pskb, pstat);
|
|
//else if (ICMPV6_MCAST_MAC(pskb->data))
|
|
// stav6ip_snooping_bynadvert(pskb, pstat);
|
|
else
|
|
staip_snooping_byarp(pskb, pstat);
|
|
}
|
|
#endif
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if((OPMODE & WIFI_STATION_STATE)
|
|
#ifdef __KERNEL__
|
|
&& (br_port)
|
|
#endif
|
|
) {
|
|
unsigned char *brmac;
|
|
|
|
brmac = priv->br_mac;
|
|
if(isDHCPpkt(pskb) && memcmp(pskb->data+MACADDRLEN,brmac,MACADDRLEN)) {
|
|
DEBUG_INFO("%s %d invoke snoop_STA_IP\n",__func__,__LINE__);
|
|
snoop_STA_IP(pskb, priv);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef _11s_TEST_MODE_
|
|
mesh_debug_rx1(priv, pskb);
|
|
#endif
|
|
|
|
#if 0//def CONFIG_RTL_STP
|
|
if (((unsigned char)pskb->data[12]) < 0x06)
|
|
{
|
|
if (!memcmp(pskb->data, STPmac, 5) && !(((unsigned char )pskb->data[5])& 0xF0))
|
|
{
|
|
if (memcmp(pskb->dev->name, WLAN_INTERFACE_NAME, sizeof(WLAN_INTERFACE_NAME)) == 0)
|
|
{
|
|
if (wlan_pseudo_dev != NULL)
|
|
pskb->dev = wlan_pseudo_dev;
|
|
pskb->protocol = eth_type_trans(pskb, priv->dev);
|
|
#if defined(_BROADLIGHT_FASTPATH_)
|
|
send_packet_to_upper_layer(pskb);
|
|
#elif defined(__LINUX_2_6__) && defined(RX_TASKLET) && !defined(CONFIG_RTL8672) && !defined(NOT_RTK_BSP) && !defined(__LINUX_3_10__)
|
|
netif_receive_skb(pskb);
|
|
#else
|
|
netif_rx(pskb);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef CONFIG_RTK_VLAN_SUPPORT
|
|
#if defined(CONFIG_RTK_MESH)
|
|
if(pskb->dev == priv->mesh_dev) {
|
|
vlan = (struct vlan_info *)&priv->mesh_vlan;
|
|
} else
|
|
#endif
|
|
{
|
|
vlan = (struct vlan_info *)&priv->pmib->vlan;
|
|
}
|
|
|
|
if (rtk_vlan_support_enable && vlan->global_vlan) {
|
|
#if defined(CONFIG_RTK_VLAN_NEW_FEATURE)
|
|
if (rx_vlan_process(priv->dev, vlan, pskb, NULL)){
|
|
#else
|
|
if (rx_vlan_process(priv->dev, vlan, pskb)){
|
|
#endif
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: by vlan!\n");
|
|
dev_kfree_skb_any(pskb);
|
|
return;
|
|
}
|
|
|
|
#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM)
|
|
if(rtk_vlan_support_enable == 2 && pskb->tag.f.tpid == htons(ETH_P_8021Q))
|
|
{
|
|
struct net_device *toDev;
|
|
|
|
toDev = re865x_get_netdev_by_name("eth1");
|
|
|
|
//printk("===%s(%d),vid(%d),from(%s),todev(%s),skb->tag.vid(%d)\n",__FUNCTION__,__LINE__,pskb->tag.f.pci & 0xfff, pskb->dev->name,
|
|
//toDev?toDev->name:NULL,pskb->tag.f.pci & 0xfff);
|
|
|
|
if(toDev)
|
|
{
|
|
pskb->dev = toDev;
|
|
toDev->netdev_ops->ndo_start_xmit(pskb,toDev);
|
|
return;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL_819X_ECOS)&&defined(CONFIG_RTL_VLAN_SUPPORT)&&defined(CONFIG_RTL_819X_SWCORE)
|
|
if (rtl_vlan_support_enable) {
|
|
#ifdef CONFIG_RTL_BRIDGE_VLAN_SUPPORT
|
|
if (rtl_vlanIngressProcess(pskb, priv->dev->name, NULL) < 0){
|
|
#else
|
|
if (rtl_vlanIngressProcess(pskb, priv->dev->name) < 0){
|
|
#endif
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: by vlan!\n");
|
|
dev_kfree_skb_any(pskb);
|
|
return;
|
|
}
|
|
}
|
|
#endif //CONFIG_RTL_VLAN_SUPPORT
|
|
|
|
#ifdef CONFIG_RTL_VLAN_8021Q
|
|
#if 0
|
|
if(linux_vlan_enable){
|
|
/*add vlan tag if pkt is untagged*/
|
|
if(*((uint16*)(pskb->data+(ETH_ALEN<<1))) != __constant_htons(ETH_P_8021Q)){
|
|
/*mapping dev to pvid array's index*/
|
|
index = priv->dev->vlan_member_map;
|
|
if(index>=WLAN0_MASK_BIT && index<=WLAN1_VXD_MASK_BIT){
|
|
if(vlan_ctl_p->pvid[index]){
|
|
memmove(pskb->data-VLAN_HLEN, pskb->data, ETH_ALEN<<1);
|
|
skb_push(pskb,VLAN_HLEN);
|
|
*((uint16*)(pskb->data+(ETH_ALEN<<1))) = __constant_htons(ETH_P_8021Q);
|
|
*((uint16*)(pskb->data+(ETH_ALEN<<1)+2)) = vlan_ctl_p->pvid[index];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(BR_SHORTCUT)
|
|
if(rtl_IsMcastIP(pskb)==0)
|
|
{
|
|
#ifdef CONFIG_RTL_VLAN_8021Q
|
|
if(!linux_vlan_enable)
|
|
#endif
|
|
/*if lltd, don't go shortcut*/
|
|
if(*(unsigned short *)(pskb->data+ETH_ALEN*2) != htons(0x88d9))
|
|
{
|
|
struct net_device *cached_dev=NULL;
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
|
|
if (pskb->dev && (pskb->dev == priv->mesh_dev))
|
|
{
|
|
int index = 0;
|
|
#ifdef CONFIG_RTL_MESH_CROSSBAND
|
|
index = priv->dev->name[4] - '0';
|
|
#endif
|
|
|
|
proxy_table_chkcln(priv, pskb);
|
|
memcpy(cached_mesh_mac[index], &pskb->data[6], 6);
|
|
cached_mesh_dev[index] = pskb->dev;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WDS
|
|
if (pskb->dev && pskb->dev->base_addr==0) {
|
|
if(priv->pmib->dot11WdsInfo.wdsNum>1)
|
|
cached_wds_dev = NULL;
|
|
else
|
|
{
|
|
memcpy(cached_wds_mac, &pskb->data[6], 6);
|
|
cached_wds_dev = pskb->dev;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CLIENT_MODE
|
|
if ((OPMODE & WIFI_STATION_STATE) && pskb->dev) {
|
|
|
|
|
|
if(priv->reperater_idx==1){
|
|
memcpy(cached_sta_mac[0], &pskb->data[6], 6);
|
|
cached_sta_dev[0] = pskb->dev;
|
|
}else if((priv->reperater_idx==2)){
|
|
memcpy(cached_sta_mac[1], &pskb->data[6], 6);
|
|
cached_sta_dev[1] = pskb->dev;
|
|
}
|
|
|
|
if (!(pskb->data[0] & 0x01) &&
|
|
!priv->pmib->dot11OperationEntry.disable_brsc &&
|
|
#ifdef __KERNEL__
|
|
(br_port) &&
|
|
#endif
|
|
((cached_dev=get_shortcut_dev(pskb->data)) !=NULL)
|
|
&& netif_running(cached_dev)
|
|
)
|
|
{
|
|
|
|
pskb->dev = cached_dev;
|
|
#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
|
|
cached_dev->hard_start_xmit(pskb, cached_dev);
|
|
#else
|
|
cached_dev->netdev_ops->ndo_start_xmit(pskb,cached_dev);
|
|
#endif
|
|
return;
|
|
|
|
}
|
|
}
|
|
/*AP mode side -> Client mode side*/
|
|
if ((OPMODE & WIFI_AP_STATE) && pskb->dev) {
|
|
if (!(pskb->data[0] & 0x01) && !priv->pmib->dot11OperationEntry.disable_brsc && priv->reperater_idx
|
|
#ifdef __KERNEL__
|
|
&& (br_port)
|
|
#endif
|
|
)
|
|
{
|
|
|
|
|
|
if(priv->reperater_idx==1){
|
|
cached_sta_macPtr = cached_sta_mac[0];
|
|
cached_sta_devPtr = cached_sta_dev[0];
|
|
}else if(priv->reperater_idx==2){
|
|
cached_sta_macPtr = cached_sta_mac[1];
|
|
cached_sta_devPtr = cached_sta_dev[1];
|
|
}
|
|
|
|
if( cached_sta_devPtr && netif_running(cached_sta_devPtr) && (!memcmp(cached_sta_macPtr,pskb->data,6))){
|
|
pskb->dev = cached_sta_devPtr;
|
|
|
|
#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
|
|
cached_sta_devPtr->hard_start_xmit(pskb, cached_sta_devPtr);
|
|
#else
|
|
cached_sta_devPtr->netdev_ops->ndo_start_xmit(pskb,cached_sta_devPtr);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef AP_2_AP_BRSC
|
|
// AP mode -> AP mode
|
|
if ((OPMODE & WIFI_AP_STATE) && pskb->dev) {
|
|
if (!(pskb->data[0] & 0x01) &&
|
|
!priv->pmib->dot11OperationEntry.disable_brsc &&
|
|
#ifdef __KERNEL__
|
|
(br_port) &&
|
|
#endif
|
|
((cached_dev=get_shortcut_dev(pskb->data)) !=NULL)
|
|
&& netif_running(cached_dev)){
|
|
pskb->dev = cached_dev;
|
|
#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
|
|
cached_dev->hard_start_xmit(pskb, cached_dev);
|
|
#else
|
|
cached_dev->netdev_ops->ndo_start_xmit(pskb,cached_dev);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
#endif // AP_2_AP_BRSC
|
|
|
|
#ifdef WDS
|
|
if (pskb->dev && (pskb->dev->base_addr || priv->pmib->dot11WdsInfo.wdsNum<2))
|
|
#endif
|
|
if (!(pskb->data[0] & 0x01) &&
|
|
!priv->pmib->dot11OperationEntry.disable_brsc &&
|
|
#if defined(CONFIG_DOMAIN_NAME_QUERY_SUPPORT) || defined(CONFIG_RTL_ULINKER)
|
|
(pskb->data[37] != 68) && /*port 68 is dhcp dest port. In order to hack dns ip, so dhcp packa can't enter bridge short cut.*/
|
|
#endif
|
|
#if defined(CONFIG_RTL_DNS_TRAP)
|
|
!(*(unsigned short *)(pskb->data+ETH_ALEN*2)==htons(0x0800) &&
|
|
*(unsigned char *)(pskb->data+0x17) == 17 &&
|
|
(*(unsigned short *)(pskb->data+0x24) == htons(53))) &&
|
|
#endif
|
|
#ifdef __KERNEL__
|
|
#ifndef _SINUX_ // if sinux, no linux bridge, so should don't depend on br_port if use br_shortcut (John Qian 2010/6/24)
|
|
(br_port) &&
|
|
#else
|
|
(g_sc_enable_brsc) &&
|
|
#endif
|
|
#endif
|
|
#ifdef CONFIG_RTL_819X
|
|
#if defined(CONFIG_RTL_ULINKER_BRSC)
|
|
(((cached_dev=brsc_get_cached_dev(0, pskb->data))!=NULL) || ((cached_dev = get_eth_cached_dev(pskb->data)) != NULL))
|
|
#else
|
|
((cached_dev = get_eth_cached_dev(pskb->data)) != NULL)
|
|
#endif
|
|
#else
|
|
cached_dev
|
|
#endif
|
|
#ifdef CONFIG_RTK_VLAN_WAN_TAG
|
|
&& rtl865x_same_root(pskb->dev,cached_dev)
|
|
#endif
|
|
&& netif_running(cached_dev)
|
|
#if defined(CONFIG_RTK_GUEST_ZONE) && defined(__KERNEL__)
|
|
&& (cached_dev->br_port->zone_type == br_port->zone_type)
|
|
#endif
|
|
)
|
|
{
|
|
|
|
#if defined(CONFIG_RTL_ULINKER_BRSC)
|
|
if (cached_usb.dev && cached_dev == cached_usb.dev) {
|
|
BRSC_COUNTER_UPDATE(tx_wlan_sc);
|
|
BDBG_BRSC("BRSC: get shortcut dev[%s]\n", cached_usb.dev->name);
|
|
|
|
if (pskb->dev)
|
|
brsc_cache_dev(1, pskb->dev, pskb->data+ETH_ALEN);
|
|
}
|
|
#endif
|
|
|
|
#if defined(SHORTCUT_STATISTIC) //defined(__ECOS) && defined(_DEBUG_RTL8192CD_)
|
|
priv->ext_stats.br_cnt_sc++;
|
|
#endif
|
|
pskb->dev = cached_dev;
|
|
#ifdef TX_SCATTER
|
|
pskb->list_num = 0;
|
|
#endif
|
|
#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
|
|
cached_dev->hard_start_xmit(pskb, cached_dev);
|
|
#else
|
|
cached_dev->netdev_ops->ndo_start_xmit(pskb,cached_dev);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif // BR_SHORTCUT
|
|
#if defined(CONFIG_RTL_FASTBRIDGE)
|
|
if (br_port) {
|
|
if (RTL_FB_RETURN_SUCCESS==rtl_fb_process_in_nic(pskb, pskb->dev))
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
if ((OPMODE & WIFI_AP_STATE) && pskb->dev && (pskb->dev->base_addr != 0)) {
|
|
*(unsigned int *)&(pskb->cb[20]) = 0x86518190; // means from wlan interface
|
|
*(unsigned int *)&(pskb->cb[24]) = priv->pmib->miscEntry.groupID; // remember group ID
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL867X_VLAN_MAPPING
|
|
if (re_vlan_loaded()) {
|
|
re_vlan_untag(pskb);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
if (pskb->dev)
|
|
#ifdef __LINUX_2_6__
|
|
pskb->protocol = eth_type_trans(pskb, pskb->dev);
|
|
else
|
|
#endif
|
|
pskb->protocol = eth_type_trans(pskb, priv->dev);
|
|
#endif
|
|
|
|
#ifdef _FULLY_WIFI_IGMP_SNOOPING_SUPPORT_
|
|
check_igmp_snooping_pkt(pskb);
|
|
#endif //_FULLY_WIFI_IGMP_SNOOPING_SUPPORT_
|
|
|
|
#ifdef _FULLY_WIFI_MLD_SNOOPING_SUPPORT_
|
|
check_mld_snooping_pkt(pskb);
|
|
#endif //_FULLY_WIFI_MLD_SNOOPING_SUPPORT_
|
|
|
|
#ifdef CONFIG_RTL8672
|
|
if(enable_IGMP_SNP) {
|
|
#ifdef CONFIG_EXT_SWITCH
|
|
check_IGMP_snoop_rx(pskb, wlan_igmp_tag);
|
|
#endif
|
|
}
|
|
pskb->switch_port = priv->dev->name;
|
|
pskb->from_dev = priv->dev;
|
|
#endif
|
|
|
|
#ifdef HS2_SUPPORT
|
|
/* Hotspot 2.0 Release 1 */
|
|
if (pskb->protocol == __constant_htons(ETHER_TDLS))
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
HS2_DEBUG_INFO("RX DROP: TDLS!\n");
|
|
dev_kfree_skb_any(pskb);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef SUPPORT_RX_UNI2MCAST
|
|
/* under sta mode for check UDP type packet that L3 IP is multicast but L2 mac is not */
|
|
if (((OPMODE & WIFI_STATION_STATE) == WIFI_STATION_STATE)
|
|
#ifdef MULTI_MAC_CLONE
|
|
&& !GET_MIB(priv)->ethBrExtInfo.macclone_enable
|
|
#endif
|
|
)
|
|
{
|
|
L3_protocol = *(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN * 2);
|
|
DA_START = SKB_MAC_HEADER(pskb);
|
|
|
|
if( L3_protocol == __constant_htons(0x0800) )
|
|
//&&(*(unsigned char *)(SKB_MAC_HEADER(pskb) + 23)) == 0x11) { /*added by qinjunjie,warning:unicast to multicast conversion should not only limited to udp*/
|
|
{
|
|
CheckUDPandU2M(pskb);
|
|
}else if(L3_protocol == __constant_htons(0x86dd) &&
|
|
*(unsigned char *)(SKB_MAC_HEADER(pskb) + 20) == 0x11 )
|
|
{
|
|
CheckV6UDPandU2M(pskb);
|
|
}
|
|
}
|
|
|
|
#ifdef BR_SHORTCUT
|
|
#ifdef VIDEO_STREAMING_REFINE
|
|
// for video streaming refine
|
|
if ((OPMODE & WIFI_STATION_STATE) &&
|
|
(*((unsigned char *)SKB_MAC_HEADER(pskb))) & 0x01) &&
|
|
!priv->pmib->dot11OperationEntry.disable_brsc &&
|
|
(br_port) &&
|
|
((dev = is_eth_streaming_only(pskb)) != NULL)) {
|
|
skb_push(pskb, 14);
|
|
#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
|
|
dev->hard_start_xmit(pskb, dev);
|
|
#else
|
|
dev->netdev_ops->ndo_start_xmit(pskb, dev);
|
|
#endif
|
|
return;
|
|
}
|
|
#endif // VIDEO_STREAMING_REFINE
|
|
#endif // BR_SHORTCUT
|
|
#endif // SUPPORT_RX_UNI2MCAST
|
|
|
|
#ifdef CONFIG_RTL_NETSNIPER_SUPPORT
|
|
pskb->wanorlan = rtl_check_wanorlan(pskb->dev->name); /* wan:1 lan:2 default:0 */
|
|
#endif
|
|
|
|
#if defined(SHORTCUT_STATISTIC) //defined(__ECOS) && defined(_DEBUG_RTL8192CD_)
|
|
priv->ext_stats.br_cnt_nosc++;
|
|
#endif
|
|
#if defined(_BROADLIGHT_FASTPATH_)
|
|
send_packet_to_upper_layer(pskb);
|
|
#elif defined(__LINUX_2_6__) && defined(RX_TASKLET) && !defined(CONFIG_RTL8672)&& !defined(NOT_RTK_BSP)&& !defined(__LINUX_3_10__)
|
|
netif_receive_skb(pskb);
|
|
#else
|
|
#if defined(CONFIG_RG_WLAN_HWNAT_ACCELERATION) && !defined(CONFIG_ARCH_LUNA_SLAVE)
|
|
{
|
|
enum {
|
|
RE8670_RX_STOP=0,
|
|
RE8670_RX_CONTINUE,
|
|
RE8670_RX_STOP_SKBNOFREE,
|
|
RE8670_RX_END
|
|
};
|
|
int ret;
|
|
pskb->data-=14;
|
|
pskb->len+=14;
|
|
//printk("[%s]\n",pskb->dev->name);
|
|
ret=fwdEngine_rx_skb(NULL,pskb,NULL);
|
|
if(ret==RE8670_RX_CONTINUE)
|
|
{
|
|
pskb->data+=14;
|
|
pskb->len-=14;
|
|
//printk("WLAN0 rx, fwdEngine is handled, trap to netif_rx\n");
|
|
netif_rx(pskb);
|
|
}
|
|
else if(ret==RE8670_RX_STOP)
|
|
{
|
|
kfree_skb(pskb);
|
|
}
|
|
}
|
|
#else
|
|
netif_rx(pskb);
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef GBWC
|
|
static int GBWC_forward_check(struct rtl8192cd_priv *priv, struct sk_buff *pskb, struct stat_info *pstat)
|
|
{
|
|
if (priv->pmib->gbwcEntry.GBWCMode && pstat) {
|
|
if (((priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_MAC_INNER) && (pstat->GBWC_in_group)) ||
|
|
((priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_MAC_OUTTER) && !(pstat->GBWC_in_group)) ||
|
|
(priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_IF_RX) ||
|
|
(priv->pmib->gbwcEntry.GBWCMode == GBWC_MODE_LIMIT_IF_TRX)) {
|
|
if ((priv->GBWC_rx_count + pskb->len) > ((priv->pmib->gbwcEntry.GBWCThrd_rx * 1024 / 8) / (100 / GBWC_TO))) {
|
|
// over the bandwidth
|
|
int ret = enque(priv, &(priv->GBWC_tx_queue.head), &(priv->GBWC_tx_queue.tail),
|
|
(unsigned long)(priv->GBWC_tx_queue.pSkb), NUM_TXPKT_QUEUE, (void *)pskb);
|
|
if (ret == FALSE) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: BWC tx queue full!\n");
|
|
dev_kfree_skb_any(pskb);
|
|
}
|
|
else {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_tx_skb_cnt);
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
else {
|
|
// not over the bandwidth
|
|
if (CIRC_CNT(priv->GBWC_tx_queue.head, priv->GBWC_tx_queue.tail, NUM_TXPKT_QUEUE)) {
|
|
// there are already packets in queue, put in queue too for order
|
|
int ret = enque(priv, &(priv->GBWC_tx_queue.head), &(priv->GBWC_tx_queue.tail),
|
|
(unsigned long)(priv->GBWC_tx_queue.pSkb), NUM_TXPKT_QUEUE, (void *)pskb);
|
|
if (ret == FALSE) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: BWC tx queue full!\n");
|
|
dev_kfree_skb_any(pskb);
|
|
}
|
|
else {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_tx_skb_cnt);
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
else {
|
|
// can forward directly
|
|
priv->GBWC_rx_count += pskb->len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
__MIPS16
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
static void reorder_ctrl_pktout(struct rtl8192cd_priv *priv, struct sk_buff *pskb, struct stat_info *pstat)
|
|
{
|
|
struct stat_info *dst_pstat = (struct stat_info*)(*(unsigned int *)&(pskb->cb[4]));
|
|
|
|
if (dst_pstat == 0)
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
else
|
|
{
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#ifdef TX_SCATTER
|
|
pskb->list_num = 0;
|
|
#endif
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
if(pskb->cb[3] == RELAY_11S) {
|
|
struct tx_insn txcfg;
|
|
txcfg.priv = pskb->dev->priv;
|
|
txcfg.is_11s = RELAY_11S;
|
|
pskb->dev = priv->mesh_dev;
|
|
__rtl8192cd_start_xmit_out(pskb, dst_pstat, &txcfg);
|
|
}
|
|
else if(pskb->cb[3] == XMIT_11S) {
|
|
DECLARE_TXINSN(txcfg);
|
|
if(dot11s_datapath_decision(pskb, &txcfg, 1) != 0) {
|
|
dst_pstat = get_stainfo(txcfg.priv, txcfg.nhop_11s);
|
|
pskb->dev = priv->mesh_dev;
|
|
__rtl8192cd_start_xmit_out(pskb, dst_pstat, &txcfg);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (rtl8192cd_start_xmit(pskb, priv->dev))
|
|
rtl_kfree_skb(priv, pskb, _SKB_TX_);
|
|
}
|
|
}
|
|
|
|
|
|
__MIPS16
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
static void reorder_ctrl_consumeQ(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned char tid, int seg)
|
|
{
|
|
int win_start, win_size;
|
|
struct reorder_ctrl_entry *rc_entry;
|
|
|
|
rc_entry = &pstat->rc_entry[tid];
|
|
win_start = rc_entry->win_start;
|
|
win_size = priv->pmib->reorderCtrlEntry.ReorderCtrlWinSz;
|
|
|
|
while (SN_LESS(win_start, rc_entry->last_seq) || (win_start == rc_entry->last_seq)) {
|
|
if (rc_entry->packet_q[win_start & (win_size - 1)]) {
|
|
reorder_ctrl_pktout(priv, rc_entry->packet_q[win_start & (win_size - 1)], pstat);
|
|
rc_entry->packet_q[win_start & (win_size - 1)] = NULL;
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
if (seg == 0)
|
|
pstat->rx_rc_passupi++;
|
|
else if (seg == 2)
|
|
pstat->rx_rc_passup2++;
|
|
else if (seg == 3)
|
|
pstat->rx_rc_passup3++;
|
|
else if (seg == 4)
|
|
pstat->rx_rc_passup4++;
|
|
#endif
|
|
}
|
|
win_start = SN_NEXT(win_start);
|
|
}
|
|
rc_entry->start_rcv = FALSE;
|
|
}
|
|
|
|
|
|
__MIPS16
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
static int reorder_ctrl_timer_add(struct rtl8192cd_priv *priv, struct stat_info *pstat, int tid, int from_timeout)
|
|
{
|
|
unsigned int now, timeout, new_timer=0;
|
|
int setup_timer;
|
|
int current_idx, next_idx;
|
|
int sys_tick;
|
|
|
|
if (!from_timeout) {
|
|
while (CIRC_CNT(priv->pshare->rc_timer_head, priv->pshare->rc_timer_tail, RC_TIMER_NUM)) {
|
|
if (priv->pshare->rc_timer[priv->pshare->rc_timer_tail].pstat == NULL) {
|
|
priv->pshare->rc_timer_tail = (priv->pshare->rc_timer_tail + 1) & (RC_TIMER_NUM - 1);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (CIRC_CNT(priv->pshare->rc_timer_head, priv->pshare->rc_timer_tail, RC_TIMER_NUM)) {
|
|
timeout = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout;
|
|
if (TSF_LESS(timeout, jiffies) || (timeout == jiffies)) {
|
|
if (timer_pending(&priv->pshare->rc_sys_timer))
|
|
del_timer(&priv->pshare->rc_sys_timer);
|
|
#ifdef SMP_SYNC
|
|
spin_unlock(&priv->rc_packet_q_lock);
|
|
#endif
|
|
reorder_ctrl_timeout((unsigned long)priv);
|
|
#ifdef SMP_SYNC
|
|
spin_lock(&priv->rc_packet_q_lock);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
current_idx = priv->pshare->rc_timer_head;
|
|
|
|
while (CIRC_CNT(current_idx, priv->pshare->rc_timer_tail, RC_TIMER_NUM)) {
|
|
if (priv->pshare->rc_timer[priv->pshare->rc_timer_tail].pstat == NULL) {
|
|
priv->pshare->rc_timer_tail = (priv->pshare->rc_timer_tail + 1) & (RC_TIMER_NUM - 1);
|
|
new_timer = 1;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (CIRC_CNT(current_idx, priv->pshare->rc_timer_tail, RC_TIMER_NUM) == 0) {
|
|
if (timer_pending(&priv->pshare->rc_sys_timer))
|
|
del_timer(&priv->pshare->rc_sys_timer);
|
|
setup_timer = 1;
|
|
}
|
|
else if (CIRC_SPACE(current_idx, priv->pshare->rc_timer_tail, RC_TIMER_NUM) == 0) {
|
|
DEBUG_ERR("%s: %s, RC timer overflow!\n", priv->dev->name, __FUNCTION__ );
|
|
return -1;
|
|
}
|
|
else { // some items in timer queue
|
|
setup_timer = 0;
|
|
if (new_timer)
|
|
new_timer = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout;
|
|
}
|
|
|
|
next_idx = (current_idx + 1) & (RC_TIMER_NUM - 1);
|
|
|
|
priv->pshare->rc_timer[current_idx].priv = priv;
|
|
priv->pshare->rc_timer[current_idx].pstat = pstat;
|
|
priv->pshare->rc_timer[current_idx].tid = (unsigned char)tid;
|
|
priv->pshare->rc_timer_head = next_idx;
|
|
|
|
now = jiffies;
|
|
timeout = now + priv->pshare->rc_timer_tick;
|
|
priv->pshare->rc_timer[current_idx].timeout = timeout;
|
|
sys_tick = priv->pshare->rc_timer_tick;
|
|
|
|
if (!from_timeout) {
|
|
if (setup_timer) {
|
|
mod_timer(&priv->pshare->rc_sys_timer, jiffies + sys_tick);
|
|
}
|
|
else if (new_timer) {
|
|
if (TSF_LESS(new_timer, now)) {
|
|
mod_timer(&priv->pshare->rc_sys_timer, jiffies + sys_tick);
|
|
}
|
|
else {
|
|
sys_tick = TSF_DIFF(new_timer, now);
|
|
if (sys_tick < 1)
|
|
sys_tick = 1;
|
|
mod_timer(&priv->pshare->rc_sys_timer, jiffies + sys_tick);
|
|
}
|
|
}
|
|
}
|
|
|
|
return current_idx;
|
|
}
|
|
|
|
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
void reorder_ctrl_timeout(unsigned long task_priv)
|
|
{
|
|
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
|
|
unsigned int timeout, current_time;
|
|
struct reorder_ctrl_entry *rc_entry=NULL;
|
|
struct rtl8192cd_priv *priv_this=NULL;
|
|
struct stat_info *pstat;
|
|
int win_start=0, win_size, win_end, head, tid=0, sys_tick;
|
|
unsigned long flags;
|
|
|
|
if (!(priv->drv_state & DRV_STATE_OPEN))
|
|
return;
|
|
|
|
#ifdef PCIE_POWER_SAVING
|
|
if ((priv->pwr_state == L2) || (priv->pwr_state == L1))
|
|
return ;
|
|
#endif
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
SMP_LOCK_REORDER_CTRL(flags);
|
|
|
|
current_time = jiffies;
|
|
|
|
head = priv->pshare->rc_timer_head;
|
|
win_size = priv->pmib->reorderCtrlEntry.ReorderCtrlWinSz;
|
|
|
|
while (CIRC_CNT(head, priv->pshare->rc_timer_tail, RC_TIMER_NUM))
|
|
{
|
|
pstat = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].pstat;
|
|
if (pstat) {
|
|
timeout = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout;
|
|
if (TSF_LESS(timeout, current_time) || (TSF_DIFF(timeout, current_time) <= RTL_MILISECONDS_TO_JIFFIES(10))) {
|
|
priv_this = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].priv;
|
|
tid = priv->pshare->rc_timer[priv->pshare->rc_timer_tail].tid;
|
|
rc_entry = &pstat->rc_entry[tid];
|
|
win_start = rc_entry->win_start;
|
|
win_end = (win_start + win_size) & 0xfff;
|
|
priv->pshare->rc_timer[priv->pshare->rc_timer_tail].pstat = NULL;
|
|
}
|
|
else {
|
|
sys_tick = TSF_DIFF(timeout, current_time);
|
|
if (sys_tick < 1)
|
|
sys_tick = 1;
|
|
mod_timer(&priv->pshare->rc_sys_timer, jiffies + sys_tick);
|
|
|
|
if (TSF_LESS(timeout, current_time))
|
|
DEBUG_ERR("Setup RC timer %d too late (now %d)\n", timeout, current_time);
|
|
|
|
RESTORE_INT(flags);
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return;
|
|
}
|
|
}
|
|
|
|
priv->pshare->rc_timer_tail = (priv->pshare->rc_timer_tail + 1) & (RC_TIMER_NUM - 1);
|
|
|
|
if (pstat) {
|
|
while (!(rc_entry->packet_q[win_start & (win_size - 1)]))
|
|
win_start = SN_NEXT(win_start);
|
|
|
|
while (rc_entry->packet_q[win_start & (win_size - 1)]) {
|
|
reorder_ctrl_pktout(priv_this, rc_entry->packet_q[win_start & (win_size - 1)], pstat);
|
|
rc_entry->packet_q[win_start & (win_size - 1)] = NULL;
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_passupi++;
|
|
#endif
|
|
win_start = SN_NEXT(win_start);
|
|
}
|
|
|
|
rc_entry->win_start = win_start;
|
|
|
|
if (SN_LESS(win_start, rc_entry->last_seq) || (win_start == rc_entry->last_seq)) {
|
|
rc_entry->rc_timer_id = reorder_ctrl_timer_add(priv_this, pstat, tid, 1) + 1;
|
|
if (rc_entry->rc_timer_id == 0)
|
|
reorder_ctrl_consumeQ(priv_this, pstat, tid, 0);
|
|
}
|
|
else {
|
|
rc_entry->start_rcv = FALSE;
|
|
rc_entry->rc_timer_id = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CIRC_CNT(priv->pshare->rc_timer_head, priv->pshare->rc_timer_tail, RC_TIMER_NUM)) {
|
|
sys_tick = (priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout - current_time);
|
|
if (sys_tick < 1)
|
|
sys_tick = 1;
|
|
mod_timer(&priv->pshare->rc_sys_timer, jiffies + sys_tick);
|
|
|
|
if (TSF_LESS(priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout, current_time))
|
|
DEBUG_ERR("Setup RC timer %d too late (now %d)\n", priv->pshare->rc_timer[priv->pshare->rc_timer_tail].timeout, current_time);
|
|
}
|
|
RESTORE_INT(flags);
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
}
|
|
|
|
|
|
/* ====================================================================================
|
|
segment 1 2 3 4
|
|
-----------------+--------------------------------+-------------------------
|
|
win_start win_end
|
|
+--------------------------------+
|
|
win_size
|
|
|
|
segment 1: drop this packet
|
|
segment 2: indicate this packet, then indicate the following packets until a hole
|
|
segment 3: queue this packet in corrosponding position
|
|
segment 4: indicate queued packets until SN_DIFF(seq, win_start)<win_size, then
|
|
queue this packet
|
|
====================================================================================*/
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
int check_win_seqment(unsigned short win_start, unsigned short win_end, unsigned short seq)
|
|
{
|
|
if (SN_LESS(seq, win_start))
|
|
return 1;
|
|
else if (seq == win_start)
|
|
return 2;
|
|
else if (SN_LESS(win_start, seq) && SN_LESS(seq, win_end))
|
|
return 3;
|
|
else
|
|
return 4;
|
|
}
|
|
|
|
|
|
__MIPS16
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
|
|
#ifndef CONFIG_RTK_MESH
|
|
static
|
|
#endif
|
|
int reorder_ctrl_check(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned short seq;
|
|
unsigned char tid;
|
|
int index, segment;
|
|
int win_start, win_size, win_end;
|
|
struct reorder_ctrl_entry *rc_entry;
|
|
#ifdef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
|
|
SMP_LOCK_REORDER_CTRL(flags);
|
|
|
|
seq = pfrinfo->seq;
|
|
tid = pfrinfo->tid;
|
|
rc_entry = &pstat->rc_entry[tid];
|
|
win_start = rc_entry->win_start;
|
|
win_size = priv->pmib->reorderCtrlEntry.ReorderCtrlWinSz;
|
|
win_end = (win_start + win_size) & 0xfff;
|
|
|
|
if (!pfrinfo->paggr && (rc_entry->start_rcv == FALSE))
|
|
{
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return TRUE;
|
|
}
|
|
|
|
if (rc_entry->start_rcv == FALSE)
|
|
{
|
|
rc_entry->start_rcv = TRUE;
|
|
rc_entry->win_start = SN_NEXT(seq);
|
|
rc_entry->last_seq = seq;
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
segment = check_win_seqment(win_start, win_end, seq);
|
|
if (segment == 1) {
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_drop1++;
|
|
#endif
|
|
//priv->ext_stats.rx_data_drops++;
|
|
//DEBUG_ERR("RX DROP: skb behind the window\n");
|
|
//rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
//return FALSE;
|
|
return TRUE;
|
|
}
|
|
else if (segment == 2) {
|
|
reorder_ctrl_pktout(priv, pfrinfo->pskb, pstat);
|
|
win_start = SN_NEXT(win_start);
|
|
while (rc_entry->packet_q[win_start & (win_size - 1)]) {
|
|
reorder_ctrl_pktout(priv, rc_entry->packet_q[win_start & (win_size - 1)], pstat);
|
|
rc_entry->packet_q[win_start & (win_size - 1)] = NULL;
|
|
win_start = SN_NEXT(win_start);
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_passup2++;
|
|
#endif
|
|
}
|
|
rc_entry->win_start = win_start;
|
|
if (SN_LESS(rc_entry->last_seq, seq))
|
|
rc_entry->last_seq = seq;
|
|
|
|
if (rc_entry->rc_timer_id)
|
|
priv->pshare->rc_timer[rc_entry->rc_timer_id - 1].pstat = NULL;
|
|
if (SN_LESS(rc_entry->last_seq, win_start))
|
|
rc_entry->rc_timer_id = 0;
|
|
else {
|
|
rc_entry->rc_timer_id = reorder_ctrl_timer_add(priv, pstat, tid, 0) + 1;
|
|
if (rc_entry->rc_timer_id == 0)
|
|
reorder_ctrl_consumeQ(priv, pstat, tid, 2);
|
|
}
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return FALSE;
|
|
}
|
|
else if (segment == 3) {
|
|
index = seq & (win_size - 1);
|
|
if (rc_entry->packet_q[index]) {
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_drop3++;
|
|
#endif
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: skb already in rc queue\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
rc_entry->packet_q[index] = pfrinfo->pskb;
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_reorder3++;
|
|
#endif
|
|
}
|
|
if (SN_LESS(rc_entry->last_seq, seq))
|
|
rc_entry->last_seq = seq;
|
|
if (rc_entry->rc_timer_id == 0) {
|
|
rc_entry->rc_timer_id = reorder_ctrl_timer_add(priv, pstat, tid, 0) + 1;
|
|
if (rc_entry->rc_timer_id == 0)
|
|
reorder_ctrl_consumeQ(priv, pstat, tid, 3);
|
|
}
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return FALSE;
|
|
}
|
|
else { // (segment == 4)
|
|
while ((SN_DIFF(seq, win_start) >= win_size) || (rc_entry->packet_q[win_start & (win_size - 1)])) {
|
|
if (rc_entry->packet_q[win_start & (win_size - 1)]) {
|
|
reorder_ctrl_pktout(priv, rc_entry->packet_q[win_start & (win_size - 1)], pstat);
|
|
rc_entry->packet_q[win_start & (win_size - 1)] = NULL;
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_passup4++;
|
|
#endif
|
|
}
|
|
win_start = SN_NEXT(win_start);
|
|
}
|
|
rc_entry->win_start = win_start;
|
|
|
|
index = seq & (win_size - 1);
|
|
if (rc_entry->packet_q[index]) {
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_drop4++;
|
|
#endif
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: skb already in rc queue\n");
|
|
rtl_kfree_skb(priv, rc_entry->packet_q[index], _SKB_RX_);
|
|
}
|
|
|
|
rc_entry->packet_q[index] = pfrinfo->pskb;
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
pstat->rx_rc_reorder4++;
|
|
#endif
|
|
rc_entry->last_seq = seq;
|
|
if (rc_entry->rc_timer_id)
|
|
priv->pshare->rc_timer[rc_entry->rc_timer_id - 1].pstat = NULL;
|
|
rc_entry->rc_timer_id = reorder_ctrl_timer_add(priv, pstat, tid, 0) + 1;
|
|
if (rc_entry->rc_timer_id == 0)
|
|
reorder_ctrl_consumeQ(priv, pstat, tid, 4);
|
|
SMP_UNLOCK_REORDER_CTRL(flags);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef RX_SHORTCUT
|
|
/*---------------------------------------------------------------
|
|
return value:
|
|
TRUE: MIC ok
|
|
FALSE: MIC error
|
|
----------------------------------------------------------------*/
|
|
static int wait_mic_done_and_compare(unsigned char *org_mic, unsigned char *tkipmic)
|
|
{
|
|
#ifdef NOT_RTK_BSP
|
|
return TRUE;
|
|
#else
|
|
register unsigned long int l,r;
|
|
int delay = 20;
|
|
|
|
while ((*(volatile unsigned int *)GDMAISR & GDMA_COMPIP) == 0) {
|
|
delay_us(delay);
|
|
delay = delay / 2;
|
|
}
|
|
|
|
l = *(volatile unsigned int *)GDMAICVL;
|
|
r = *(volatile unsigned int *)GDMAICVR;
|
|
|
|
tkipmic[0] = (unsigned char)(l & 0xff);
|
|
tkipmic[1] = (unsigned char)((l >> 8) & 0xff);
|
|
tkipmic[2] = (unsigned char)((l >> 16) & 0xff);
|
|
tkipmic[3] = (unsigned char)((l >> 24) & 0xff);
|
|
tkipmic[4] = (unsigned char)(r & 0xff);
|
|
tkipmic[5] = (unsigned char)((r >> 8) & 0xff);
|
|
tkipmic[6] = (unsigned char)((r >> 16) & 0xff);
|
|
tkipmic[7] = (unsigned char)((r >> 24) & 0xff);
|
|
|
|
return (memcmp(org_mic, tkipmic, 8) ? FALSE : TRUE);
|
|
#endif // NOT_RTK_BSP
|
|
}
|
|
|
|
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
int get_rx_sc_index(struct stat_info *pstat, unsigned char *pframe)
|
|
{
|
|
struct rx_sc_entry *prxsc_entry;
|
|
int i;
|
|
|
|
prxsc_entry = pstat->rx_sc_ent;
|
|
|
|
for (i=0; i<RX_SC_ENTRY_NUM; i++) {
|
|
if (!memcmp(GetAddr1Ptr(pframe), prxsc_entry[i].rx_wlanhdr.addr1, 18))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
int get_rx_sc_free_entry(struct stat_info *pstat, unsigned char *pframe)
|
|
{
|
|
struct rx_sc_entry *prxsc_entry;
|
|
int i;
|
|
|
|
i = get_rx_sc_index(pstat, pframe);
|
|
if (i >= 0)
|
|
return i;
|
|
|
|
prxsc_entry = pstat->rx_sc_ent;
|
|
|
|
for (i=0; i<RX_SC_ENTRY_NUM; i++) {
|
|
if (prxsc_entry[i].rx_payload_offset == 0)
|
|
return i;
|
|
}
|
|
|
|
// no free entry
|
|
i = pstat->rx_sc_replace_idx;
|
|
pstat->rx_sc_replace_idx = (++pstat->rx_sc_replace_idx) % RX_SC_ENTRY_NUM;
|
|
return i;
|
|
}
|
|
inline unsigned char sta_packet_number_check(struct rtl8192cd_priv *priv, union PN48 *last_RxPN, unsigned char *pframe, unsigned int hdr_len)
|
|
{
|
|
int ret = SUCCESS;
|
|
union PN48 rxPN;
|
|
|
|
if(!GetPrivacy(pframe)) {
|
|
return FAIL;
|
|
}
|
|
|
|
rxPN.val48 = 0;
|
|
rxPN._byte_.TSC0 = pframe[hdr_len];
|
|
rxPN._byte_.TSC1 = pframe[hdr_len+1];
|
|
rxPN._byte_.TSC2 = pframe[hdr_len+4];
|
|
rxPN._byte_.TSC3 = pframe[hdr_len+5];
|
|
rxPN._byte_.TSC4 = pframe[hdr_len+6];
|
|
rxPN._byte_.TSC5 = pframe[hdr_len+7];
|
|
|
|
if((last_RxPN->val48 + 1) != rxPN.val48) {
|
|
ret = FAIL;
|
|
} else {
|
|
last_RxPN->val48 = rxPN.val48;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifndef RTK_NL80211
|
|
const unsigned char rfc1042_header[WLAN_LLC_HEADER_SIZE]={0xaa,0xaa,0x03,00,00,00};
|
|
#else
|
|
//For OpenWRT, rfc1042_header is defined at compat-wireless/net/wireless/util.c
|
|
extern const unsigned char rfc1042_header[];
|
|
#endif
|
|
/*---------------------------------------------------------------
|
|
return value:
|
|
0: shortcut ok, rx data has passup
|
|
1: discard this packet
|
|
-1: can't do shortcut, data path should be continued
|
|
---------------------------------------------------------------*/
|
|
__MIPS16
|
|
#ifndef WIFI_MIN_IMEM_USAGE
|
|
__IRAM_IN_865X
|
|
#endif
|
|
int rx_shortcut(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
// unsigned long flags=0;
|
|
struct stat_info *pstat, *dst_pstat;
|
|
int privacy, tkip_mic_ret=0;
|
|
int payload_length, offset, pos=0, do_rc=0, idx;
|
|
struct wlan_ethhdr_t *e_hdr;
|
|
unsigned char rxmic[8], tkipmic[8];
|
|
struct sk_buff skb_copy;
|
|
unsigned char wlanhdr_copy[sizeof(struct wlanllc_hdr)];
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
unsigned char da[MACADDRLEN];
|
|
unsigned short tpcache=0;
|
|
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
struct path_sel_entry *pEntry = NULL;
|
|
struct MESH_HDR *meshHdrPt;
|
|
unsigned char meshDest[MACADDRLEN];
|
|
#endif
|
|
struct rx_sc_entry *prxsc_entry = NULL;
|
|
unsigned char is_qos_datafrm=0;
|
|
|
|
#ifdef HW_FILL_MACID //eric-8814
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
if(!pstat)
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
}
|
|
else
|
|
#endif
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
|
|
is_qos_datafrm = is_qos_data(pframe);
|
|
|
|
|
|
#if defined(CONFIG_RTK_MESH) && !defined(RX_RL_SHORTCUT)
|
|
|
|
// RTK mesh doesn't support shortcut now -- chris 071909.
|
|
if (GET_MIB(priv)->dot1180211sInfo.mesh_enable)
|
|
goto shouldnot_rxsc;
|
|
#endif
|
|
|
|
#if 0 // already flush cache in rtl8192cd_rx_isr()
|
|
#ifndef RTL8190_CACHABLE_CLUSTER
|
|
#ifdef __MIPSEB__
|
|
pframe = (UINT8 *)((unsigned long)pframe | 0x20000000);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
if (priv->pmib->dot11OperationEntry.guest_access
|
|
#ifdef CONFIG_RTL8186_KB
|
|
||(pstat && pstat->ieee8021x_ctrlport == DOT11_PortStatus_Guest)
|
|
#endif
|
|
)
|
|
goto shouldnot_rxsc;
|
|
|
|
if (pstat && ((idx = get_rx_sc_index(pstat, pframe)) >= 0))
|
|
prxsc_entry = &pstat->rx_sc_ent[idx];
|
|
|
|
if ((NULL != prxsc_entry) &&
|
|
prxsc_entry->rx_payload_offset &&
|
|
(GetFragNum(pframe) == 0) && (GetMFrag(pframe) == 0))
|
|
{
|
|
privacy = GetPrivacy(pframe);
|
|
memcpy(da, pfrinfo->da, MACADDRLEN);
|
|
|
|
tpcache = GetTupleCache(pframe);
|
|
#ifdef CLIENT_MODE
|
|
if (IS_MCAST(da))
|
|
{
|
|
if (tpcache == pstat->tpcache_mcast)
|
|
{
|
|
priv->ext_stats.rx_decache++;
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (is_qos_datafrm) {
|
|
pos = GetSequence(pframe) & (TUPLE_WINDOW - 1);
|
|
if (tpcache == pstat->tpcache[pfrinfo->tid][pos]) {
|
|
priv->ext_stats.rx_decache++;
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
if (GetRetry(pframe)) {
|
|
if (tpcache == pstat->tpcache_mgt) {
|
|
priv->ext_stats.rx_decache++;
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check wlan header
|
|
if (pstat->rx_privacy == privacy)
|
|
{
|
|
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
if (pfrinfo->is_11s) {
|
|
if(mesh_shortcut_update(priv, pfrinfo, pstat, idx, &pEntry, &meshHdrPt) != 0) {
|
|
goto shouldnot_rxsc;
|
|
}
|
|
|
|
if(pEntry == NULL) {
|
|
memcpy(meshDest, meshHdrPt->DestMACAddr, MACADDRLEN);/*backup mesh addr5 */
|
|
}
|
|
pfrinfo->pskb->dev = priv->mesh_dev;
|
|
}
|
|
else
|
|
|
|
#endif //CONFIG_RTK_MESH
|
|
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds == 3
|
|
#ifdef CONFIG_RTK_MESH
|
|
&& priv->pmib->dot11WdsInfo.wdsEnabled
|
|
#endif
|
|
) {
|
|
if (memcmp(GetAddr4Ptr(pframe), prxsc_entry->rx_wlanhdr.addr4, 6))
|
|
goto shouldnot_rxsc;
|
|
pfrinfo->pskb->dev = getWdsDevByAddr(priv, GetAddr2Ptr(pframe));
|
|
}
|
|
else
|
|
#endif
|
|
|
|
#ifdef A4_STA
|
|
if (pfrinfo->to_fr_ds == 3 && (pstat->state & WIFI_A4_STA)) {
|
|
if (memcmp(GetAddr4Ptr(pframe), prxsc_entry->rx_wlanhdr.addr4, 6))
|
|
goto shouldnot_rxsc;
|
|
a4_sta_add(priv, pstat, GetAddr4Ptr(pframe));
|
|
}
|
|
#endif
|
|
pfrinfo->pskb->dev = priv->dev;
|
|
|
|
offset = prxsc_entry->rx_payload_offset + sizeof(rfc1042_header);
|
|
|
|
/*
|
|
printk("pstat->rx_payload_offset = %02x, 0xaa, cmp = %d \n",pframe[prxsc_entry->rx_payload_offset],
|
|
memcmp(&pframe[prxsc_entry->rx_payload_offset], rfc1042_header, 6));
|
|
printk("pstat->rx_ethhdr.type = %02x, pframe[offset] = %02x, cmp= %d \n", prxsc_entry->rx_ethhdr.type, pframe[offset],
|
|
memcmp(&prxsc_entry->rx_ethhdr.type,&pframe[offset], 2));
|
|
*/
|
|
// check snap header
|
|
if (memcmp(&pframe[prxsc_entry->rx_payload_offset], rfc1042_header, 6) ||
|
|
memcmp(&prxsc_entry->rx_ethhdr.type,&pframe[offset], 2))
|
|
goto shouldnot_rxsc;
|
|
|
|
payload_length = pfrinfo->pktlen - offset - prxsc_entry->rx_trim_pad - 2;
|
|
if (payload_length < WLAN_ETHHDR_LEN)
|
|
goto shouldnot_rxsc;
|
|
|
|
if (privacy)
|
|
{
|
|
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds == 3
|
|
#ifdef CONFIG_RTK_MESH
|
|
&& priv->pmib->dot11WdsInfo.wdsEnabled
|
|
#endif
|
|
)
|
|
privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
|
|
|
|
else
|
|
#endif
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
|
|
#ifdef CONFIG_RTL_WAPI_SUPPORT
|
|
if (privacy==_WAPI_SMS4_)
|
|
{
|
|
/* Decryption */
|
|
if (SecSWSMS4Decryption(priv, pstat, pfrinfo) == FAIL)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: WAPI decrpt error!\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return 1;
|
|
}
|
|
pframe = get_pframe(pfrinfo);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (privacy == _TKIP_PRIVACY_)
|
|
{
|
|
memcpy((void *)rxmic, (void *)(pframe + pfrinfo->pktlen - 8 - 4), 8); // 8 michael, 4 icv
|
|
//SAVE_INT_AND_CLI(flags);
|
|
tkip_mic_ret = tkip_rx_mic(priv, pframe, pfrinfo->da, pfrinfo->sa,
|
|
pfrinfo->tid, pframe + pfrinfo->hdr_len + 8,
|
|
pfrinfo->pktlen - pfrinfo->hdr_len - 8 - 8 - 4, tkipmic, 1); // 8 IV, 8 Mic, 4 ICV
|
|
if (tkip_mic_ret) { // MIC completed
|
|
//RESTORE_INT(flags);
|
|
if (memcmp(rxmic, tkipmic, 8)) {
|
|
goto shouldnot_rxsc;
|
|
}
|
|
}
|
|
else {
|
|
memcpy(&skb_copy, pfrinfo->pskb, sizeof(skb_copy));
|
|
memcpy(wlanhdr_copy, pframe, sizeof(wlanhdr_copy));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) &&
|
|
priv->pmib->reorderCtrlEntry.ReorderCtrlEnable) {
|
|
if (!IS_MCAST(GetAddr1Ptr(pframe)))
|
|
do_rc = 1;
|
|
}
|
|
|
|
rx_sum_up(NULL, pstat, pfrinfo->pktlen, 0);
|
|
pstat->rx_sc_pkts++;
|
|
|
|
priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
|
|
|
|
update_sta_rssi(priv, pstat, pfrinfo);
|
|
|
|
#ifdef DETECT_STA_EXISTANCE
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
if (pstat->leave!= 0)
|
|
RTL8188E_MACID_NOLINK(priv, 0, REMAP_AID(pstat));
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
{
|
|
if (pstat->leave!= 0)
|
|
{
|
|
#if defined(CONFIG_PCI_HCI)
|
|
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
|
|
pstat->bDrop = 0;
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_update_sta_msr(priv, pstat, INCREASE);
|
|
#endif
|
|
}
|
|
pstat->rx_last_good_time = priv->up_time;
|
|
}
|
|
#endif //#ifdef CONFIG_WLAN_HAL
|
|
|
|
pstat->leave = 0;
|
|
#endif
|
|
|
|
//printk("RXSC\n");
|
|
|
|
#ifdef SUPPORT_SNMP_MIB
|
|
if (IS_MCAST(da))
|
|
SNMP_MIB_INC(dot11MulticastReceivedFrameCount, 1);
|
|
#endif
|
|
|
|
/* chop 802.11 header from skb. */
|
|
//skb_put(pfrinfo->pskb, pfrinfo->pktlen); // pskb->tail will be wrong
|
|
pfrinfo->pskb->tail = pfrinfo->pskb->data + pfrinfo->pktlen;
|
|
pfrinfo->pskb->len = pfrinfo->pktlen;
|
|
|
|
skb_pull(pfrinfo->pskb, offset+2);
|
|
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
|
|
if (pfrinfo->is_11s && pEntry == NULL) {
|
|
skb_pull(pfrinfo->pskb, 16); //because we guarantee only 6 address frame enters shortcut
|
|
payload_length -= 16;
|
|
}
|
|
#endif
|
|
|
|
e_hdr = (struct wlan_ethhdr_t *)skb_push(pfrinfo->pskb, WLAN_ETHHDR_LEN);
|
|
memcpy((unsigned char *)e_hdr, (unsigned char *)&prxsc_entry->rx_ethhdr, sizeof(struct wlan_ethhdr_t));
|
|
/* chop off the 802.11 CRC */
|
|
|
|
skb_trim(pfrinfo->pskb, payload_length + WLAN_ETHHDR_LEN);
|
|
|
|
|
|
//printk("RXSC skb_pull offset+2 = %d\n", offset+2);
|
|
//printk("RXSC pstat->rx_ethhdr dest= %02x\n", e_hdr->daddr[5]);
|
|
//printk("RXSC pstat->rx_ethhdr src = %02x\n", e_hdr->saddr[5]);
|
|
|
|
if ((privacy == _TKIP_PRIVACY_) && (tkip_mic_ret == FALSE)) {
|
|
if (wait_mic_done_and_compare(rxmic, tkipmic) == FALSE) {
|
|
// RESTORE_INT(flags);
|
|
memcpy(pfrinfo->pskb, &skb_copy, sizeof(skb_copy));
|
|
memcpy(pframe, wlanhdr_copy, sizeof(wlanhdr_copy));
|
|
goto shouldnot_rxsc;
|
|
}
|
|
// RESTORE_INT(flags);
|
|
}
|
|
|
|
#ifdef CLIENT_MODE
|
|
if (IS_MCAST(da))
|
|
pstat->tpcache_mcast = tpcache;
|
|
else
|
|
#endif
|
|
if (is_qos_datafrm)
|
|
pstat->tpcache[pfrinfo->tid][pos] = tpcache;
|
|
else
|
|
pstat->tpcache_mgt = tpcache;
|
|
|
|
if (OPMODE & WIFI_AP_STATE)
|
|
{
|
|
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
pfrinfo->pskb->cb[3] = 0;
|
|
if (pfrinfo->is_11s ) {/* from wlan0-msh0*/
|
|
if(pEntry) {/* to wlan0-msh0*/
|
|
meshHdrPt->TTL--;
|
|
if(1 > meshHdrPt->TTL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: TTL=0\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return 0;
|
|
}
|
|
dst_pstat = get_stainfo(pEntry->priv, pEntry->nexthopMAC);
|
|
if(dst_pstat) {
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = dst_pstat;
|
|
pfrinfo->pskb->cb[3] = RELAY_11S;
|
|
pfrinfo->pskb->dev = pEntry->priv->dev; /*temprarily save the priv to nexthop*/
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo) == FALSE) {
|
|
do_rc = 0;
|
|
}
|
|
} else {
|
|
do_rc = 1;
|
|
}
|
|
|
|
|
|
if(do_rc) {
|
|
struct tx_insn txcfg;
|
|
txcfg.priv = pEntry->priv;
|
|
txcfg.is_11s = RELAY_11S;
|
|
pfrinfo->pskb->dev = priv->mesh_dev;
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
rtl_atomic_inc(&priv->rtl_tx_skb_cnt);
|
|
#endif
|
|
__rtl8192cd_start_xmit_out(pfrinfo->pskb, dst_pstat, &txcfg);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
else { /*to wlan0 or eth0*/
|
|
dst_pstat = get_stainfo(priv, meshDest);/*mesh addr5*/
|
|
}
|
|
}
|
|
else { /*from wlan0*/
|
|
dst_pstat = get_stainfo(priv, da);
|
|
if(dst_pstat == NULL) {
|
|
int index = 0;
|
|
#ifdef CONFIG_RTL_MESH_CROSSBAND
|
|
index = (priv->dev->name[4] == '0')?1:0;
|
|
#endif
|
|
if(cached_mesh_dev[index] && !memcmp(da, cached_mesh_mac[index], MACADDRLEN)) {/*to wlan0-msh0*/
|
|
#ifdef CONFIG_RTL_MESH_CROSSBAND
|
|
pfrinfo->pskb->dev = priv->mesh_priv_sc->dev;
|
|
#else
|
|
pfrinfo->pskb->dev = priv->mesh_priv_first->dev;
|
|
#endif
|
|
|
|
if (do_rc) {
|
|
pfrinfo->pskb->cb[4] = 1;
|
|
pfrinfo->pskb->cb[3] = XMIT_11S;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo) == FALSE) {
|
|
do_rc = 0;
|
|
}
|
|
}
|
|
else
|
|
do_rc = 1;
|
|
|
|
if(do_rc) {
|
|
DECLARE_TXINSN(txcfg);
|
|
if(dot11s_datapath_decision(pfrinfo->pskb, &txcfg, 1) != 0) {
|
|
dst_pstat = get_stainfo(txcfg.priv, txcfg.nhop_11s);
|
|
pfrinfo->pskb->dev = priv->mesh_dev;
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
rtl_atomic_inc(&priv->rtl_tx_skb_cnt);
|
|
#endif
|
|
__rtl8192cd_start_xmit_out(pfrinfo->pskb, dst_pstat, &txcfg);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
dst_pstat = get_stainfo(priv, da);
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef A4_STA
|
|
if (priv->pshare->rf_ft_var.a4_enable && (dst_pstat == NULL))
|
|
dst_pstat = a4_sta_lookup(priv, da);
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(WDS)
|
|
if ((pfrinfo->to_fr_ds==3
|
|
#ifdef CONFIG_RTK_MESH
|
|
&& priv->pmib->dot11WdsInfo.wdsEnabled
|
|
#endif
|
|
) ||
|
|
(dst_pstat == NULL) || !(dst_pstat->state & WIFI_ASOC_STATE))
|
|
#else
|
|
if ((dst_pstat == NULL) || (!(dst_pstat->state & WIFI_ASOC_STATE)))
|
|
#endif
|
|
{
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = 0;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo)) {
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
}
|
|
else
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
#ifdef HS2_SUPPORT
|
|
/* Hotspot 2.0 Release 1 */
|
|
else if (priv->pmib->dot11OperationEntry.block_relay == 3) { // with l2_inspect
|
|
unsigned short protocol;
|
|
|
|
HS2_DEBUG_INFO("%s block_relay=3\n");
|
|
if(IS_ICMPV4_PROTO(pfrinfo->pskb->data)) {
|
|
if(IS_ICMPV4_ECHO_TYPE(pfrinfo->pskb->data)) {
|
|
if(priv->pmib->hs2Entry.ICMPv4ECHO == 2) {
|
|
memcpy(&pfrinfo->pskb->data[0], priv->pmib->hs2Entry.redir_mac, 6);
|
|
HS2_DEBUG_INFO("redirect ICMPv4 Packet to connected portal\n");
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
} else if(priv->pmib->hs2Entry.ICMPv4ECHO == 0) {
|
|
HS2_DEBUG_INFO("Drop ICMPv4 Packet\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
/*
|
|
else if(priv->pmib->hs2Entry.ICMPv4ECHO == 1) {
|
|
panic_printk("Allow ICMPv4 Echo Requests\n");
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = (unsigned int)dst_pstat; // backup pstat pointer
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, isMeshPoint(dst_pstat)? priv->mesh_dev: priv->dev))
|
|
#else
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, priv->dev))
|
|
#endif
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_TX_);
|
|
}
|
|
*/
|
|
return 1;
|
|
} else {
|
|
//free
|
|
}
|
|
} else {
|
|
//free
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
if (priv->pmib->dot11OperationEntry.block_relay == 1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Relay unicast packet is blocked in shortcut!\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return 1;
|
|
}
|
|
else if (priv->pmib->dot11OperationEntry.block_relay == 2) {
|
|
DEBUG_INFO("Relay unicast packet is blocked! Indicate to bridge in shortcut\n");
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
else {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#ifdef GBWC
|
|
if (GBWC_forward_check(priv, pfrinfo->pskb, pstat)) {
|
|
// packet is queued, nothing to do
|
|
}
|
|
else
|
|
#endif
|
|
if (do_rc) {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = (unsigned int)dst_pstat; // backup pstat pointer
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo)) {
|
|
#ifdef TX_SCATTER
|
|
pfrinfo->pskb->list_num = 0;
|
|
#endif
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, priv->dev))
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_TX_);
|
|
}
|
|
}
|
|
else {
|
|
#ifdef TX_SCATTER
|
|
pfrinfo->pskb->list_num = 0;
|
|
#endif
|
|
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, priv->dev))
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_TX_);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
|
|
priv->rxDataNumInPeriod++;
|
|
if (IS_MCAST(pfrinfo->pskb->data)) {
|
|
priv->rxMlcstDataNumInPeriod++;
|
|
} else if ((OPMODE & WIFI_STATION_STATE) && (priv->ps_state)) {
|
|
if ((GetFrameSubType(pframe) == WIFI_DATA)
|
|
#ifdef WIFI_WMM
|
|
||(QOS_ENABLE && pstat->QosEnabled && (GetFrameSubType(pframe) == WIFI_QOS_DATA))
|
|
#endif
|
|
) {
|
|
if (GetMData(pframe)) {
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if (QOS_ENABLE && APSD_ENABLE && priv->uapsd_assoc) {
|
|
if (!((priv->pmib->dot11QosEntry.UAPSD_AC_BE && ((pfrinfo->tid == 0) || (pfrinfo->tid == 3))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_BK && ((pfrinfo->tid == 1) || (pfrinfo->tid == 2))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_VI && ((pfrinfo->tid == 4) || (pfrinfo->tid == 5))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_VO && ((pfrinfo->tid == 6) || (pfrinfo->tid == 7)))))
|
|
issue_PsPoll(priv);
|
|
} else
|
|
#endif
|
|
{
|
|
issue_PsPoll(priv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef RTK_BR_EXT
|
|
if (!priv->pmib->ethBrExtInfo.nat25sc_disable &&
|
|
!(pfrinfo->pskb->data[0] & 1) &&
|
|
*((unsigned short *)(pfrinfo->pskb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP) &&
|
|
!memcmp(priv->scdb_ip, pfrinfo->pskb->data+ETH_HLEN+16, 4)) {
|
|
memcpy(pfrinfo->pskb->data, priv->scdb_mac, ETH_ALEN);
|
|
#ifdef MULTI_MAC_CLONE
|
|
mclone_dhcp_caddr(priv, pfrinfo->pskb);
|
|
#endif
|
|
}
|
|
else
|
|
if(nat25_handle_frame(priv, pfrinfo->pskb) == -1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: nat25_handle_frame fail in shortcut!\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return 1;
|
|
}
|
|
#endif
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = 0;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo))
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
else
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
return 0;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Non supported mode in process_datafrme in shortcut\n");
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
shouldnot_rxsc:
|
|
|
|
if (pstat)
|
|
pstat->rx_sc_pkts_slow++;
|
|
return -1;
|
|
}
|
|
#endif // RX_SHORTCUT
|
|
|
|
|
|
#ifdef DRVMAC_LB
|
|
void lb_convert(struct rtl8192cd_priv *priv, unsigned char *pframe)
|
|
{
|
|
unsigned char *addr1, *addr2, *addr3;
|
|
|
|
if (get_tofr_ds(pframe) == 0x01)
|
|
{
|
|
SetToDs(pframe);
|
|
ClearFrDs(pframe);
|
|
addr1 = GetAddr1Ptr(pframe);
|
|
addr2 = GetAddr2Ptr(pframe);
|
|
addr3 = GetAddr3Ptr(pframe);
|
|
if (addr1[0] & 0x01) {
|
|
memcpy(addr3, addr1, 6);
|
|
memcpy(addr1, addr2, 6);
|
|
memcpy(addr2, priv->pmib->miscEntry.lb_da, 6);
|
|
}
|
|
else {
|
|
memcpy(addr1, addr2, 6);
|
|
memcpy(addr2, priv->pmib->miscEntry.lb_da, 6);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
Strip from "validate_mpdu()"
|
|
|
|
0: no reuse, allocate new skb due to the current is queued.
|
|
1: reuse! due to error pkt or short pkt.
|
|
*/
|
|
static int rtl8192cd_rx_procCtrlPkt(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo
|
|
#ifdef MBSSID
|
|
,int vap_idx
|
|
#endif
|
|
)
|
|
{
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
struct stat_info *pstat = NULL;
|
|
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
if (((GetFrameSubType(pframe)) != WIFI_PSPOLL) ||
|
|
(pfrinfo->to_fr_ds != 0x00))
|
|
return 1;
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable && (vap_idx >= 0))
|
|
{
|
|
priv = priv->pvap_priv[vap_idx];
|
|
if (!(OPMODE & WIFI_AP_STATE))
|
|
return 1;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (!(OPMODE & WIFI_AP_STATE)) {
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
priv = GET_VXD_PRIV(priv);
|
|
else
|
|
return 1;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (!IS_BSSID(priv, GetAddr1Ptr(pframe)))
|
|
return 1;
|
|
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
// check power save state
|
|
|
|
if (pstat != NULL)
|
|
{
|
|
#ifdef HW_DETEC_POWER_STATE
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
// 8813 power state control only by HW, not by SW.
|
|
// Only if HW detect macid not ready, SW patch this packet
|
|
if(pfrinfo->macid == HW_MACID_SEARCH_NOT_READY)
|
|
{
|
|
printk("%s %d HW_MACID_SEARCH_NOT_READY",__FUNCTION__,__LINE__);
|
|
if(priv->pshare->HWPwrStateUpdate[pstat->aid]==false)
|
|
{
|
|
printk("%s %d HW not update By SW Aid = %x \n",__FUNCTION__,__LINE__,pstat->aid);
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
else if(pfrinfo->macid > HW_MACID_SEARCH_SUPPORT_NUM)
|
|
{
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
} else
|
|
#endif // #ifdef HW_DETEC_POWER_STATE
|
|
{
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
} else
|
|
return 1;
|
|
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_ctrlframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_CTRL(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_ctrllist));
|
|
SMP_UNLOCK_RX_CTRL(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int rtl8192cd_rx_procNullPkt(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo
|
|
#ifdef MBSSID
|
|
,int vap_idx
|
|
#endif
|
|
)
|
|
{
|
|
unsigned char *sa = pfrinfo->sa;
|
|
struct stat_info *pstat = NULL;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
#ifdef SMP_SYNC
|
|
unsigned long x;
|
|
#endif
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, sa);
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if ((pstat == NULL) && IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(GET_VXD_PRIV(priv), sa);
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
if (pstat)
|
|
priv = GET_VXD_PRIV(priv);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
if ((pstat == NULL)
|
|
&& GET_ROOT(priv)->pmib->miscEntry.vap_enable
|
|
&& (vap_idx >= 0)) {
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv->pvap_priv[vap_idx], sa);
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
if (pstat)
|
|
priv = priv->pvap_priv[vap_idx];
|
|
}
|
|
#endif
|
|
|
|
if (pstat && (pstat->state & WIFI_ASOC_STATE)
|
|
&& (!(OPMODE & WIFI_AP_STATE) || IS_BSSID(priv, GetAddr1Ptr(pframe)))) {
|
|
#ifdef DRVMAC_LB
|
|
rx_sum_up(priv, pstat, pfrinfo->pktlen, 0);
|
|
#else
|
|
rx_sum_up(NULL, pstat, pfrinfo->pktlen, 0);
|
|
#endif
|
|
update_sta_rssi(priv, pstat, pfrinfo);
|
|
|
|
#ifdef DETECT_STA_EXISTANCE
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
if (pstat->leave!= 0)
|
|
RTL8188E_MACID_NOLINK(priv, 0, REMAP_AID(pstat));
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
{
|
|
if (pstat->leave!= 0)
|
|
{
|
|
#if defined(CONFIG_PCI_HCI)
|
|
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
|
|
pstat->bDrop = 0;
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_update_sta_msr(priv, pstat, INCREASE);
|
|
#endif
|
|
}
|
|
pstat->rx_last_good_time = priv->up_time;
|
|
}
|
|
#endif //#ifdef CONFIG_WLAN_HAL
|
|
|
|
pstat->leave = 0;
|
|
#endif
|
|
|
|
// check power save state
|
|
#ifndef DRVMAC_LB
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#ifdef HW_DETEC_POWER_STATE
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
// 8813 power state control only by HW, not by SW.
|
|
// Only if HW detect macid not ready, SW patch this packet
|
|
if(pfrinfo->macid == HW_MACID_SEARCH_NOT_READY)
|
|
{
|
|
printk("%s %d HW_MACID_SEARCH_NOT_READY",__FUNCTION__,__LINE__);
|
|
if(priv->pshare->HWPwrStateUpdate[pstat->aid]==false)
|
|
{
|
|
printk("%s %d HW not update By SW Aid = %x \n",__FUNCTION__,__LINE__,pstat->aid);
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
else if(pfrinfo->macid > HW_MACID_SEARCH_SUPPORT_NUM)
|
|
{
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
else
|
|
#endif // #ifdef HW_DETEC_POWER_STATE
|
|
{
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef MULTI_MAC_CLONE
|
|
int idx = mclone_find_address(priv, pfrinfo->sa, NULL, MAC_CLONE_SA_FIND);
|
|
if (idx >= 0)
|
|
{
|
|
struct rtl8192cd_priv *priv_backup;
|
|
struct stat_info *pstat_backup;
|
|
priv_backup = priv;
|
|
pstat_backup = pstat;
|
|
priv = priv->pshare->mclone_sta[idx-1].priv;
|
|
pstat = get_stainfo(priv, BSSID);
|
|
if (pstat)
|
|
{
|
|
ACTIVE_ID = idx;
|
|
issue_NullData(priv, pstat->hwaddr);
|
|
}
|
|
priv = priv_backup;
|
|
pstat = pstat_backup;
|
|
}
|
|
#endif
|
|
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if ((QOS_ENABLE)
|
|
#ifndef DRVMAC_LB
|
|
&& (APSD_ENABLE)
|
|
#endif
|
|
&& (OPMODE & WIFI_AP_STATE) && pstat
|
|
#ifndef DRVMAC_LB
|
|
&& (pstat->state & WIFI_SLEEP_STATE)
|
|
#endif
|
|
&& (pstat->QosEnabled)
|
|
#ifndef DRVMAC_LB
|
|
&& (pstat->apsd_bitmap & 0x0f)
|
|
#endif
|
|
&& ((GetFrameSubType(pframe)) == (WIFI_DATA_NULL | BIT(7)))) {
|
|
unsigned char *bssid = GetAddr1Ptr(pframe);
|
|
if (IS_BSSID(priv, bssid))
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* special case for mobile wifi. the mobile insleep will send
|
|
null data to AP after AP's reboot. if not deauthed, the client will not reconnect */
|
|
if (pstat == NULL) {
|
|
if (OPMODE & WIFI_AP_STATE)
|
|
issue_deauth(priv,GetAddr2Ptr(pframe), _RSON_UNSPECIFIED_);
|
|
return 1;
|
|
}
|
|
|
|
// for AR5007 IOT ISSUE
|
|
if ((!GetPwrMgt(pframe)) && (GetTupleCache(pframe) == 0) // because this is special case for AR5007, so use GetTupleCache with Seq-Num and Frag-Num, GetSequenceis also ok
|
|
&& (OPMODE & WIFI_AP_STATE) && (IS_BSSID(priv, GetAddr1Ptr(pframe)))
|
|
&& (((GetFrameSubType(pframe)) == WIFI_DATA_NULL)
|
|
#ifdef WIFI_WMM
|
|
|| ((QOS_ENABLE) && ((GetFrameSubType(pframe)) == (WIFI_DATA_NULL | BIT(7))))
|
|
#endif
|
|
)
|
|
) {
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
DEBUG_INFO("special Null Data in%d \n", pfrinfo->tid);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
// for AR5007 IOT ISSUE
|
|
static void rtl8192cd_rx_handle_Spec_Null_Data(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *sa;
|
|
struct stat_info *pstat = NULL;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
sa = pfrinfo->sa;
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, sa);
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
if (pstat==NULL) {
|
|
goto out;
|
|
}
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
if ((!GetPwrMgt(pframe)) && (GetTupleCache(pframe) == 0) // because this is special case for AR5007, so use GetTupleCache with Seq-Num and Frag-Num, GetSequenceis also ok
|
|
&& (OPMODE & WIFI_AP_STATE) && (IS_BSSID(priv, GetAddr1Ptr(pframe))))
|
|
{
|
|
int i,j;
|
|
|
|
DEBUG_INFO("tpcache should be reset: %d\n", pfrinfo->tid);
|
|
for (i=0; i<8; i++)
|
|
for (j=0; j<TUPLE_WINDOW; j++)
|
|
pstat->tpcache[i][j] = 0xffff;
|
|
}
|
|
out:
|
|
RESTORE_INT(flags);
|
|
}
|
|
|
|
|
|
#ifdef RTK_NL80211 // wrt-adhoc
|
|
#ifdef UNIVERSAL_REPEATER
|
|
unsigned char is_vxd_bssid(struct rtl8192cd_priv *priv, unsigned char *bssid)
|
|
{
|
|
struct rtl8192cd_priv * priv_root = NULL;
|
|
struct rtl8192cd_priv * priv_vxd = NULL;
|
|
unsigned char ret = 0;
|
|
|
|
if(!IS_VXD_INTERFACE(priv))
|
|
{
|
|
priv_root = GET_ROOT(priv);
|
|
priv_vxd = GET_VXD_PRIV(priv_root);
|
|
}
|
|
|
|
if((netif_running(priv_vxd->dev)) &&
|
|
(priv_vxd->pmib->dot11OperationEntry.opmode & WIFI_ADHOC_STATE))
|
|
{
|
|
if(!memcmp(bssid, priv_vxd->pmib->dot11StationConfigEntry.dot11Bssid, 6))
|
|
ret = 1;
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
Check the "to_fr_ds" field:
|
|
|
|
FromDS = 0
|
|
ToDS = 0
|
|
*/
|
|
static int rtl8192cd_rx_dispatch_mgmt_adhoc(struct rtl8192cd_priv **priv_p, struct rx_frinfo *pfrinfo
|
|
#ifdef MBSSID
|
|
,int vap_idx
|
|
#endif
|
|
)
|
|
{
|
|
int reuse = 1;
|
|
struct rtl8192cd_priv *priv = *priv_p;
|
|
unsigned int opmode = OPMODE;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
int retry=GetRetry(pframe);/*in case of skb has been freed*/
|
|
unsigned int frtype = GetFrameType(pframe);
|
|
unsigned char *da = pfrinfo->da;
|
|
unsigned char *bssid = GetAddr3Ptr(pframe);
|
|
unsigned short frame_type = GetFrameSubType(pframe);
|
|
#ifdef MBSSID
|
|
int i;
|
|
#endif
|
|
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
if ((GetMFrag(pframe)) && (frtype == WIFI_MGT_TYPE))
|
|
goto out;
|
|
|
|
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
|
|
// If mgt packet & (beacon or prob-rsp), put in root interface Q
|
|
// then it will be handled by root & virtual interface
|
|
// If mgt packet & (prob-req), put in AP interface Q
|
|
// If mgt packet & (others), check BSSID (addr3) for matched interface
|
|
|
|
if (frtype == WIFI_MGT_TYPE) {
|
|
int vxd_interface_ready=1, vap_interface_ready=0;
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (!IS_DRV_OPEN(GET_VXD_PRIV(priv)) ||
|
|
((opmode & WIFI_STATION_STATE) && !(GET_VXD_PRIV(priv)->drv_state & DRV_STATE_VXD_AP_STARTED)))
|
|
vxd_interface_ready = 0;
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
// if (opmode & WIFI_AP_STATE) {
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i]))
|
|
vap_interface_ready = 1;
|
|
}
|
|
}
|
|
// }
|
|
#endif
|
|
|
|
if (!vxd_interface_ready && !vap_interface_ready)
|
|
goto put_in_que;
|
|
|
|
#if 0
|
|
if (frame_type == WIFI_BEACON || frame_type == WIFI_PROBERSP) {
|
|
pfrinfo->is_br_mgnt = 1;
|
|
goto put_in_que;
|
|
}
|
|
#endif
|
|
|
|
if (frame_type == WIFI_PROBEREQ) {
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable)
|
|
{
|
|
if (vap_interface_ready) {
|
|
pfrinfo->is_br_mgnt = 1;
|
|
goto put_in_que;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (opmode & WIFI_STATION_STATE) {
|
|
if (!vxd_interface_ready) goto out;
|
|
priv = GET_VXD_PRIV(priv);
|
|
opmode = OPMODE;
|
|
goto put_in_que;
|
|
}
|
|
#endif
|
|
}
|
|
else { // not (Beacon, Probe-rsp, probe-rsp)
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable)
|
|
{
|
|
if (vap_idx >= 0) {
|
|
if (frame_type == WIFI_BEACON && priv->ss_req_ongoing)
|
|
{
|
|
pfrinfo->is_br_mgnt = 1;
|
|
goto put_in_que;//goto root interface
|
|
}
|
|
|
|
priv = priv->pvap_priv[vap_idx];
|
|
opmode = OPMODE;
|
|
goto put_in_que;
|
|
}
|
|
}
|
|
#endif
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
if (frame_type == WIFI_BEACON || frame_type == WIFI_PROBERSP) {
|
|
pfrinfo->is_br_mgnt = 1;
|
|
goto put_in_que;
|
|
}
|
|
}
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (vxd_interface_ready && !memcmp(GET_VXD_PRIV(priv)->pmib->dot11Bss.bssid, bssid, MACADDRLEN)) {
|
|
priv = GET_VXD_PRIV(priv);
|
|
opmode = OPMODE;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if defined(RTK_NL80211) && !defined(NON_NL80211_WPAS) // wrt-adhoc
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (frtype != WIFI_MGT_TYPE)
|
|
if (memcmp(bssid, "\x0\x0\x0\x0\x0\x0", MACADDRLEN) &&
|
|
is_vxd_bssid(priv, bssid))
|
|
{
|
|
unsigned char *sa = pfrinfo->sa;
|
|
|
|
priv = GET_VXD_PRIV(priv);
|
|
#if 0
|
|
printk(" VXD_ADHOC Rx data packets !! \n");
|
|
dump_mac_rx(da);
|
|
dump_mac_rx(sa);
|
|
#endif
|
|
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
|
|
goto out;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
put_in_que:
|
|
#endif // UNIVERSAL_REPEATER || MBSSID
|
|
|
|
if (opmode & WIFI_AP_STATE)
|
|
{
|
|
if (IS_MCAST(da))
|
|
{
|
|
// For AP mode, if DA == MCAST, then BSSID should be also MCAST
|
|
if (IS_MCAST(bssid))
|
|
reuse = 0;
|
|
|
|
// support 11A
|
|
else if (priv->pmib->dot11BssType.net_work_type & (WIRELESS_11G|WIRELESS_11A))
|
|
reuse = 0;
|
|
|
|
#ifdef WDS
|
|
else if (priv->pmib->dot11WdsInfo.wdsEnabled)
|
|
reuse = 0;
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
else if (GET_MIB(priv)->dot1180211sInfo.mesh_enable)
|
|
reuse = 0;
|
|
#endif
|
|
|
|
else if (opmode & WIFI_SITE_MONITOR)
|
|
reuse = 0;
|
|
|
|
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
|
|
else if (pfrinfo->is_br_mgnt && reuse)
|
|
reuse = 0;
|
|
#endif
|
|
|
|
else
|
|
{}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID
|
|
* Action frame is an exception (for bcm iot), do not check bssid
|
|
*/
|
|
if (IS_BSSID(priv, da) && ((IS_BSSID(priv, bssid) || (frame_type == WIFI_WMM_ACTION))
|
|
#ifdef CONFIG_RTK_MESH
|
|
|| (GET_MIB(priv)->dot1180211sInfo.mesh_enable
|
|
&& (!memcmp(bssid, pfrinfo->sa, MACADDRLEN)) /*mesh's management frame: A3 = A2 = TA*/
|
|
&& (frtype == WIFI_MGT_TYPE))
|
|
#endif
|
|
)) {
|
|
|
|
|
|
reuse = 0;
|
|
}
|
|
else if (opmode & WIFI_SITE_MONITOR)
|
|
reuse = 0;
|
|
|
|
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
|
|
else if (pfrinfo->is_br_mgnt && reuse)
|
|
reuse = 0;
|
|
#endif
|
|
#ifdef WDS
|
|
else if (priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum)
|
|
reuse = 0;
|
|
#endif
|
|
|
|
else
|
|
{}
|
|
}
|
|
|
|
if (!reuse) {
|
|
if (frtype == WIFI_MGT_TYPE)
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
#if defined(CONFIG_PCI_HCI)
|
|
rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_recv_mgnt_frame(priv, pfrinfo);
|
|
#endif
|
|
#else
|
|
SMP_LOCK_RX_MGT(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_mgtlist));
|
|
SMP_UNLOCK_RX_MGT(x);
|
|
#endif
|
|
}
|
|
else
|
|
reuse = 1;
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (opmode & WIFI_STATION_STATE)
|
|
{
|
|
// For Station mode, sa and bssid should always be BSSID, and DA is my mac-address
|
|
// in case of to_fr_ds = 0x00, then it must be mgt frame type
|
|
|
|
#ifdef MULTI_MAC_CLONE
|
|
if (IS_MCAST(da) || mclone_find_address(priv, da, pfrinfo->pskb, MAC_CLONE_DA_FIND) >= 0)
|
|
#else
|
|
unsigned char *myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
|
|
if (IS_MCAST(da) || !memcmp(da, myhwaddr, MACADDRLEN))
|
|
#endif
|
|
reuse = 0;
|
|
|
|
if (!reuse) {
|
|
if (frtype == WIFI_MGT_TYPE)
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
#if defined(CONFIG_PCI_HCI)
|
|
rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_recv_mgnt_frame(priv, pfrinfo);
|
|
#endif
|
|
#else
|
|
SMP_LOCK_RX_MGT(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_mgtlist));
|
|
SMP_UNLOCK_RX_MGT(x);
|
|
#endif
|
|
}
|
|
else
|
|
reuse = 1;
|
|
}
|
|
}
|
|
else if (opmode & WIFI_ADHOC_STATE)
|
|
{
|
|
unsigned char *myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
|
|
if (IS_MCAST(da) || !memcmp(da, myhwaddr, MACADDRLEN))
|
|
{
|
|
if (frtype == WIFI_MGT_TYPE)
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
#if defined(CONFIG_PCI_HCI)
|
|
rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_recv_mgnt_frame(priv, pfrinfo);
|
|
#endif
|
|
#else
|
|
SMP_LOCK_RX_MGT(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_mgtlist));
|
|
SMP_UNLOCK_RX_MGT(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
else
|
|
{ // data frames
|
|
if (memcmp(bssid, "\x0\x0\x0\x0\x0\x0", MACADDRLEN) &&
|
|
memcmp(BSSID, "\x0\x0\x0\x0\x0\x0", MACADDRLEN) &&
|
|
!memcmp(bssid, BSSID, MACADDRLEN))
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // CLIENT_MODE
|
|
else
|
|
reuse = 1;
|
|
|
|
out:
|
|
|
|
/* update priv's point */
|
|
*priv_p = priv;
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen, retry);
|
|
return reuse;
|
|
}
|
|
|
|
|
|
/*
|
|
Check the "to_fr_ds" field:
|
|
|
|
FromDS != 0
|
|
ToDS = 0
|
|
*/
|
|
#if defined(CLIENT_MODE) || defined(CONFIG_RTK_MESH)
|
|
static int rtl8192cd_rx_dispatch_fromDs(struct rtl8192cd_priv **priv_p, struct rx_frinfo *pfrinfo
|
|
#ifdef MBSSID
|
|
,int vap_idx
|
|
#endif
|
|
)
|
|
{
|
|
int reuse = 1;
|
|
struct rtl8192cd_priv *priv = *priv_p;
|
|
unsigned int opmode = OPMODE;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
int retry=GetRetry(pframe);/*in case of skb has been freed*/
|
|
unsigned int frtype = GetFrameType(pframe);
|
|
unsigned char *da = pfrinfo->da;
|
|
#ifdef MULTI_MAC_CLONE
|
|
unsigned char *myhwaddr = GET_MY_HWADDR;
|
|
#else
|
|
unsigned char *myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
|
|
#endif
|
|
unsigned char *bssid = GetAddr2Ptr(pframe);
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable && (vap_idx >= 0))
|
|
{
|
|
priv = priv->pvap_priv[vap_idx];
|
|
opmode = OPMODE;
|
|
myhwaddr = GET_MY_HWADDR;
|
|
}
|
|
#endif
|
|
#ifdef CLIENT_MODE //(add for Mesh)
|
|
if (frtype == WIFI_MGT_TYPE)
|
|
goto out;
|
|
|
|
if ((opmode & (WIFI_STATION_STATE | WIFI_ASOC_STATE)) ==
|
|
(WIFI_STATION_STATE | WIFI_ASOC_STATE))
|
|
{
|
|
// For Station mode,
|
|
// da should be for me, bssid should be BSSID
|
|
if (IS_BSSID(priv, bssid)) {
|
|
if (IS_MCAST(da) || !memcmp(da, myhwaddr, MACADDRLEN))
|
|
{
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
}
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER
|
|
else if ((opmode & WIFI_AP_STATE) && IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
{
|
|
#ifdef SDIO_2_PORT
|
|
myhwaddr = GET_VXD_PRIV(priv)->pmib->dot11OperationEntry.hwaddr;
|
|
#endif
|
|
if (IS_BSSID(GET_VXD_PRIV(priv), bssid)) {
|
|
if (IS_MCAST(da) || !memcmp(da, myhwaddr, MACADDRLEN))
|
|
{
|
|
priv = GET_VXD_PRIV(priv);
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &priv->rx_datalist);
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
reuse = 1;
|
|
|
|
#endif // CLIENT_MODE (add for Mesh)
|
|
out:
|
|
|
|
/* update priv's point */
|
|
*priv_p = priv;
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen, retry);
|
|
return reuse;
|
|
}
|
|
#endif // defined(CLIENT_MODE) || defined(CONFIG_RTK_MESH)
|
|
|
|
|
|
/*
|
|
Check the "to_fr_ds" field:
|
|
|
|
FromDS = 0
|
|
ToDS != 0
|
|
*/
|
|
static inline int rtl8192cd_rx_dispatch_toDs(struct rtl8192cd_priv **priv_p, struct rx_frinfo *pfrinfo
|
|
#ifdef MBSSID
|
|
,int vap_idx
|
|
#endif
|
|
)
|
|
{
|
|
int reuse = 1;
|
|
struct rtl8192cd_priv *priv = *priv_p;
|
|
unsigned int opmode = OPMODE;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
int retry=GetRetry(pframe); /*in case of skb has been freed*/
|
|
unsigned int frtype = GetFrameType(pframe);
|
|
unsigned char *bssid = GetAddr1Ptr(pframe);
|
|
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
#ifdef CONFIG_RTK_MESH
|
|
if (GET_MIB(priv)->dot1180211sInfo.mesh_enable == 1) { // For MBSSID enable and STA connect to Virtual-AP can't use problem.
|
|
struct stat_info *pstat = get_stainfo(priv, pfrinfo->sa);
|
|
|
|
if ((pstat == NULL) || isPossibleNeighbor(pstat))
|
|
goto out;
|
|
}
|
|
#endif // CONFIG_RTK_MESH
|
|
|
|
|
|
if (frtype == WIFI_MGT_TYPE)
|
|
goto out;
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable && (vap_idx >= 0))
|
|
{
|
|
priv = priv->pvap_priv[vap_idx];
|
|
opmode = OPMODE;
|
|
}
|
|
#endif
|
|
|
|
if (opmode & WIFI_AP_STATE)
|
|
{
|
|
#if 0
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable && (vap_idx >= 0))
|
|
{
|
|
priv = priv->pvap_priv[vap_idx];
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
// For AP mode, the data frame should have bssid==BSSID. (sa state checked laterly)
|
|
if (IS_BSSID(priv, bssid))
|
|
{
|
|
// we only receive mgt frame when we are in SITE_MONITOR or link_loss
|
|
// please consider the case: re-auth and re-assoc
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER
|
|
else if (IS_ROOT_INTERFACE(priv) && (opmode & WIFI_STATION_STATE) && IS_DRV_OPEN(GET_VXD_PRIV(priv))
|
|
&& (GET_VXD_PRIV(priv)->drv_state & DRV_STATE_VXD_AP_STARTED)) {
|
|
if (IS_BSSID(GET_VXD_PRIV(priv), bssid))
|
|
{
|
|
priv = GET_VXD_PRIV(priv);
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&(pfrinfo->rx_list), &priv->rx_datalist);
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
reuse = 1;
|
|
|
|
out:
|
|
|
|
/* update priv's point */
|
|
*priv_p = priv;
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen,retry);
|
|
return reuse;
|
|
}
|
|
|
|
|
|
/*
|
|
Check the "to_fr_ds" field:
|
|
|
|
FromDS != 0
|
|
ToDS != 0
|
|
NOTE: The functuion duplicate to rtl8190_rx_dispatch_mesh (mesh_rx.c)
|
|
*/
|
|
#ifdef WDS
|
|
static int rtl8192cd_rx_dispatch_wds(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
int reuse = 1;
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
unsigned int frtype = GetFrameType(pframe);
|
|
struct net_device *dev;
|
|
int fragnum;
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen, GetRetry(pframe));
|
|
|
|
if (memcmp(GET_MY_HWADDR, GetAddr1Ptr(pframe), MACADDRLEN)) {
|
|
DEBUG_INFO("Rx a WDS packet but which addr1 is not matched own, drop it!\n");
|
|
goto out;
|
|
}
|
|
|
|
if (!priv->pmib->dot11WdsInfo.wdsEnabled) {
|
|
DEBUG_ERR("Rx a WDS packet but WDS is not enabled in local mib, drop it!\n");
|
|
goto out;
|
|
}
|
|
dev = getWdsDevByAddr(priv, GetAddr2Ptr(pframe));
|
|
if (dev==NULL) {
|
|
#ifdef LAZY_WDS
|
|
if (priv->pmib->dot11WdsInfo.wdsEnabled == WDS_LAZY_ENABLE) {
|
|
if (add_wds_entry(priv, 0, GetAddr2Ptr(pframe))) {
|
|
dev = getWdsDevByAddr(priv, GetAddr2Ptr(pframe));
|
|
if (dev == NULL) {
|
|
DEBUG_ERR("Rx a WDS packet but which TA is not valid, drop it!\n");
|
|
goto out;
|
|
}
|
|
LOG_MSG("Add a wds entry - %02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
*GetAddr2Ptr(pframe), *(GetAddr2Ptr(pframe)+1), *(GetAddr2Ptr(pframe)+2), *(GetAddr2Ptr(pframe)+3),
|
|
*(GetAddr2Ptr(pframe)+4), *(GetAddr2Ptr(pframe)+5));
|
|
}
|
|
else {
|
|
DEBUG_ERR("Rx a WDS packet but wds table is full, drop it!\n");
|
|
goto out;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
DEBUG_ERR("Rx a WDS packet but which TA is not valid, drop it!\n");
|
|
goto out;
|
|
}
|
|
}
|
|
if (!netif_running(dev)) {
|
|
DEBUG_ERR("Rx a WDS packet but which interface is not up, drop it!\n");
|
|
goto out;
|
|
}
|
|
fragnum = GetFragNum(pframe);
|
|
if (GetMFrag(pframe) || fragnum) {
|
|
DEBUG_ERR("Rx a fragment WDS packet, drop it!\n");
|
|
goto out;
|
|
}
|
|
if (frtype != WIFI_DATA_TYPE) {
|
|
DEBUG_ERR("Rx a WDS packet but which type is not DATA, drop it!\n");
|
|
goto out;
|
|
}
|
|
#ifdef __LINUX_2_6__
|
|
pfrinfo->pskb->dev=dev;
|
|
#endif
|
|
|
|
#ifdef RTL8190_DIRECT_RX
|
|
rtl8192cd_rx_dataframe(priv, NULL, pfrinfo);
|
|
#else
|
|
SMP_LOCK_RX_DATA(x);
|
|
list_add_tail(&pfrinfo->rx_list, &priv->rx_datalist);
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
#endif
|
|
reuse = 0;
|
|
goto out;
|
|
|
|
out:
|
|
|
|
return reuse;
|
|
}
|
|
#endif // WDS
|
|
|
|
#ifdef SUPPORT_MONITOR
|
|
static void rtl_ieee80211_add_rx_packet_header(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo, unsigned int frtype,unsigned int subfrtype)
|
|
{
|
|
unsigned char *pframe = get_pframe(pfrinfo); //skb data
|
|
struct rtl_wifi_header *rthdr;
|
|
struct sk_buff* pskb = pfrinfo->pskb;
|
|
unsigned char channel = 0;
|
|
unsigned char *p = NULL;
|
|
static const size_t len = PAGE_SIZE;
|
|
p = get_ie(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, _DSSET_IE_, &len, pfrinfo->pktlen - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_);
|
|
|
|
if(GetFrameSubType(pframe)==WIFI_BEACON)
|
|
{
|
|
if (p != NULL)
|
|
channel = *(p+2);
|
|
else
|
|
channel = priv->pmib->dot11RFEntry.dot11channel;
|
|
}
|
|
else
|
|
channel = priv->chan_num+1;
|
|
|
|
rthdr = (void *)skb_push(pskb, sizeof(*rthdr));
|
|
if(!rthdr)
|
|
{
|
|
panic_printk("(%s)line=%d,!!! failed to allocate memory !!!\n", __FUNCTION__, __LINE__);
|
|
ASSERT(rthdr);
|
|
}
|
|
memset(rthdr, 0, sizeof(*rthdr));
|
|
|
|
rthdr->rt_frame_type = frtype;
|
|
rthdr->rt_sub_frame_type = subfrtype;
|
|
rthdr->rt_rssi = pfrinfo->rssi;
|
|
rthdr->rt_noise = 10;
|
|
memcpy((rthdr->rt_addr1),GetAddr1Ptr(pframe), MACADDRLEN);
|
|
memcpy((rthdr->rt_addr2),GetAddr2Ptr(pframe), MACADDRLEN);
|
|
rthdr->rt_rate= pfrinfo->rx_rate;
|
|
rthdr->rt_channel_num = channel;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
return value:
|
|
0: no reuse, allocate new skb due to the current is queued.
|
|
1: reuse! due to error pkt or short pkt.
|
|
----------------------------------------------------------------*/
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
int validate_mpdu(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *sa, *da, *myhwaddr, *pframe;
|
|
unsigned int frtype;
|
|
|
|
|
|
int reuse = 1;
|
|
#ifdef MBSSID
|
|
unsigned int opmode = OPMODE;
|
|
int i, vap_idx=-1;
|
|
#endif
|
|
|
|
#if defined(__LINUX_2_6__) || defined(__ECOS)
|
|
if(pfrinfo == NULL || pfrinfo->pskb==NULL || pfrinfo->pskb->data == NULL)
|
|
return 1;
|
|
#endif
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
|
|
#if 1 //Filen_Debug
|
|
if ((unsigned long)pframe & BIT0) {
|
|
panic_printk("Error: pframe(0x%lx), pfrinfo->pskb(0x%lx), pfrinfo(0x%lx)\n", (unsigned long)pframe, (unsigned long)pfrinfo->pskb, (unsigned long)pfrinfo);
|
|
panic_printk("Error: rxbuf_shift(0x%x), driver_info_size(0x%x)\n", pfrinfo->rxbuf_shift, pfrinfo->driver_info_size);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
#if 0 // already flush cache in rtl8192cd_rx_isr()
|
|
#ifndef RTL8190_CACHABLE_CLUSTER
|
|
#ifdef __MIPSEB__
|
|
pframe = (UINT8 *)((unsigned long)pframe | 0x20000000);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef DRVMAC_LB
|
|
if (priv->pmib->miscEntry.drvmac_lb)
|
|
lb_convert(priv, pframe);
|
|
#endif
|
|
|
|
pfrinfo->hdr_len = get_hdrlen(priv, pframe);
|
|
if (pfrinfo->hdr_len == 0) // unallowed packet type
|
|
{
|
|
// printk("pfrinfo->hdr_len == 0\n");
|
|
return 1;
|
|
}
|
|
|
|
#ifdef CONFIG_8814_AP_MAC_VERI
|
|
RX_MAC_Verify_8814(priv,pframe,pfrinfo);
|
|
#endif //#ifdef CONFIG_8814_AP_MAC_VERI
|
|
|
|
frtype = GetFrameType(pframe);
|
|
pfrinfo->to_fr_ds = get_tofr_ds(pframe);
|
|
pfrinfo->da = da = get_da(pframe);
|
|
pfrinfo->sa = sa = get_sa(pframe);
|
|
pfrinfo->seq = GetSequence(pframe);
|
|
|
|
#ifdef SUPPORT_MONITOR
|
|
if(priv->is_monitor_mode == TRUE)
|
|
{
|
|
unsigned int sub_frame_type = GetFrameSubType(pframe);
|
|
if((frtype == WIFI_MGT_TYPE) || (frtype == WIFI_DATA_TYPE))
|
|
{
|
|
struct sk_buff* pskb = pfrinfo->pskb;
|
|
rtl_ieee80211_add_rx_packet_header(priv, pfrinfo, frtype,sub_frame_type);
|
|
pskb->dev = priv->dev;
|
|
skb_reset_mac_header(pskb);
|
|
pskb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
pskb->pkt_type = PACKET_OTHERHOST;
|
|
pskb->protocol = htons(ETH_P_802_2);
|
|
netif_receive_skb(pskb);
|
|
reuse = 0;
|
|
return reuse;
|
|
}
|
|
else
|
|
{
|
|
reuse = 1;
|
|
return reuse;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
pfrinfo->is_11s = 0;
|
|
|
|
// WIFI_11S_MESH_ACTION use QoS bit, but it's not a QoS data (8186 compatible)
|
|
if (is_qos_data(pframe) && GetFrameSubType(pframe)!=WIFI_11S_MESH_ACTION) {
|
|
#else
|
|
if (is_qos_data(pframe)) {
|
|
#endif
|
|
pfrinfo->tid = GetTid(pframe) & 0x07; // we only process TC of 0~7
|
|
}
|
|
else {
|
|
pfrinfo->tid = 0;
|
|
}
|
|
#ifdef MULTI_MAC_CLONE
|
|
if (MCLONE_NUM > 0 && !IS_MCAST(GetAddr1Ptr(pframe))) {
|
|
int id;
|
|
id = mclone_find_address(priv, GetAddr1Ptr(pframe), pfrinfo->pskb, MAC_CLONE_DA_FIND);
|
|
if (id > 0)
|
|
ACTIVE_ID = id;
|
|
else
|
|
ACTIVE_ID = 0;
|
|
} else
|
|
ACTIVE_ID = 0;
|
|
myhwaddr = GET_MY_HWADDR;
|
|
#else
|
|
myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
|
|
#endif
|
|
|
|
#ifdef PCIE_POWER_SAVING
|
|
if (!memcmp(myhwaddr, GetAddr1Ptr(pframe), MACADDRLEN))
|
|
mod_timer(&priv->ps_timer, jiffies + POWER_DOWN_T0);
|
|
#endif
|
|
|
|
// filter packets that SA is myself
|
|
#ifdef MULTI_MAC_CLONE
|
|
if ((OPMODE & WIFI_STATION_STATE) && IS_MCAST(GetAddr1Ptr(pframe)) &&
|
|
priv->pmib->ethBrExtInfo.macclone_enable && (mclone_find_address(priv, sa, NULL, MAC_CLONE_NOCARE_FIND) >= 0)) {
|
|
return 1;
|
|
}
|
|
else if ((OPMODE & WIFI_AP_STATE) && IS_MCAST(GetAddr1Ptr(pframe)) &&
|
|
/*priv->pmib->ethBrExtInfo.macclone_enable &&*/ (mclone_find_address(priv, sa, NULL, MAC_CLONE_MSA_FIND) >= 0)) {
|
|
return 1;
|
|
}
|
|
else
|
|
#endif
|
|
if ((!memcmp(myhwaddr, sa, MACADDRLEN) && (0==priv->pmib->miscEntry.func_off))
|
|
#ifdef CONFIG_RTK_MESH
|
|
// for e.g., MPP1 - THIS_DEVICE - ROOT ;
|
|
// THIS_DEVICE use ROOT first, and then ROOT dispatch the packet to MPP1
|
|
&& (priv->pmib->dot1180211sInfo.mesh_enable ? ((pfrinfo->to_fr_ds != 0x03) && GetFrameSubType(pframe) != WIFI_11S_MESH) : TRUE)
|
|
#endif
|
|
)
|
|
return 1;
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i]))
|
|
{
|
|
if ( (((pfrinfo->to_fr_ds == 0x00) || (pfrinfo->to_fr_ds == 0x02)) && !memcmp(priv->pvap_priv[i]->pmib->dot11OperationEntry.hwaddr, GetAddr1Ptr(pframe), MACADDRLEN))
|
|
|| (((pfrinfo->to_fr_ds == 0x00) || (pfrinfo->to_fr_ds == 0x01)) && !memcmp(priv->pvap_priv[i]->pmib->dot11StationConfigEntry.dot11Bssid, GetAddr2Ptr(pframe), MACADDRLEN)) ) {
|
|
vap_idx = i;
|
|
if ((priv->pvap_priv[i]->pmib->dot11OperationEntry.opmode & WIFI_STATION_STATE) && (pfrinfo->to_fr_ds == 0x01) && !memcmp(priv->pvap_priv[i]->pmib->dot11OperationEntry.hwaddr, sa, MACADDRLEN))
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// check power save state
|
|
if ((opmode & WIFI_AP_STATE)
|
|
#ifdef UNIVERSAL_REPEATER
|
|
|| ((opmode & WIFI_STATION_STATE) && IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
#endif
|
|
)
|
|
{
|
|
bssid = GetAddr1Ptr(pframe);
|
|
|
|
#ifdef MBSSID
|
|
if (vap_idx >= 0) {
|
|
if (IS_BSSID(priv->pvap_priv[vap_idx], bssid))
|
|
pwr_state(priv->pvap_priv[vap_idx], pfrinfo);
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (opmode & WIFI_AP_STATE) {
|
|
if (IS_BSSID(priv, bssid))
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
else {
|
|
if (IS_BSSID(GET_VXD_PRIV(priv), bssid))
|
|
pwr_state(GET_VXD_PRIV(priv), pfrinfo);
|
|
}
|
|
#else
|
|
if (IS_BSSID(priv, bssid))
|
|
pwr_state(priv, pfrinfo);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// if receiving control frames, we just handle PS-Poll only
|
|
if (frtype == WIFI_CTRL_TYPE)
|
|
{
|
|
return rtl8192cd_rx_procCtrlPkt(priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
}
|
|
|
|
// for ap, we have handled; for station/ad-hoc, we reject null_data frame
|
|
if (((GetFrameSubType(pframe)) == WIFI_DATA_NULL) ||
|
|
(((GetFrameSubType(pframe)) == WIFI_DATA) && pfrinfo->pktlen <= 24)
|
|
#ifdef WIFI_WMM
|
|
||((QOS_ENABLE) && ((GetFrameSubType(pframe)) == (WIFI_DATA_NULL | BIT(7))))
|
|
#endif
|
|
)
|
|
{
|
|
return rtl8192cd_rx_procNullPkt(priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
}
|
|
|
|
// david, move rx statistics from rtl8192cd_rx_isr() to here because repeater issue
|
|
//qinjunjie:move rx_sum_up to rtl8192cd_rx_dispatch_mgmt_adhoc/rtl8192cd_rx_dispatch_fromDs/rtl8192cd_rx_dispatch_toDs/rtl8192cd_rx_dispatch_wds
|
|
// rx_sum_up(priv, NULL, pfrinfo->pktlen, GetRetry(pframe));
|
|
|
|
// enqueue data frames and management frames
|
|
#if defined(CONFIG_RTL_SIMPLE_CONFIG)
|
|
if((priv->pmib->dot11StationConfigEntry.sc_enabled == 1) && (priv->simple_config_status !=0))
|
|
{
|
|
rtk_sc_start_parse_packet(priv, pfrinfo);
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if((GET_VXD_PRIV(priv)->pmib->dot11StationConfigEntry.sc_enabled == 1) && (GET_VXD_PRIV(priv)->simple_config_status !=0))
|
|
{
|
|
rtk_sc_start_parse_packet(GET_VXD_PRIV(priv), pfrinfo);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
switch (pfrinfo->to_fr_ds)
|
|
{
|
|
case 0x00: // ToDs=0, FromDs=0
|
|
reuse = rtl8192cd_rx_dispatch_mgmt_adhoc(&priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
case 0x01: // ToDs=0, FromDs=1
|
|
#if defined(CLIENT_MODE) || defined(CONFIG_RTK_MESH)
|
|
reuse = rtl8192cd_rx_dispatch_fromDs(&priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
#endif
|
|
break;
|
|
|
|
case 0x02: // ToDs=1, FromDs=0
|
|
reuse = rtl8192cd_rx_dispatch_toDs(&priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
break;
|
|
|
|
case 0x03: // ToDs=1, FromDs=1
|
|
#ifdef CONFIG_RTK_MESH
|
|
if( 1 == GET_MIB(priv)->dot1180211sInfo.mesh_enable)
|
|
{
|
|
reuse = rx_dispatch_mesh(priv, pfrinfo);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef A4_STA
|
|
if (priv->pshare->rf_ft_var.a4_enable) {
|
|
|
|
reuse = rtl8192cd_rx_dispatch_toDs(&priv, pfrinfo
|
|
#ifdef MBSSID
|
|
,vap_idx
|
|
#endif
|
|
);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WDS
|
|
reuse = rtl8192cd_rx_dispatch_wds(priv, pfrinfo);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return reuse;
|
|
}
|
|
|
|
|
|
void rx_pkt_exception(struct rtl8192cd_priv *priv, unsigned int cmd)
|
|
{
|
|
struct net_device_stats *pnet_stats = &(priv->net_stats);
|
|
|
|
if (cmd & RX_CRC32)
|
|
{
|
|
pnet_stats->rx_crc_errors++;
|
|
pnet_stats->rx_errors++;
|
|
SNMP_MIB_INC(dot11FCSErrorCount, 1);
|
|
#ifdef _11s_TEST_MODE_
|
|
mesh_debug_rx2(priv, cmd);
|
|
#endif
|
|
}
|
|
else if (cmd & RX_ICVERR)
|
|
{
|
|
pnet_stats->rx_errors++;
|
|
SNMP_MIB_ASSIGN(dot11WEPICVErrorCount, 1);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
__IRAM_IN_865X
|
|
static void
|
|
rx_pkt_exception_88XX(
|
|
struct rtl8192cd_priv *priv,
|
|
BOOLEAN bRX_CRC32,
|
|
BOOLEAN bRX_ICVERR
|
|
)
|
|
{
|
|
struct net_device_stats *pnet_stats = &(priv->net_stats);
|
|
|
|
priv->ext_stats.rx_reuse++;
|
|
//printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
|
|
if ( bRX_CRC32 )
|
|
{
|
|
pnet_stats->rx_crc_errors++;
|
|
pnet_stats->rx_errors++;
|
|
SNMP_MIB_INC(dot11FCSErrorCount, 1);
|
|
|
|
#if 0 //Filen: mesh_debug_rx2() can't be found ???
|
|
#ifdef _11s_TEST_MODE_
|
|
mesh_debug_rx2(priv, cmd);
|
|
#endif
|
|
#endif
|
|
}
|
|
else if ( bRX_ICVERR )
|
|
{
|
|
pnet_stats->rx_errors++;
|
|
SNMP_MIB_ASSIGN(dot11WEPICVErrorCount, 1);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
#endif //CONFIG_WLAN_HAL
|
|
|
|
#ifdef CONFIG_PCI_HCI
|
|
#if defined(RX_TASKLET) || defined(__ECOS)
|
|
__IRAM_IN_865X
|
|
void rtl8192cd_rx_tkl_isr(unsigned long task_priv)
|
|
{
|
|
struct rtl8192cd_priv *priv;
|
|
#if defined(__LINUX_2_6__) || defined(__ECOS)
|
|
unsigned long flags = 0;
|
|
#endif
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x = 0;
|
|
#endif
|
|
|
|
priv = (struct rtl8192cd_priv *)task_priv;
|
|
|
|
// printk("=====>> INSIDE rtl8192cd_rx_tkl_isr <<=====\n");
|
|
|
|
#ifdef PCIE_POWER_SAVING
|
|
if ((priv->pwr_state == L2) || (priv->pwr_state == L1)) {
|
|
priv->pshare->has_triggered_rx_tasklet = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if defined(__LINUX_2_6__) || defined(__ECOS)
|
|
SMP_LOCK(x);
|
|
//RTL_W32(HIMR, 0);
|
|
#else
|
|
SAVE_INT_AND_CLI(x);
|
|
SMP_LOCK(x);
|
|
|
|
#ifdef DELAY_REFILL_RX_BUF
|
|
priv->pshare->has_triggered_rx_tasklet = 2; // indicate as ISR in service
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask);
|
|
RTL_W32(REG_88E_HIMRE, priv->pshare->InterruptMaskExt);
|
|
} else
|
|
#endif
|
|
{
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if (IS_HAL_CHIP(priv)) {
|
|
GET_HAL_INTERFACE(priv)->EnableRxRelatedInterruptHandler(priv);
|
|
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#endif
|
|
{//not HAL
|
|
//RTL_W32(HIMR, RTL_R32(HIMR) | (HIMR_RXFOVW| HIMR_RDU | HIMR_ROK));
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E){
|
|
RTL_W32(REG_92E_HIMR, RTL_R32(REG_92E_HIMR) | HIMR_ROK);
|
|
RTL_W32(REG_92E_HIMRE, RTL_R32(REG_92E_HIMRE) | HIMRE_92E_RXFOVW);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
RTL_W32(HIMR, RTL_R32(HIMR) | (HIMR_RXFOVW | HIMR_ROK));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//#ifdef DELAY_REFILL_RX_BUF
|
|
// priv->pshare->has_triggered_rx_tasklet = 2; // indicate as ISR in service
|
|
//#endif
|
|
|
|
rtl8192cd_rx_isr(priv);
|
|
|
|
#if defined(__LINUX_2_6__) || defined(__ECOS)
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
//Filen: "has_triggered_rx_tasklet" & "HIMR Enable" should be atomic
|
|
// To avoid that "RX interrupt" is gone
|
|
priv->pshare->has_triggered_rx_tasklet = 0;
|
|
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask);
|
|
RTL_W32(REG_88E_HIMRE, priv->pshare->InterruptMaskExt);
|
|
} else
|
|
#endif
|
|
{
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if (IS_HAL_CHIP(priv)) {
|
|
GET_HAL_INTERFACE(priv)->EnableRxRelatedInterruptHandler(priv);
|
|
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#endif
|
|
{//not HAL
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E){
|
|
RTL_W32(REG_92E_HIMR, priv->pshare->InterruptMask);
|
|
RTL_W32(REG_92E_HIMRE, priv->pshare->InterruptMaskExt);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
RTL_W32(HIMR, priv->pshare->InterruptMask);
|
|
}
|
|
}
|
|
}
|
|
|
|
RESTORE_INT(flags);
|
|
SMP_UNLOCK(x);
|
|
#else
|
|
|
|
priv->pshare->has_triggered_rx_tasklet = 0;
|
|
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK(x);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif // CONFIG_PCI_HCI
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
#ifdef DELAY_REFILL_RX_BUF
|
|
#ifndef __LINUX_2_6__
|
|
__MIPS16
|
|
#endif
|
|
__IRAM_IN_865X
|
|
int refill_rx_ring_88XX(
|
|
struct rtl8192cd_priv *priv,
|
|
struct sk_buff *skb,
|
|
unsigned char *data,
|
|
unsigned int q_num,
|
|
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q
|
|
)
|
|
{
|
|
|
|
/* return 0 means can't refill (because interface be closed or not opened yet) to rx ring but relesae to skb_poll*/
|
|
if (!(priv->drv_state & DRV_STATE_OPEN)){
|
|
return 0;
|
|
}
|
|
struct rtl8192cd_hw *phw=GET_HW(priv);
|
|
struct sk_buff *new_skb;
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
unsigned long x;
|
|
#endif
|
|
extern struct sk_buff *dev_alloc_8190_skb(unsigned char *data, int size);
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
SAVE_INT_AND_CLI(x);
|
|
SMP_LOCK_SKB(x);
|
|
#endif
|
|
if (skb || (priv->pshare->has_triggered_rx_tasklet != 2 &&
|
|
(((cur_q->host_idx + cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num) != cur_q->cur_host_idx) ) ) {
|
|
|
|
if (skb) {
|
|
new_skb = skb;
|
|
} else {
|
|
#ifdef CONFIG_RTL8190_PRIV_SKB
|
|
new_skb = dev_alloc_8190_skb(data, RX_BUF_LEN);
|
|
#else
|
|
new_skb = dev_alloc_skb(RX_BUF_LEN);
|
|
#endif
|
|
if (new_skb == NULL) {
|
|
DEBUG_ERR("out of skb struct!\n");
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
}
|
|
|
|
{
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDInfoHandler(priv, q_num,
|
|
(cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num, new_skb, init_rxdesc_88XX, _FALSE);
|
|
|
|
cur_q->rxbd_ok_cnt++;
|
|
}
|
|
|
|
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 1;
|
|
}
|
|
else {
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
#endif // CONFIG_WLAN_HAL
|
|
|
|
#ifdef DELAY_REFILL_RX_BUF
|
|
#if (!defined(CONFIG_WLAN_HAL) || CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#ifndef __LINUX_2_6__
|
|
__MIPS16
|
|
#endif
|
|
#ifndef __ECOS
|
|
__IRAM_IN_865X
|
|
#endif
|
|
int refill_rx_ring(struct rtl8192cd_priv *priv, struct sk_buff *skb, unsigned char *data)
|
|
{
|
|
struct rtl8192cd_hw *phw=GET_HW(priv);
|
|
struct sk_buff *new_skb;
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
unsigned long x;
|
|
#endif
|
|
extern struct sk_buff *dev_alloc_8190_skb(unsigned char *data, int size);
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
SAVE_INT_AND_CLI(x);
|
|
SMP_LOCK_SKB(x);
|
|
#endif
|
|
if (skb ||
|
|
//(priv->pshare->has_triggered_rx_tasklet != 2 && phw->cur_rx_refill != phw->cur_rx)) {
|
|
phw->cur_rx_refill != phw->cur_rx) {
|
|
if (skb)
|
|
new_skb = skb;
|
|
else {
|
|
#ifdef CONFIG_RTL8190_PRIV_SKB
|
|
new_skb = dev_alloc_8190_skb(data, RX_BUF_LEN);
|
|
#else
|
|
new_skb = dev_alloc_skb(RX_BUF_LEN);
|
|
#endif
|
|
if (new_skb == NULL) {
|
|
DEBUG_ERR("out of skb struct!\n");
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
}
|
|
|
|
init_rxdesc(new_skb, phw->cur_rx_refill, priv);
|
|
//phw->cur_rx_refill = (phw->cur_rx_refill + 1) % NUM_RX_DESC;
|
|
phw->cur_rx_refill = ((phw->cur_rx_refill+1)==NUM_RX_DESC)?0:phw->cur_rx_refill+1;
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
RTL_W32(REG_88E_HISR, HIMR_88E_RDU);
|
|
RTL_W32(REG_88E_HISRE, HIMRE_88E_RXFOVW);
|
|
} else
|
|
#endif
|
|
#ifdef CONFIG_RTL_8812_SUPPORT //8812_client
|
|
if (GET_CHIP_VER(priv)==VERSION_8812E) {
|
|
RTL_W32(REG_HISR0_8812, BIT(1));
|
|
RTL_W32(REG_HISR1_8812, BIT(8));
|
|
} else
|
|
#endif
|
|
{
|
|
RTL_W32(HISR,(HIMR_RXFOVW | HIMR_RDU));
|
|
}
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 1;
|
|
}
|
|
else {
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(RX_TASKLET)
|
|
RESTORE_INT(x);
|
|
SMP_UNLOCK_SKB(x);
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
#else
|
|
int refill_rx_ring(struct rtl8192cd_priv *priv, struct sk_buff *skb, unsigned char *data)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif // !CONFIG_WLAN_HAL || CONFIG_WLAN_NOT_HAL_EXIST
|
|
#endif // DELAY_REFILL_RX_BUF
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
void flush_rx_list(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct rx_frinfo *pfrinfo;
|
|
struct list_head *phead, *plist;
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
|
|
phead = &priv->pshare->gather_list;
|
|
plist = phead->next;
|
|
|
|
while (plist != phead) {
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, rx_list);
|
|
plist = plist->next;
|
|
if (pfrinfo->pskb)
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
INIT_LIST_HEAD(&priv->pshare->gather_list);
|
|
|
|
RESTORE_INT(flags);
|
|
}
|
|
|
|
static int search_first_segment(struct rtl8192cd_priv *priv, struct rx_frinfo **found)
|
|
{
|
|
struct rx_frinfo *pfrinfo, *first = NULL;
|
|
struct list_head *phead, *plist;
|
|
int len = 0, look_for = GATHER_FIRST, ok = 0;
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
unsigned char *pframe;
|
|
u8 qosControl[4];
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
|
|
phead = &priv->pshare->gather_list;
|
|
plist = phead->next;
|
|
|
|
while (phead && plist != phead) {
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, rx_list);
|
|
plist = plist->next;
|
|
|
|
if (pfrinfo->gather_flag & look_for) {
|
|
len += pfrinfo->pktlen;
|
|
if (pfrinfo->gather_flag & GATHER_FIRST) {
|
|
first = pfrinfo;
|
|
list_del_init(&pfrinfo->rx_list);
|
|
|
|
if (pfrinfo->pskb) {
|
|
pframe = get_pframe(pfrinfo);
|
|
memcpy(qosControl, GetQosControl(pframe), 2);
|
|
if (!is_qos_data(pframe) || !(qosControl[0] & BIT(7))) { /* not AMSDU */
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
pfrinfo->pskb = NULL;
|
|
} else {
|
|
look_for = GATHER_MIDDLE | GATHER_LAST;
|
|
}
|
|
}
|
|
}
|
|
else if (pfrinfo->gather_flag & GATHER_LAST) {
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if (IS_HAL_CHIP(priv)) {
|
|
first->gather_len = len - _CRCLNG_;
|
|
} else if(CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#endif
|
|
{//not HAL
|
|
first->gather_len = len;
|
|
}
|
|
*found = first;
|
|
ok = 1;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
list_del_init(&pfrinfo->rx_list);
|
|
if (pfrinfo->pskb)
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
}
|
|
|
|
if (first && !ok) {
|
|
if (first->pskb)
|
|
rtl_kfree_skb(priv, first->pskb, _SKB_RX_);
|
|
}
|
|
|
|
RESTORE_INT(flags);
|
|
return ok;
|
|
}
|
|
|
|
#endif /* RX_BUFFER_GATHER */
|
|
|
|
#ifdef CONFIG_PCI_HCI
|
|
|
|
#if (defined(__ECOS) ||defined(__LINUX_2_6__)) && defined(RX_TASKLET)
|
|
#define RTL_WLAN_RX_ATOMIC_PROTECT_ENTER do {SAVE_INT_AND_CLI(x);} while(0)
|
|
#define RTL_WLAN_RX_ATOMIC_PROTECT_EXIT do {RESTORE_INT(x);} while(0)
|
|
#else
|
|
#define RTL_WLAN_RX_ATOMIC_PROTECT_ENTER
|
|
#define RTL_WLAN_RX_ATOMIC_PROTECT_EXIT
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
|
|
BOOLEAN
|
|
CheckRxPktLenReuse(
|
|
struct rtl8192cd_priv *priv,
|
|
struct rx_frinfo *pfrinfo,
|
|
PRX_DESC_STATUS_88XX prx_desc_status
|
|
)
|
|
{
|
|
// TODO: 0x2d00 is 11520, but MAX AMSDU is 11454 (0x2CBE)
|
|
//3 Check Upper bound length
|
|
// 1.) Check older than 11AC
|
|
if (!(priv->pmib->dot11BssType.net_work_type & WIRELESS_11AC)) {
|
|
if (pfrinfo->pktlen > 0x2000) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// 2.) Check 11AC
|
|
if (priv->pmib->dot11BssType.net_work_type & WIRELESS_11AC) {
|
|
if (pfrinfo->pktlen > 0x2d00) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//3 Check Low bound length
|
|
if (prx_desc_status->C2HPkt) {
|
|
// TODO: check if there is low bound length for C2H packet length
|
|
}
|
|
else {
|
|
// Normal RX packet
|
|
if (pfrinfo->pktlen < 16) {
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (pfrinfo->gather_flag != GATHER_LAST) {
|
|
return TRUE;
|
|
}
|
|
#else
|
|
return TRUE;
|
|
#endif //defined(RX_BUFFER_GATHER)
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
void
|
|
validate_C2HPkt(
|
|
struct rtl8192cd_priv *priv,
|
|
struct rx_frinfo *pfrinfo
|
|
)
|
|
{
|
|
#ifdef CONFIG_WLAN_HAL_8881A
|
|
if ((GET_CHIP_VER(priv) == VERSION_8881A)) {
|
|
C2HPacketHandler_8881A(priv, get_pframe(pfrinfo), pfrinfo->pktlen); // no CRC in C2H_PACKET
|
|
}
|
|
else
|
|
#endif
|
|
GET_HAL_INTERFACE(priv)->C2HPacketHandler(priv,get_pframe(pfrinfo), pfrinfo->pktlen); // no CRC in C2H_PACKET
|
|
// TODO: Parsing C2H Packet
|
|
}
|
|
|
|
#define CFG_UPDATE_RX_SWBD_IDX_EARLY 1
|
|
|
|
#ifdef CONFIG_RTK_VOIP_QOS
|
|
extern int ( *check_voip_channel_loading )( void );
|
|
#endif
|
|
#if !defined(__LINUX_2_6__) && !defined(__ECOS)
|
|
__MIPS16
|
|
#endif
|
|
__IRAM_IN_865X
|
|
void rtl88XX_rx_isr(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct rtl8192cd_hw *phw;
|
|
struct sk_buff *pskb, *new_skb;
|
|
struct rx_frinfo *pfrinfo;
|
|
unsigned int reuse;
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
unsigned int cmp_flags;
|
|
#endif
|
|
#if (defined(__ECOS) || defined(__LINUX_2_6__)) && defined(RX_TASKLET)
|
|
unsigned long x;
|
|
#if defined(SMP_SYNC)
|
|
unsigned long y = 0;
|
|
#endif
|
|
#endif
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
int refill;
|
|
#else
|
|
u2Byte rxbdOkCnt = 0;
|
|
#endif
|
|
#if defined(MP_TEST)
|
|
unsigned char *sa,*da,*bssid;
|
|
char *pframe;
|
|
unsigned int find_flag;
|
|
#endif
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
#ifdef CONCURRENT_MODE
|
|
extern int skb_free_num[];
|
|
#else
|
|
extern int skb_free_num;
|
|
#endif
|
|
#endif
|
|
#if defined(RX_BUFFER_GATHER)
|
|
int pfrinfo_update;
|
|
#endif
|
|
unsigned int q_num;
|
|
PHCI_RX_DMA_MANAGER_88XX prx_dma;
|
|
PHCI_RX_DMA_QUEUE_STRUCT_88XX cur_q;
|
|
RX_DESC_STATUS_88XX rx_desc_status;
|
|
|
|
#if 1//(defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST)) || defined (CHK_RX_ISR_TAKES_TOO_LONG)
|
|
unsigned long start_time = jiffies;
|
|
int n = 0;
|
|
#endif
|
|
int update = 0;
|
|
u4Byte skb_shift_size = 0;
|
|
u4Byte skb_used_size;
|
|
|
|
#ifdef RX_LOOP_LIMIT
|
|
unsigned int loop_cnt = 0;
|
|
#endif
|
|
|
|
if (!(priv->drv_state & DRV_STATE_OPEN))
|
|
return;
|
|
|
|
SMP_LOCK_RECV(y);
|
|
|
|
phw = GET_HW(priv);
|
|
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
|
|
// Currently, only one queue for rx...
|
|
q_num = 0;
|
|
prx_dma = (PHCI_RX_DMA_MANAGER_88XX)(_GET_HAL_DATA(priv)->PRxDMA88XX);
|
|
cur_q = &(prx_dma->rx_queue[q_num]);
|
|
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHWIdxHandler(priv, q_num);
|
|
|
|
while (cur_q->cur_host_idx != cur_q->hw_idx)
|
|
{
|
|
if ( (n++ > (NUM_RX_DESC *2/3)) || ((jiffies - start_time) >= RTL_MILISECONDS_TO_JIFFIES(1000) ))
|
|
{
|
|
break;
|
|
}
|
|
#if 0 //def __ECOS
|
|
if ((n++ > 100) || ((jiffies - start_time) >= 1))
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef RX_LOOP_LIMIT
|
|
if ((priv->pmib->dot11StationConfigEntry.limit_rxloop > 0) &&
|
|
(loop_cnt++ > priv->pmib->dot11StationConfigEntry.limit_rxloop))
|
|
break;
|
|
#endif
|
|
#if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST)
|
|
if ( (n++ > 100 || (jiffies - start_time) >= 1 )&& (check_voip_channel_loading && (check_voip_channel_loading() > 0)) )
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
#if defined (CHK_RX_ISR_TAKES_TOO_LONG)
|
|
/* for small packet RX test(ex. VeryWave UDP small pkt size RX test), there may comes too many packets from the air and
|
|
cause our RX ISR while(1) loop run too long and then cause the system watch dog timer timeout.
|
|
So we break the while loop when it takes to long */
|
|
if ( (n++ > 1000) || ((jiffies - start_time) >= RTL_MILISECONDS_TO_JIFFIES(1000) ))
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_WLAN_HAL_8192EE
|
|
if (GET_CHIP_VER(priv) == VERSION_8192E) {
|
|
if(((priv->pshare->RxTagPollingCount >20)) )
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
refill = 1;
|
|
#endif // DELAY_REFILL_RX_BUF
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
pfrinfo_update = 0;
|
|
#endif
|
|
|
|
pskb = (struct sk_buff *)(phw->rx_infoL[cur_q->cur_host_idx].pbuf);
|
|
pfrinfo = get_pfrinfo(pskb);
|
|
reuse = 1;
|
|
skb_shift_size = 0;
|
|
|
|
if ( RT_STATUS_SUCCESS != GET_HAL_INTERFACE(priv)->QueryRxDescHandler(priv, q_num, pskb->data, &rx_desc_status) ) {
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
if (IS_PCIBIOS_TYPE) {
|
|
pci_unmap_single(priv->pshare->pdev, phw->rx_infoL[cur_q->cur_host_idx].paddr, (RX_BUF_LEN - sizeof(struct rx_frinfo)), PCI_DMA_FROMDEVICE);
|
|
}
|
|
#endif
|
|
pfrinfo = NULL;
|
|
priv->ext_stats.rx_reuse++;
|
|
#ifdef __ECOS
|
|
panic_printk("QueryRxDesc:%s(%d), reuse1(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
#else
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
#endif
|
|
goto rx_reuse;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
if (IS_PCIBIOS_TYPE) {
|
|
pci_unmap_single(priv->pshare->pdev, phw->rx_infoL[cur_q->cur_host_idx].paddr, rx_desc_status.PKT_LEN, PCI_DMA_FROMDEVICE);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_WLAN_HAL_8192EE
|
|
//translate_CRC32_outsrc(priv, pfrinfo, rx_desc_status.CRC32);
|
|
if(!rx_desc_status.C2HPkt)
|
|
{
|
|
translate_CRC32_outsrc(priv, pfrinfo, rx_desc_status.CRC32,rx_desc_status.PKT_LEN);
|
|
}
|
|
#endif
|
|
|
|
if (rx_desc_status.CRC32) {
|
|
rx_pkt_exception_88XX(priv, rx_desc_status.CRC32, rx_desc_status.ICVERR);
|
|
goto rx_reuse;
|
|
}
|
|
|
|
#if !defined(RX_BUFFER_GATHER)
|
|
else if (!(rx_desc_status.FS == 0x01 && rx_desc_status.LS == 0x01)) {
|
|
// h/w use more than 1 rx descriptor to receive a packet
|
|
// that means this packet is too large
|
|
// drop such kind of packet
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
#endif // !defined(RX_BUFFER_GATHER)
|
|
else if (!IS_DRV_OPEN(priv)) {
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
else {
|
|
pfrinfo->pskb = pskb;
|
|
if(rx_desc_status.C2HPkt)
|
|
pfrinfo->pktlen = rx_desc_status.PKT_LEN;// If is C2H packet, there is no CRC length Kevin for txbf
|
|
else
|
|
pfrinfo->pktlen = rx_desc_status.PKT_LEN - _CRCLNG_;
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (!(rx_desc_status.FS == 0x01 && rx_desc_status.LS == 0x01)) {
|
|
if (rx_desc_status.FS == 0x01 && priv->pshare->gather_state == GATHER_STATE_NO) {
|
|
priv->pshare->gather_state = GATHER_STATE_FIRST;
|
|
pfrinfo->pktlen = rx_desc_status.RXBuffSize - SIZE_RXDESC_88XX - rx_desc_status.DRV_INFO_SIZE - rx_desc_status.SHIFT;
|
|
priv->pshare->gather_len = pfrinfo->pktlen;
|
|
priv->pshare->pkt_total_len = rx_desc_status.PKT_LEN;
|
|
pfrinfo->gather_flag = GATHER_FIRST;
|
|
} else if ((rx_desc_status.FS == 0x00 && rx_desc_status.LS == 0x00) &&
|
|
(priv->pshare->gather_state == GATHER_STATE_FIRST || priv->pshare->gather_state == GATHER_STATE_MIDDLE)) {
|
|
priv->pshare->gather_state = GATHER_STATE_MIDDLE;
|
|
pfrinfo->pktlen = rx_desc_status.RXBuffSize;
|
|
priv->pshare->gather_len += rx_desc_status.RXBuffSize;
|
|
pfrinfo->gather_flag = GATHER_MIDDLE;
|
|
} else if (rx_desc_status.LS == 0x01 &&
|
|
(priv->pshare->gather_state == GATHER_STATE_FIRST || priv->pshare->gather_state == GATHER_STATE_MIDDLE)) {
|
|
priv->pshare->gather_state = GATHER_STATE_LAST;
|
|
pfrinfo->pktlen = priv->pshare->pkt_total_len - priv->pshare->gather_len;
|
|
pfrinfo->gather_flag = GATHER_LAST;
|
|
} else {
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
flush_rx_list(priv);
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
}
|
|
|
|
priv->ext_stats.rx_reuse++;
|
|
//printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
|
|
}
|
|
else {
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
DEBUG_ERR("Rx pkt not in valid gather state [%x]!\n", priv->pshare->gather_state);
|
|
flush_rx_list(priv);
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
}
|
|
}
|
|
|
|
if (pfrinfo->gather_flag && pfrinfo->gather_flag != GATHER_FIRST) {
|
|
pfrinfo->driver_info_size = 0;
|
|
pfrinfo->rxbuf_shift = 0;
|
|
}
|
|
else
|
|
#endif /* RX_BUFFER_GATHER */
|
|
{
|
|
pfrinfo->driver_info_size = rx_desc_status.DRV_INFO_SIZE;
|
|
pfrinfo->rxbuf_shift = rx_desc_status.SHIFT;
|
|
}
|
|
|
|
pfrinfo->sw_dec = rx_desc_status.SWDEC;
|
|
|
|
if (CheckRxPktLenReuse(priv, pfrinfo, &rx_desc_status)) {
|
|
printk("pktlen out of range, pfrinfo->pktlen=0x%x, goto rx_reuse\n", pfrinfo->pktlen);
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
|
|
#if defined(CONFIG_RTL865X_CMO)
|
|
if (pfrinfo->pskb == NULL) {
|
|
pfrinfo->pskb = pskb;
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (priv->pshare->gather_state != GATHER_STATE_MIDDLE && priv->pshare->gather_state != GATHER_STATE_LAST)
|
|
#endif
|
|
{
|
|
//3 Shift SKB pointer before we use skb->data
|
|
skb_reserve(pskb, sizeof(RX_DESC_88XX));
|
|
skb_shift_size += sizeof(RX_DESC_88XX);
|
|
}
|
|
|
|
//3 1.) Check if C2H packet is received
|
|
if (rx_desc_status.C2HPkt) {
|
|
//printk("rcv c2h pkt\n");
|
|
//priv->ext_stats.rx_reuse++;
|
|
//printk("%s(%d), C2H reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
validate_C2HPkt(priv, pfrinfo);
|
|
#if 0//def CONFIG_WLAN_HAL_8192EE
|
|
if (GET_CHIP_VER(priv) == VERSION_8192E) {
|
|
C2HPacketHandler_92E(priv, get_pframe(pfrinfo), pfrinfo->pktlen); // no CRC in C2H_PACKET
|
|
}
|
|
#endif
|
|
pskb->data -= skb_shift_size; // skb_shift_size == sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size == sizeof(RX_DESC_88XX)
|
|
goto rx_reuse;
|
|
}
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (TRUE == rx_desc_status.PHYST && ((priv->pshare->gather_state == GATHER_STATE_FIRST) || (priv->pshare->gather_state == GATHER_STATE_NO)))
|
|
#else
|
|
if (TRUE == rx_desc_status.PHYST)
|
|
#endif
|
|
{
|
|
pfrinfo->driver_info = (struct RxFWInfo *)(get_pframe(pfrinfo));
|
|
}
|
|
else {
|
|
//printk("%s(%d): driver_info pointer error\n", __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
pfrinfo->physt = rx_desc_status.PHYST;
|
|
pfrinfo->paggr = rx_desc_status.PAGGR;
|
|
pfrinfo->faggr = 0;
|
|
pfrinfo->rx_splcp = 0;
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pfrinfo->macid = rx_desc_status.rxMACID;
|
|
}
|
|
#endif //HW_FILL_MACID
|
|
pfrinfo->rx_bw = 0;
|
|
|
|
if(priv->pmib->dot11BssType.net_work_type & WIRELESS_11AC) {
|
|
if (rx_desc_status.RX_RATE < 12) {
|
|
pfrinfo->rx_rate = dot11_rate_table[rx_desc_status.RX_RATE];
|
|
} else if(rx_desc_status.RX_RATE < 44) {
|
|
pfrinfo->rx_rate = HT_RATE_ID + (rx_desc_status.RX_RATE - 12);
|
|
} else{
|
|
pfrinfo->rx_rate = VHT_RATE_ID + (rx_desc_status.RX_RATE - 44);
|
|
}
|
|
} else if (rx_desc_status.RX_RATE < 12) {
|
|
pfrinfo->rx_rate = dot11_rate_table[rx_desc_status.RX_RATE];
|
|
} else {
|
|
pfrinfo->rx_rate = HT_RATE_ID + (rx_desc_status.RX_RATE - 12);
|
|
}
|
|
|
|
if (!pfrinfo->physt) {
|
|
pfrinfo->rssi = 0;
|
|
} else {
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (pfrinfo->driver_info_size > 0)
|
|
#endif
|
|
{
|
|
|
|
#ifdef USE_OUT_SRC
|
|
#ifdef _OUTSRC_COEXIST
|
|
if(IS_OUTSRC_CHIP(priv))
|
|
#endif
|
|
{
|
|
translate_rssi_sq_outsrc(priv, pfrinfo, rx_desc_status.RX_RATE);
|
|
}
|
|
#endif
|
|
|
|
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
|
|
#ifdef _OUTSRC_COEXIST
|
|
if(!IS_OUTSRC_CHIP(priv))
|
|
#endif
|
|
{
|
|
translate_rssi_sq(priv, pfrinfo);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
{
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
// Use REFILL_THRESHOLD-2 because we should keep at least 2 skb to trigger movement of host_idx
|
|
cmp_flags = (CIRC_CNT_RTK(cur_q->cur_host_idx,
|
|
(cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num, NUM_RX_DESC) >= REFILL_THRESHOLD-2);
|
|
|
|
if (cmp_flags) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.rx_reuse++;
|
|
DEBUG_WARN("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
priv->ext_stats.reused_skb++;
|
|
pskb->data -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
goto rx_reuse;
|
|
}
|
|
new_skb = NULL;
|
|
#else
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
if (new_skb == NULL) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.rx_reuse++;
|
|
//printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
priv->ext_stats.reused_skb++;
|
|
pskb->data -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
}
|
|
#else /* defined(CONFIG_RTL8190_PRIV_SKB) */
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
// TODO: REFILL_THRESHOLD or REFILL_THRESHOLD-1?
|
|
cmp_flags = (CIRC_CNT_RTK(cur_q->cur_host_idx,
|
|
(cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num, NUM_RX_DESC) > REFILL_THRESHOLD);
|
|
|
|
if (cmp_flags) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
priv->ext_stats.reused_skb++;
|
|
pskb->data -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
goto rx_reuse;
|
|
}
|
|
new_skb = NULL;
|
|
#else
|
|
|
|
// allocate new one in advance
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
if (new_skb == NULL) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
priv->ext_stats.reused_skb++;
|
|
pskb->data -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*-----------------------------------------------------
|
|
validate_mpdu will check if we still can reuse the skb
|
|
------------------------------------------------------*/
|
|
#if defined(CONFIG_RTL_QOS_PATCH) || defined(CONFIG_RTK_VOIP_QOS) || defined(CONFIG_RTK_VLAN_WAN_TAG_SUPPORT)
|
|
pskb->srcPhyPort = QOS_PATCH_RX_FROM_WIRELESS;
|
|
#endif
|
|
|
|
#if defined(MP_TEST)
|
|
if (OPMODE & WIFI_MP_STATE) {
|
|
skb_reserve(pskb, (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size));
|
|
skb_shift_size += (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
reuse = 1;
|
|
find_flag=1;
|
|
//-------------------------------------------------------------------------------------------
|
|
if((OPMODE & WIFI_MP_ARX_FILTER ) && (OPMODE & WIFI_MP_RX ) )
|
|
{
|
|
pframe = get_pframe(pfrinfo);
|
|
sa = get_sa(pframe);
|
|
da = get_da(pframe);
|
|
bssid =get_bssid_mp(pframe);
|
|
if(priv->pshare->mp_filter_flag & 0x1)
|
|
{
|
|
//sa = get_sa(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_SA,sa,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
if(find_flag)
|
|
{
|
|
if(priv->pshare->mp_filter_flag & 0x2)
|
|
{
|
|
//da = get_da(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_DA,da,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
}
|
|
if(find_flag)
|
|
{
|
|
if(priv->pshare->mp_filter_flag & 0x4)
|
|
{
|
|
//bssid =get_bssid_mp(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_BSSID,bssid,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
if(find_flag)
|
|
{
|
|
printk("flag: %x\nSA: %02x:%02x:%02x:%02x:%02x:%02x\nDA: %02x:%02x:%02x:%02x:%02x:%02x\nBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",priv->pshare->mp_filter_flag,
|
|
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5],
|
|
da[0], da[1], da[2], da[3], da[4], da[5],
|
|
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
|
}
|
|
#endif
|
|
}
|
|
//-------------------------------------------------------------------------------------------
|
|
if(find_flag)
|
|
{
|
|
#if defined(B2B_TEST)
|
|
mp_validate_rx_packet(priv, pskb->data, pfrinfo->pktlen);
|
|
#endif
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen, GetRetry(get_pframe(pfrinfo)));
|
|
//if (priv->pshare->rf_ft_var.rssi_dump)
|
|
update_sta_rssi(priv, NULL, pfrinfo);
|
|
}
|
|
|
|
pskb->data -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
}
|
|
else
|
|
#endif // defined(MP_TEST)
|
|
{
|
|
|
|
// 64 is the value in init_rxdesc_88XX: *pBufLen = RX_BUF_LEN - sizeof(struct rx_frinfo) - 64;
|
|
// Actually, the precise value is the offset, but the value is 64 in old version code (rtl8192cd).
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (rx_desc_status.FS == 0x01 && rx_desc_status.LS == 0x01) {
|
|
skb_used_size = 64 + sizeof(struct rx_frinfo) + SIZE_RXDESC_88XX +
|
|
pfrinfo->driver_info_size + pfrinfo->rxbuf_shift + pfrinfo->pktlen + _CRCLNG_;
|
|
} else if (rx_desc_status.FS == 0x01 && rx_desc_status.LS == 0x0) {
|
|
skb_used_size = 64 + sizeof(struct rx_frinfo) + SIZE_RXDESC_88XX +
|
|
pfrinfo->driver_info_size + pfrinfo->rxbuf_shift + pfrinfo->pktlen;
|
|
} else { // (FS,LS) = (0,0) or (0,1)
|
|
skb_used_size = 64 + sizeof(struct rx_frinfo) +
|
|
pfrinfo->driver_info_size + pfrinfo->rxbuf_shift + pfrinfo->pktlen;
|
|
}
|
|
#else
|
|
skb_used_size = 64 + sizeof(struct rx_frinfo) + SIZE_RXDESC_88XX +
|
|
pfrinfo->driver_info_size + pfrinfo->rxbuf_shift + pfrinfo->pktlen + _CRCLNG_;
|
|
#endif
|
|
|
|
if (skb_used_size <= RX_BUF_LEN) {
|
|
skb_reserve(pskb, (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size));
|
|
skb_shift_size += (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
|
|
if (rx_desc_status.ICVERR) {
|
|
rx_pkt_exception_88XX(priv, rx_desc_status.CRC32, rx_desc_status.ICVERR);
|
|
pskb->data -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
#if !defined(DELAY_REFILL_RX_BUF) || !defined(CONFIG_RTL8190_PRIV_SKB) //we create this, but we do not free it!
|
|
if (new_skb != NULL)
|
|
rtl_kfree_skb(priv, new_skb, _SKB_RX_);
|
|
#endif
|
|
priv->ext_stats.rx_reuse++;
|
|
printk("%s(%d), reuse(0x%x)\n", __FUNCTION__, __LINE__, (unsigned int)priv->ext_stats.rx_reuse);
|
|
goto rx_reuse;
|
|
}
|
|
|
|
SNMP_MIB_INC(dot11ReceivedFragmentCount, 1);
|
|
|
|
#if defined(SW_ANT_SWITCH)
|
|
if(priv->pshare->rf_ft_var.antSw_enable) {
|
|
dm_SWAW_RSSI_Check(priv, pfrinfo);
|
|
}
|
|
#endif
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
list_add_tail(&pfrinfo->rx_list, &priv->pshare->gather_list);
|
|
|
|
if (priv->pshare->gather_state == GATHER_STATE_LAST) {
|
|
if (!search_first_segment(priv, &pfrinfo)) {
|
|
reuse = 0;
|
|
} else {
|
|
pskb = pfrinfo->pskb;
|
|
pfrinfo_update = 1;
|
|
}
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
} else {
|
|
reuse = 0;
|
|
}
|
|
}
|
|
if (priv->pshare->gather_state == GATHER_STATE_NO && reuse)
|
|
#endif
|
|
{
|
|
#ifdef BEAMFORMING_SUPPORT
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
unsigned int frtype = GetFrameSubType(pframe);
|
|
if( frtype== Type_Action_No_Ack || frtype == Type_NDPA ) {
|
|
if( frtype== Type_Action_No_Ack) {
|
|
priv->pshare->rf_ft_var.csi_counter++;
|
|
priv->pshare->rf_ft_var.csi_counter %= priv->pshare->rf_ft_var.dumpcsi;
|
|
if( priv->pshare->rf_ft_var.dumpcsi &&
|
|
priv->pshare->rf_ft_var.csi_counter==1)
|
|
{
|
|
if ((pfrinfo->physt)&& (pfrinfo->driver_info_size > 0)) {
|
|
}
|
|
}
|
|
}
|
|
else /*if(frtype == Type_NDPA) */{
|
|
}
|
|
reuse = 1;
|
|
}else
|
|
#endif
|
|
reuse = validate_mpdu(priv, pfrinfo);
|
|
}
|
|
|
|
if (reuse) {
|
|
pskb->data -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + sizeof(RX_DESC_88XX))
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
if (pfrinfo->gather_flag & GATHER_FIRST){
|
|
//flush_rx_list(priv);
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
reuse = 0;
|
|
// printk("%s(%d), Gather-First packet error, free skb\n", __FUNCTION__, __LINE__);
|
|
DEBUG_WARN("Gather-First packet error, free skb\n");
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
//free skb by upper layer, i.e., validate_mpdu
|
|
//So, we don't need to control skb data/tail pointer
|
|
}
|
|
}
|
|
else {
|
|
pskb->data -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
pskb->tail -= skb_shift_size; // skb_shift_size is sizeof(RX_DESC_88XX)
|
|
}
|
|
}
|
|
} /* if (cmd&XXXX) */
|
|
|
|
if (!reuse) {
|
|
phw->rx_infoL[cur_q->cur_host_idx].pbuf = NULL;
|
|
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
if (IS_PCIBIOS_TYPE) {
|
|
// pci_unmap_single(priv->pshare->pdev, phw->rx_infoL[cur_q->cur_host_idx].paddr, (RX_BUF_LEN - sizeof(struct rx_frinfo)), PCI_DMA_FROMDEVICE);
|
|
}
|
|
#endif
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
#ifdef CONCURRENT_MODE
|
|
if (skb_free_num[priv->pshare->wlandev_idx] == 0 && priv->pshare->skb_queue.qlen == 0)
|
|
#else
|
|
if (skb_free_num == 0 && priv->pshare->skb_queue.qlen == 0)
|
|
#endif
|
|
{
|
|
refill = 0;
|
|
goto rx_done;
|
|
}
|
|
#endif
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
ASSERT(new_skb);
|
|
if(new_skb == NULL) {
|
|
printk("not enough memory...\n");
|
|
refill = 0;
|
|
goto rx_done;
|
|
}
|
|
|
|
#endif
|
|
pskb = new_skb;
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDInfoHandler(priv, q_num,
|
|
(cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num, (pu1Byte)pskb, init_rxdesc_88XX, _FALSE);
|
|
#else
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDInfoHandler(priv, q_num, cur_q->cur_host_idx, (pu1Byte)pskb, init_rxdesc_88XX, _FALSE);
|
|
#endif
|
|
goto rx_done;
|
|
|
|
} /* if (!reuse) */
|
|
#if !defined(DELAY_REFILL_RX_BUF)
|
|
else {
|
|
rtl_kfree_skb(priv, new_skb, _SKB_RX_);
|
|
}
|
|
#endif
|
|
|
|
rx_reuse:
|
|
#if 0 //Filen: for debug
|
|
{
|
|
static unsigned int rx_reuse_cnt = 0;
|
|
|
|
rx_reuse_cnt++;
|
|
printk("%s(%d): reuse(0x%x), rx_reuse_cnt(0x%x), pkt_len: 0x%x\n",
|
|
__FUNCTION__, __LINE__, reuse, rx_reuse_cnt, rx_desc_status.PKT_LEN);
|
|
}
|
|
#endif
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
#if defined(RX_BUFFER_GATHER)
|
|
cmp_flags = (cur_q->cur_host_idx != (cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num) || pfrinfo_update;
|
|
#else
|
|
cmp_flags = (cur_q->cur_host_idx != (cur_q->host_idx+cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num);
|
|
#endif // RX_BUFFER_GATHER
|
|
|
|
if (cmp_flags)
|
|
{
|
|
phw->rx_infoL[cur_q->cur_host_idx].pbuf = NULL;
|
|
pskb->data = pskb->head;
|
|
pskb->tail = pskb->head;
|
|
// TODO: why skb_reserve 128
|
|
#ifdef __ECOS
|
|
skb_reserve(pskb, 32);
|
|
#else
|
|
skb_reserve(pskb, 128);
|
|
#endif
|
|
#if defined(CONFIG_RTL8196_RTL8366)
|
|
skb_reserve(pskb, 8);
|
|
#endif
|
|
#if defined(CONFIG_RTK_VOIP_VLAN_ID)
|
|
skb_reserve(pskb, 4);
|
|
#endif
|
|
refill_rx_ring_88XX(priv, pskb, NULL, q_num, cur_q);
|
|
refill = 0;
|
|
} else
|
|
#endif /* defined(DELAY_REFILL_RX_BUF) */
|
|
{
|
|
u4Byte offset;
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (pfrinfo != NULL) {
|
|
pfrinfo->gather_flag = 0;
|
|
}
|
|
#endif
|
|
offset = GetOffsetStartToRXDESC(priv, pskb);
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
// phw->rx_infoL[cur_q->cur_host_idx].paddr = get_physical_addr(priv, pskb->data, (RX_BUF_LEN - sizeof(struct rx_frinfo) - offset), PCI_DMA_FROMDEVICE);
|
|
|
|
pskb->data -= (sizeof(struct rx_frinfo) + offset);
|
|
pskb->tail -= (sizeof(struct rx_frinfo) + offset);
|
|
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDInfoHandler(priv, q_num, cur_q->cur_host_idx, (pu1Byte)pskb, init_rxdesc_88XX, _FALSE);
|
|
// Remove it because pci_map_single() in get_physical_addr() already performed memory sync.
|
|
//rtl_cache_sync_wback(priv, (unsigned long)bus_to_virt(phw->rx_infoL[cur_q->cur_host_idx].paddr),
|
|
// RX_BUF_LEN - sizeof(struct rx_frinfo) - offset,
|
|
// PCI_DMA_FROMDEVICE);
|
|
#else
|
|
#ifdef TRXBD_CACHABLE_REGION
|
|
memset(phw->rx_infoL[cur_q->cur_host_idx].paddr, 0, RX_BUF_LEN - sizeof(struct rx_frinfo) - offset);
|
|
_dma_cache_wback((unsigned long)(bus_to_virt(phw->rx_infoL[cur_q->cur_host_idx].paddr)-CONFIG_LUNA_SLAVE_PHYMEM_OFFSET),
|
|
RX_BUF_LEN - sizeof(struct rx_frinfo) - offset);
|
|
|
|
// _dma_cache_inv((unsigned long)(bus_to_virt(phw->rx_infoL[cur_q->cur_host_idx].paddr)-CONFIG_LUNA_SLAVE_PHYMEM_OFFSET),
|
|
// RX_BUF_LEN - sizeof(struct rx_frinfo) - offset);
|
|
#else
|
|
rtl_cache_sync_wback(priv, (unsigned long)bus_to_virt(phw->rx_infoL[cur_q->cur_host_idx].paddr),
|
|
RX_BUF_LEN - sizeof(struct rx_frinfo) - offset,
|
|
PCI_DMA_FROMDEVICE);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
rx_done:
|
|
|
|
cur_q->cur_host_idx = (cur_q->cur_host_idx+1) % cur_q->total_rxbd_num;
|
|
|
|
#if CFG_UPDATE_RX_SWBD_IDX_EARLY
|
|
update = 0;
|
|
if(cur_q->cur_host_idx == cur_q->hw_idx) {
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHWIdxHandler(priv, q_num);
|
|
update = 1;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
if (refill) {
|
|
cur_q->rxbd_ok_cnt++;
|
|
}
|
|
#else
|
|
rxbdOkCnt++;
|
|
#endif // DELAY_REFILL_RX_BUF
|
|
|
|
#if CFG_UPDATE_RX_SWBD_IDX_EARLY
|
|
if (update) {
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
|
|
cur_q->rxbd_ok_cnt = 0;
|
|
#else
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, rxbdOkCnt);
|
|
rxbdOkCnt = 0;
|
|
#endif
|
|
}
|
|
#endif //CFG_UPDATE_RX_SWBD_IDX_EARLY
|
|
} /* while(1) */
|
|
|
|
//#if !CFG_UPDATE_RX_SWBD_IDX_EARLY
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, cur_q->rxbd_ok_cnt);
|
|
cur_q->rxbd_ok_cnt = 0;
|
|
#else
|
|
GET_HAL_INTERFACE(priv)->UpdateRXBDHostIdxHandler(priv, q_num, rxbdOkCnt);
|
|
#endif
|
|
//#endif //!CFG_UPDATE_RX_SWBD_IDX_EARLY
|
|
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
|
|
SMP_UNLOCK_RECV(y);
|
|
|
|
if (!IS_DRV_OPEN(priv))
|
|
return;
|
|
|
|
#if defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX)
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
if (!list_empty(&priv->wakeup_list))
|
|
process_dzqueue(priv);
|
|
|
|
#if defined(MBSSID)
|
|
if (priv->pmib->miscEntry.vap_enable) {
|
|
int i;
|
|
struct rtl8192cd_priv *priv_vap;
|
|
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i])) {
|
|
priv_vap = priv->pvap_priv[i];
|
|
if (!list_empty(&priv_vap->wakeup_list))
|
|
process_dzqueue(priv_vap);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER
|
|
else {
|
|
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
if (!list_empty(&GET_VXD_PRIV(priv)->wakeup_list))
|
|
process_dzqueue(GET_VXD_PRIV(priv));
|
|
}
|
|
#endif
|
|
#endif /* defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX) */
|
|
|
|
if(priv->pshare->skip_mic_chk)
|
|
--priv->pshare->skip_mic_chk;
|
|
}
|
|
#endif // CONFIG_WLAN_HAL
|
|
|
|
#ifdef CONFIG_RTK_VOIP_QOS
|
|
extern int ( *check_voip_channel_loading )( void );
|
|
#endif
|
|
#ifndef __ECOS
|
|
#ifndef __LINUX_2_6__
|
|
__MIPS16
|
|
#endif
|
|
#endif
|
|
__IRAM_IN_865X
|
|
void rtl8192cd_rx_isr(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct rx_desc *pdesc, *prxdesc;
|
|
struct rtl8192cd_hw *phw;
|
|
struct sk_buff *pskb, *new_skb;
|
|
struct rx_frinfo *pfrinfo;
|
|
unsigned int tail;
|
|
unsigned int cmd, reuse;
|
|
#ifdef DELAY_REFILL_RX_BUF
|
|
unsigned int cmp_flags;
|
|
#endif
|
|
unsigned int rtl8192cd_ICV;
|
|
#if (defined(__ECOS) ||defined(__LINUX_2_6__)) && defined(RX_TASKLET)
|
|
unsigned long x;
|
|
#if defined(SMP_SYNC)
|
|
unsigned long y = 0;
|
|
#endif
|
|
#endif
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
int refill;
|
|
#endif
|
|
#if defined(MP_TEST)
|
|
unsigned char *sa,*da,*bssid;
|
|
char *pframe;
|
|
unsigned int find_flag;
|
|
#endif
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
#ifdef CONCURRENT_MODE
|
|
extern int skb_free_num[];
|
|
#else
|
|
extern int skb_free_num;
|
|
#endif
|
|
#endif
|
|
#if defined(RX_BUFFER_GATHER)
|
|
int pfrinfo_update;
|
|
#endif
|
|
|
|
#if /*defined(__ECOS) ||*/ (defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST))
|
|
unsigned long start_time = jiffies;
|
|
int n = 0;
|
|
#endif
|
|
#ifdef RX_LOOP_LIMIT
|
|
unsigned int loop_cnt = 0;
|
|
#endif
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv)) {
|
|
rtl88XX_rx_isr(priv);
|
|
return;
|
|
}else if(CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#endif //CONFIG_WLAN_HAL
|
|
{
|
|
if (!(priv->drv_state & DRV_STATE_OPEN))
|
|
return;
|
|
|
|
SMP_LOCK_RECV(y);
|
|
|
|
phw = GET_HW(priv);
|
|
tail = phw->cur_rx;
|
|
|
|
#if defined(RTL8190_CACHABLE_DESC)
|
|
prxdesc = (struct rx_desc *)(phw->rx_descL);
|
|
rtl_cache_sync_wback(priv, (unsigned long)prxdesc, sizeof(struct rx_desc), PCI_DMA_FROMDEVICE);
|
|
#else
|
|
#if defined(__MIPSEB__)
|
|
prxdesc = (struct rx_desc *)((unsigned long)(phw->rx_descL) | 0x20000000);
|
|
#else
|
|
prxdesc = (struct rx_desc *)(phw->rx_descL);
|
|
#endif
|
|
#endif /* RTL8190_CACHABLE_DESC */
|
|
|
|
while (1)
|
|
{
|
|
#if 0 //def __ECOS
|
|
if ((n++ > 100) || ((jiffies - start_time) >= 1))
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#ifdef RX_LOOP_LIMIT
|
|
if ((priv->pmib->dot11StationConfigEntry.limit_rxloop > 0) &&
|
|
(loop_cnt++ > priv->pmib->dot11StationConfigEntry.limit_rxloop))
|
|
break;
|
|
#endif
|
|
|
|
#if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST)
|
|
if ( (n++ > 100 || (jiffies - start_time) >= 1 )&& (check_voip_channel_loading && (check_voip_channel_loading() > 0)) )
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
refill = 1;
|
|
|
|
/*
|
|
if (((tail+1) % NUM_RX_DESC) == phw->cur_rx_refill) {
|
|
break;
|
|
}*/
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
cmp_flags = ( ((tail+1)==NUM_RX_DESC?0:tail+1) == phw->cur_rx_refill );
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
|
|
if (cmp_flags) {
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
pfrinfo_update = 0;
|
|
#endif
|
|
|
|
pdesc = prxdesc + tail;
|
|
cmd = get_desc(pdesc->Dword0);
|
|
reuse = 1;
|
|
|
|
if (cmd & RX_OWN)
|
|
break;
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
if (IS_PCIBIOS_TYPE) {
|
|
pci_unmap_single(priv->pshare->pdev, phw->rx_infoL[tail].paddr, (cmd & RX_PktLenMask), PCI_DMA_FROMDEVICE);
|
|
}
|
|
#endif
|
|
|
|
pskb = (struct sk_buff *)(phw->rx_infoL[tail].pbuf);
|
|
pfrinfo = get_pfrinfo(pskb);
|
|
|
|
#ifdef MP_SWITCH_LNA
|
|
if((GET_CHIP_VER(priv) == VERSION_8192D) && priv->pshare->rf_ft_var.mp_specific)
|
|
dynamic_switch_lna(priv);
|
|
#endif
|
|
|
|
if (cmd & RX_CRC32) {
|
|
/*printk("CRC32 happens~!!\n");*/
|
|
rx_pkt_exception(priv, cmd);
|
|
goto rx_reuse;
|
|
}
|
|
#if defined(CONFIG_RTL_88E_SUPPORT) && defined(TXREPORT)
|
|
else if ((GET_CHIP_VER(priv)==VERSION_8188E) &&
|
|
(((get_desc(pdesc->Dword3) >> RXdesc_88E_RptSelSHIFT) & RXdesc_88E_RptSelMask) == 2)) {
|
|
pfrinfo->pktlen = (cmd & RX_PktLenMask);
|
|
if (get_desc(pdesc->Dword4) || get_desc(pdesc->Dword5))
|
|
#ifdef RATEADAPTIVE_BY_ODM
|
|
ODM_RA_TxRPT2Handle_8188E(ODMPTR, pskb->data, pfrinfo->pktlen, get_desc(pdesc->Dword4), get_desc(pdesc->Dword5));
|
|
#else
|
|
RTL8188E_TxReportHandler(priv, pskb, get_desc(pdesc->Dword4), get_desc(pdesc->Dword5), pdesc);
|
|
#endif
|
|
goto rx_reuse;
|
|
} else if ((GET_CHIP_VER(priv)==VERSION_8188E) &&
|
|
((get_desc(pdesc->Dword3) >> RXdesc_88E_RptSelSHIFT) & RXdesc_88E_RptSelMask)) {
|
|
printk("%s %d, Rx report select mismatch, val:%d\n", __FUNCTION__, __LINE__,
|
|
((get_desc(pdesc->Dword3) >> RXdesc_88E_RptSelSHIFT) & RXdesc_88E_RptSelMask));
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
#if !defined(RX_BUFFER_GATHER)
|
|
else if ((cmd & (RX_FirstSeg | RX_LastSeg)) != (RX_FirstSeg | RX_LastSeg)) {
|
|
// h/w use more than 1 rx descriptor to receive a packet
|
|
// that means this packet is too large
|
|
// drop such kind of packet
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
else if (!IS_DRV_OPEN(priv)) {
|
|
goto rx_reuse;
|
|
} else {
|
|
pfrinfo->pskb = pskb;
|
|
pfrinfo->pktlen = (cmd & RX_PktLenMask) - _CRCLNG_;
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if ((cmd & (RX_FirstSeg | RX_LastSeg)) != (RX_FirstSeg | RX_LastSeg)) {
|
|
if ((cmd & RX_FirstSeg) && priv->pshare->gather_state == GATHER_STATE_NO) {
|
|
priv->pshare->gather_state = GATHER_STATE_FIRST;
|
|
priv->pshare->gather_len = pfrinfo->pktlen;
|
|
pfrinfo->gather_flag = GATHER_FIRST;
|
|
} else if (!(cmd & (RX_FirstSeg | RX_LastSeg)) &&
|
|
(priv->pshare->gather_state == GATHER_STATE_FIRST || priv->pshare->gather_state == GATHER_STATE_MIDDLE)) {
|
|
priv->pshare->gather_state = GATHER_STATE_MIDDLE;
|
|
priv->pshare->gather_len += pfrinfo->pktlen;
|
|
pfrinfo->gather_flag = GATHER_MIDDLE;
|
|
} else if ((cmd & RX_LastSeg) &&
|
|
(priv->pshare->gather_state == GATHER_STATE_FIRST || priv->pshare->gather_state == GATHER_STATE_MIDDLE)) {
|
|
priv->pshare->gather_state = GATHER_STATE_LAST;
|
|
pfrinfo->pktlen -= priv->pshare->gather_len;
|
|
pfrinfo->gather_flag = GATHER_LAST;
|
|
} else {
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
DEBUG_ERR("Rx pkt not in sequence [%x, %x]!\n", (cmd & (RX_FirstSeg | RX_LastSeg)), priv->pshare->gather_state);
|
|
flush_rx_list(priv);
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
}
|
|
goto rx_reuse;
|
|
}
|
|
} else {
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
DEBUG_ERR("Rx pkt not in valid gather state [%x]!\n", priv->pshare->gather_state);
|
|
flush_rx_list(priv);
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
}
|
|
}
|
|
if (pfrinfo->gather_flag && pfrinfo->gather_flag != GATHER_FIRST) {
|
|
pfrinfo->driver_info_size = 0;
|
|
pfrinfo->rxbuf_shift = 0;
|
|
}
|
|
else
|
|
#endif /* RX_BUFFER_GATHER */
|
|
{
|
|
pfrinfo->driver_info_size = ((cmd >> RX_DrvInfoSizeSHIFT) & RX_DrvInfoSizeMask)<<3;
|
|
pfrinfo->rxbuf_shift = (cmd & (RX_ShiftMask << RX_ShiftSHIFT)) >> RX_ShiftSHIFT;
|
|
}
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (pfrinfo->gather_flag) {
|
|
pfrinfo->pktlen -= (pfrinfo->driver_info_size - 4);
|
|
priv->pshare->gather_len -= (pfrinfo->driver_info_size - 4);
|
|
}
|
|
#endif
|
|
pfrinfo->sw_dec = (cmd & RX_SwDec) >> 27;
|
|
pfrinfo->pktlen -= pfrinfo->rxbuf_shift;
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if ( ((GET_CHIP_VER(priv)!= VERSION_8812E) && (pfrinfo->pktlen > 0x2000))
|
|
|| ((GET_CHIP_VER(priv)== VERSION_8812E) && (pfrinfo->pktlen > 0x2d00))
|
|
|| (pfrinfo->pktlen < 16)) {
|
|
#else
|
|
if ((pfrinfo->pktlen > 0x2000) || (pfrinfo->pktlen < 16)) {
|
|
#endif
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (!(pfrinfo->gather_flag && (pfrinfo->pktlen < 16)))
|
|
#endif
|
|
{
|
|
DEBUG_INFO("pfrinfo->pktlen=%d, goto rx_reuse\n",pfrinfo->pktlen);
|
|
if( get_desc(pdesc->Dword2) & BIT(28)) {
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
C2HPacketHandler_8812(priv, get_pframe(pfrinfo), pfrinfo->pktlen+4); // no CRC in C2H_PACKET
|
|
#endif
|
|
}
|
|
goto rx_reuse;
|
|
}
|
|
}
|
|
|
|
//#ifdef PCIE_POWER_SAVING_DEBUG
|
|
#if 0
|
|
if(priv->firstPkt) {
|
|
unsigned char *pp= pdesc ;
|
|
printk("rx isr, first pkt: len=%d\n[", pfrinfo->pktlen);
|
|
// printHex(pp, sizeof(struct rx_frinfo));
|
|
// printk("------------------\n");
|
|
printHex(pskb->data+32,pfrinfo->pktlen);
|
|
priv->firstPkt=0;
|
|
printk("]\n\n");
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL865X_CMO)
|
|
if (pfrinfo->pskb == NULL) {
|
|
panic_printk(" rtl8192cd_rx_isr(): pfrinfo->pskb = NULL.\n");
|
|
pfrinfo->pskb = pskb;
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
|
|
pfrinfo->driver_info = (struct RxFWInfo *)(get_pframe(pfrinfo));
|
|
pfrinfo->physt = (get_desc(pdesc->Dword0) & RX_PHYST)? 1:0;
|
|
#if defined(CONFIG_RTL_8812_SUPPORT) //eric_8812 ??
|
|
if (GET_CHIP_VER(priv)==VERSION_8812E)
|
|
{
|
|
pfrinfo->paggr = (get_desc(pdesc->Dword1) & RXdesc_92E_PAGGR)? 1:0;
|
|
pfrinfo->faggr = 0;
|
|
if (IS_C_CUT_8812(priv)) {
|
|
pfrinfo->rx_bw = (get_desc(pdesc->Dword4)>>4)&0x3;
|
|
pfrinfo->rx_splcp = (get_desc(pdesc->Dword4))&0x01;
|
|
} else {
|
|
pfrinfo->rx_bw = 0;
|
|
pfrinfo->rx_splcp = 0;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
pfrinfo->faggr = (get_desc(pdesc->Dword1) & RX_FAGGR)? 1:0;
|
|
pfrinfo->paggr = (get_desc(pdesc->Dword1) & RX_PAGGR)? 1:0;
|
|
pfrinfo->rx_bw = (get_desc(pdesc->Dword3) & RX_BW)? 1:0;
|
|
pfrinfo->rx_splcp = (get_desc(pdesc->Dword3) & RX_SPLCP)? 1:0;
|
|
}
|
|
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
{
|
|
unsigned int rxdesc_rate = (get_desc(pdesc->Dword3)& 0x7f);
|
|
if (rxdesc_rate < 12) {
|
|
pfrinfo->rx_rate = dot11_rate_table[rxdesc_rate];
|
|
} else if(rxdesc_rate < 44) {
|
|
pfrinfo->rx_rate = HT_RATE_ID +(rxdesc_rate - 12);
|
|
} else{
|
|
pfrinfo->rx_rate = VHT_RATE_ID +(rxdesc_rate - 44);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if ((get_desc(pdesc->Dword3)&RX_RxMcsMask) < 12) {
|
|
pfrinfo->rx_rate = dot11_rate_table[(get_desc(pdesc->Dword3)&RX_RxMcsMask)];
|
|
} else {
|
|
pfrinfo->rx_rate = HT_RATE_ID + ((get_desc(pdesc->Dword3)&RX_RxMcsMask)-12);
|
|
}
|
|
|
|
if (!pfrinfo->physt) {
|
|
pfrinfo->rssi = 0;
|
|
} else {
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (pfrinfo->driver_info_size > 0)
|
|
#endif
|
|
{
|
|
#ifdef USE_OUT_SRC
|
|
#ifdef _OUTSRC_COEXIST
|
|
if(IS_OUTSRC_CHIP(priv))
|
|
#endif
|
|
{
|
|
translate_rssi_sq_outsrc(priv, pfrinfo, (get_desc(pdesc->Dword3)&RX_RxMcsMask));
|
|
}
|
|
#endif
|
|
|
|
#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
|
|
#ifdef _OUTSRC_COEXIST
|
|
if(!IS_OUTSRC_CHIP(priv))
|
|
#endif
|
|
{
|
|
translate_rssi_sq(priv, pfrinfo);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
{
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
cmp_flags = (CIRC_CNT_RTK(tail, phw->cur_rx_refill, NUM_RX_DESC) > REFILL_THRESHOLD);
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
if (cmp_flags) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.reused_skb++;
|
|
goto rx_reuse;
|
|
}
|
|
new_skb = NULL;
|
|
#else
|
|
// if (skb_free_num== 0 && priv->pshare->skb_queue.qlen == 0) {
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
if (new_skb == NULL) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.reused_skb++;
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
}
|
|
#else /* defined(CONFIG_RTL8190_PRIV_SKB) */
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
cmp_flags = (CIRC_CNT_RTK(tail, phw->cur_rx_refill, NUM_RX_DESC) > REFILL_THRESHOLD);
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
if (cmp_flags) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.reused_skb++;
|
|
goto rx_reuse;
|
|
}
|
|
new_skb = NULL;
|
|
#else
|
|
// allocate new one in advance
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
if (new_skb == NULL) {
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
priv->ext_stats.reused_skb++;
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*-----------------------------------------------------
|
|
validate_mpdu will check if we still can reuse the skb
|
|
------------------------------------------------------*/
|
|
#if defined(CONFIG_RTL_QOS_PATCH) || defined(CONFIG_RTK_VOIP_QOS) || defined(CONFIG_RTK_VLAN_WAN_TAG_SUPPORT)
|
|
pskb->srcPhyPort = QOS_PATCH_RX_FROM_WIRELESS;
|
|
#endif
|
|
|
|
#if defined(MP_TEST)
|
|
if (OPMODE & WIFI_MP_STATE) {
|
|
skb_reserve(pskb, (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size));
|
|
reuse = 1;
|
|
find_flag=1;
|
|
//-------------------------------------------------------------------------------------------
|
|
if((OPMODE & WIFI_MP_ARX_FILTER ) && (OPMODE & WIFI_MP_RX ) )
|
|
{
|
|
pframe = get_pframe(pfrinfo);
|
|
sa = get_sa(pframe);
|
|
da = get_da(pframe);
|
|
bssid =get_bssid_mp(pframe);
|
|
if(priv->pshare->mp_filter_flag & 0x1)
|
|
{
|
|
//sa = get_sa(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_SA,sa,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
if(find_flag)
|
|
{
|
|
if(priv->pshare->mp_filter_flag & 0x2)
|
|
{
|
|
//da = get_da(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_DA,da,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
}
|
|
if(find_flag)
|
|
{
|
|
if(priv->pshare->mp_filter_flag & 0x4)
|
|
{
|
|
//bssid =get_bssid_mp(pframe);
|
|
if(memcmp(priv->pshare->mp_filter_BSSID,bssid,MACADDRLEN))
|
|
{
|
|
find_flag=0;
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
if(find_flag)
|
|
{
|
|
printk("flag: %x\nSA: %02x:%02x:%02x:%02x:%02x:%02x\nDA: %02x:%02x:%02x:%02x:%02x:%02x\nBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",priv->pshare->mp_filter_flag,
|
|
sa[0],
|
|
sa[1],
|
|
sa[2],
|
|
sa[3],
|
|
sa[4],
|
|
sa[5],
|
|
da[0],
|
|
da[1],
|
|
da[2],
|
|
da[3],
|
|
da[4],
|
|
da[5],
|
|
bssid[0],
|
|
bssid[1],
|
|
bssid[2],
|
|
bssid[3],
|
|
bssid[4],
|
|
bssid[5]);
|
|
}
|
|
#endif
|
|
}
|
|
//-------------------------------------------------------------------------------------------
|
|
if(find_flag)
|
|
{
|
|
#if defined(B2B_TEST)
|
|
mp_validate_rx_packet(priv, pskb->data, pfrinfo->pktlen);
|
|
#endif
|
|
rx_sum_up(priv, NULL, pfrinfo->pktlen, GetRetry(get_pframe(pfrinfo)));
|
|
if (priv->pshare->rf_ft_var.rssi_dump)
|
|
update_sta_rssi(priv, NULL, pfrinfo);
|
|
}
|
|
pskb->data -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
pskb->tail -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
}
|
|
else
|
|
#endif // defined(MP_TEST)
|
|
{
|
|
#if defined(RX_BUFFER_GATHER)
|
|
#define RTL_WLAN_DRV_RX_GATHER_GAP_THRESHOLD 32
|
|
#else
|
|
#define RTL_WLAN_DRV_RX_GATHER_GAP_THRESHOLD 64
|
|
#endif
|
|
|
|
if (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size + pfrinfo->pktlen + _CRCLNG_ <= (RX_BUF_LEN- sizeof(struct rx_frinfo)-RTL_WLAN_DRV_RX_GATHER_GAP_THRESHOLD) ) {
|
|
skb_reserve(pskb, (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size));
|
|
if (cmd & RX_ICVERR) {
|
|
rtl8192cd_ICV = 1;
|
|
#if defined(CONFIG_RTL_92C_SUPPORT) || defined(CONFIG_RTL_92D_SUPPORT)
|
|
/* 88C, 92C, and 92D need to check privacy algorithm and accept icv error packet when using CCMP,
|
|
because hw may report wrong icv status when using CCMP privacy
|
|
*/
|
|
rtl8192cd_ICV = check_icverr_drop(priv, pfrinfo);
|
|
#endif
|
|
|
|
if (rtl8192cd_ICV) {
|
|
rx_pkt_exception(priv, cmd);
|
|
pskb->data -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
pskb->tail -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
#if !defined(DELAY_REFILL_RX_BUF) || !defined(CONFIG_RTL8190_PRIV_SKB) //we create this, but we do not free it!
|
|
if (new_skb != NULL)
|
|
rtl_kfree_skb(priv, new_skb, _SKB_RX_);
|
|
#endif
|
|
goto rx_reuse;
|
|
}
|
|
|
|
}
|
|
|
|
// printk("pkt in\n");
|
|
SNMP_MIB_INC(dot11ReceivedFragmentCount, 1);
|
|
|
|
#if defined(SW_ANT_SWITCH)
|
|
if(priv->pshare->rf_ft_var.antSw_enable) {
|
|
dm_SWAW_RSSI_Check(priv, pfrinfo);
|
|
}
|
|
#endif
|
|
|
|
#if defined(RX_BUFFER_GATHER)
|
|
if (priv->pshare->gather_state != GATHER_STATE_NO) {
|
|
list_add_tail(&pfrinfo->rx_list, &priv->pshare->gather_list);
|
|
|
|
if (priv->pshare->gather_state == GATHER_STATE_LAST) {
|
|
if (!search_first_segment(priv, &pfrinfo))
|
|
reuse = 0;
|
|
else {
|
|
pskb = pfrinfo->pskb;
|
|
pfrinfo_update = 1;
|
|
}
|
|
priv->pshare->gather_state = GATHER_STATE_NO;
|
|
} else {
|
|
reuse = 0;
|
|
}
|
|
}
|
|
if (priv->pshare->gather_state == GATHER_STATE_NO && reuse)
|
|
#endif
|
|
{
|
|
#ifdef BEAMFORMING_SUPPORT
|
|
unsigned char *pframe = get_pframe(pfrinfo);
|
|
unsigned int frtype = GetFrameSubType(pframe);
|
|
if( frtype== Type_Action_No_Ack || frtype == Type_NDPA ) {
|
|
if( frtype== Type_Action_No_Ack) {
|
|
priv->pshare->rf_ft_var.csi_counter++;
|
|
if(priv->pshare->rf_ft_var.dumpcsi)
|
|
priv->pshare->rf_ft_var.csi_counter %= priv->pshare->rf_ft_var.dumpcsi;
|
|
if( priv->pshare->rf_ft_var.dumpcsi &&
|
|
priv->pshare->rf_ft_var.csi_counter==1)
|
|
{
|
|
#if 0
|
|
panic_printk("Action_no_Ack: %x %x %x %x\n",
|
|
get_desc(pdesc->Dword0),
|
|
get_desc(pdesc->Dword1),
|
|
get_desc(pdesc->Dword2),
|
|
get_desc(pdesc->Dword3) );
|
|
if ((pfrinfo->physt)&& (pfrinfo->driver_info_size > 0)) {
|
|
unsigned char *p = pfrinfo->driver_info;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else if(frtype == Type_NDPA) {
|
|
#if 0
|
|
panic_printk("Type_NDPA: %x %x %x %x\n",
|
|
get_desc(pdesc->Dword0),
|
|
get_desc(pdesc->Dword1),
|
|
get_desc(pdesc->Dword2),
|
|
get_desc(pdesc->Dword3)
|
|
);
|
|
#endif
|
|
Beamforming_GetNDPAFrame(priv, pframe);
|
|
#if 0
|
|
if ((pfrinfo->physt)&& (pfrinfo->driver_info_size > 0)) {
|
|
panic_printk("pRtRfdStatus:(%d)\n", pfrinfo->driver_info_size);
|
|
printHex(pfrinfo->driver_info, pfrinfo->driver_info_size);
|
|
panic_printk("\n");
|
|
}
|
|
#endif
|
|
}
|
|
reuse = 1;
|
|
}else
|
|
#endif
|
|
reuse = validate_mpdu(priv, pfrinfo);
|
|
}
|
|
|
|
if (reuse) {
|
|
pskb->data -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
pskb->tail -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
if (pfrinfo->gather_flag & GATHER_FIRST){
|
|
//flush_rx_list(priv);
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
reuse = 0;
|
|
DEBUG_WARN("Gather-First packet error, free skb\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#undef RTL_WLAN_DRV_RX_GATHER_GAP_THRESHOLD
|
|
}
|
|
} /* if (cmd&XXXX) */
|
|
|
|
if (!reuse) {
|
|
phw->rx_infoL[tail].pbuf = NULL; // clear pointer for not being accidently freed
|
|
|
|
#if 0
|
|
// allocate new one
|
|
pskb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_);
|
|
|
|
if (pskb == (struct sk_buff *)NULL)
|
|
{
|
|
DEBUG_WARN("out of skb_buff\n");
|
|
list_del(&pfrinfo->rx_list);
|
|
pskb = (struct sk_buff *)(phw->rx_infoL[tail].pbuf);
|
|
pskb->data -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
pskb->tail -= (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
|
|
goto rx_reuse;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
#if defined(CONFIG_RTL8190_PRIV_SKB)
|
|
#ifdef CONCURRENT_MODE
|
|
if (skb_free_num[priv->pshare->wlandev_idx] == 0 && priv->pshare->skb_queue.qlen == 0)
|
|
#else
|
|
if (skb_free_num == 0 && priv->pshare->skb_queue.qlen == 0)
|
|
#endif
|
|
{
|
|
refill = 0;
|
|
goto rx_done;
|
|
}
|
|
#endif
|
|
new_skb = rtl_dev_alloc_skb(priv, RX_BUF_LEN, _SKB_RX_, 0);
|
|
ASSERT(new_skb);
|
|
if(new_skb == NULL) {
|
|
printk("not enough memory...\n");
|
|
refill = 0;
|
|
goto rx_done;
|
|
}
|
|
#endif
|
|
pskb = new_skb;
|
|
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
init_rxdesc(pskb, phw->cur_rx_refill, priv);
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
#else
|
|
init_rxdesc(pskb, tail, priv);
|
|
#endif
|
|
|
|
goto rx_done;
|
|
} /* if (!reuse) */
|
|
#if !defined(DELAY_REFILL_RX_BUF)
|
|
else {
|
|
rtl_kfree_skb(priv, new_skb, _SKB_RX_);
|
|
}
|
|
#endif
|
|
|
|
rx_reuse:
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
#if defined(RX_BUFFER_GATHER)
|
|
cmp_flags = (tail != phw->cur_rx_refill) || (pfrinfo_update);
|
|
#else
|
|
cmp_flags = (tail != phw->cur_rx_refill);
|
|
#endif
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
|
|
if (cmp_flags)
|
|
{
|
|
phw->rx_infoL[tail].pbuf = NULL; // clear pointer for not being accidently freed
|
|
pskb->data = pskb->head;
|
|
pskb->tail = pskb->head;
|
|
skb_reserve(pskb, NET_SKB_PAD);
|
|
#if defined(CONFIG_RTL8196_RTL8366)
|
|
skb_reserve(pskb, 8);
|
|
#endif
|
|
#if defined(CONFIG_RTK_VOIP_VLAN_ID)
|
|
skb_reserve(pskb, 4);
|
|
#endif
|
|
refill_rx_ring(priv, pskb, NULL);
|
|
refill = 0;
|
|
} else
|
|
#endif /* defined(DELAY_REFILL_RX_BUF) */
|
|
{
|
|
#if defined(RX_BUFFER_GATHER)
|
|
pfrinfo->gather_flag = 0;
|
|
#endif
|
|
SMP_LOCK_SKB(x);
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
if (IS_PCIBIOS_TYPE) {
|
|
phw->rx_infoL[tail].paddr = get_physical_addr(priv, pskb->data, (RX_BUF_LEN - sizeof(struct rx_frinfo)), PCI_DMA_FROMDEVICE);
|
|
}
|
|
#endif
|
|
pdesc->Dword6 = set_desc(phw->rx_infoL[tail].paddr);
|
|
#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
|
|
// Remove it because pci_map_single() in get_physical_addr() already performed memory sync.
|
|
//rtl_cache_sync_wback(priv, (unsigned long)bus_to_virt(phw->rx_infoL[tail].paddr), RX_BUF_LEN - sizeof(struct rx_frinfo)-64, PCI_DMA_FROMDEVICE);
|
|
#else
|
|
rtl_cache_sync_wback(priv, (unsigned long)bus_to_virt(phw->rx_infoL[tail].paddr-CONFIG_LUNA_SLAVE_PHYMEM_OFFSET), RX_BUF_LEN - sizeof(struct rx_frinfo)-64, PCI_DMA_FROMDEVICE);
|
|
#endif
|
|
pdesc->Dword0 = set_desc((tail == (NUM_RX_DESC - 1)? RX_EOR : 0) | RX_OWN | (RX_BUF_LEN - sizeof(struct rx_frinfo)-64));
|
|
SMP_UNLOCK_SKB(x);
|
|
}
|
|
|
|
rx_done:
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_ENTER;
|
|
//tail = (tail + 1) % NUM_RX_DESC;
|
|
tail = ( ((tail+1)==NUM_RX_DESC)?0:tail+1);
|
|
phw->cur_rx = tail;
|
|
|
|
#if defined(DELAY_REFILL_RX_BUF)
|
|
if (refill) {
|
|
//phw->cur_rx_refill = (phw->cur_rx_refill + 1) % NUM_RX_DESC;
|
|
phw->cur_rx_refill = ( ((phw->cur_rx_refill+1)==NUM_RX_DESC)?0:phw->cur_rx_refill+1);
|
|
}
|
|
#endif
|
|
RTL_WLAN_RX_ATOMIC_PROTECT_EXIT;
|
|
} /* while(1) */
|
|
SMP_UNLOCK_RECV(y);
|
|
|
|
if (!IS_DRV_OPEN(priv))
|
|
return;
|
|
|
|
#if defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX)
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
if (!list_empty(&priv->wakeup_list))
|
|
process_dzqueue(priv);
|
|
|
|
#if defined(MBSSID)
|
|
if (priv->pmib->miscEntry.vap_enable) {
|
|
int i;
|
|
struct rtl8192cd_priv *priv_vap;
|
|
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i])) {
|
|
priv_vap = priv->pvap_priv[i];
|
|
if (!list_empty(&priv_vap->wakeup_list))
|
|
process_dzqueue(priv_vap);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef UNIVERSAL_REPEATER
|
|
else {
|
|
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
if (!list_empty(&GET_VXD_PRIV(priv)->wakeup_list))
|
|
process_dzqueue(GET_VXD_PRIV(priv));
|
|
}
|
|
#endif
|
|
#endif /* defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX) */
|
|
|
|
if(priv->pshare->skip_mic_chk)
|
|
--priv->pshare->skip_mic_chk;
|
|
}
|
|
}
|
|
|
|
#undef RTL_WLAN_RX_ATOMIC_PROTECT_ENTER
|
|
#undef RTL_WLAN_RX_ATOMIC_PROTECT_EXIT
|
|
|
|
#endif // CONFIG_PCI_HCI
|
|
|
|
// The purpose of reassemble is to assemble the frag into a complete one.
|
|
static struct rx_frinfo *reassemble(struct rtl8192cd_priv *priv, struct stat_info *pstat)
|
|
{
|
|
struct list_head *phead, *plist;
|
|
unsigned short seq=0;
|
|
unsigned char tofr_ds=0;
|
|
unsigned int iv, icv, mic, privacy=0, offset;
|
|
struct sk_buff *pskb;
|
|
struct rx_frinfo *pfrinfo, *pfirstfrinfo=NULL;
|
|
unsigned char *pframe=NULL, *pfirstframe=NULL, tail[16]; //4, 12, and 8 for WEP/TKIP/AES
|
|
unsigned long flags;
|
|
int i;
|
|
union PN48 last_PN;
|
|
|
|
struct list_head frag_list;
|
|
|
|
INIT_LIST_HEAD(&frag_list);
|
|
|
|
DEFRAG_LOCK(flags);
|
|
list_del_init(&pstat->defrag_list);
|
|
list_splice_init(&pstat->frag_list, &frag_list);
|
|
pstat->frag_count = 0;
|
|
DEFRAG_UNLOCK(flags);
|
|
|
|
phead = &frag_list;
|
|
|
|
// checking all the seq should be the same, and the frg should monotically increase
|
|
for(i=0, plist=phead->next; plist!=phead; plist=plist->next, i++)
|
|
{
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, mpdu_list);
|
|
pframe = get_pframe(pfrinfo);
|
|
|
|
if ((GetFragNum(pframe)) != i)
|
|
{
|
|
DEBUG_ERR("RX DROP: FragNum did not match, FragNum=%d, GetFragNum(pframe)=%d\n",
|
|
i, GetFragNum(pframe));
|
|
goto unchainned_all;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
seq = GetSequence(pframe);
|
|
privacy = GetPrivacy(pframe);
|
|
tofr_ds = pfrinfo->to_fr_ds;
|
|
if (get_sta_encrypt_algthm(priv, pstat) == _CCMP_PRIVACY_)
|
|
{
|
|
last_PN.val48 = 0;
|
|
last_PN._byte_.TSC0 = pframe[pfrinfo->hdr_len];
|
|
last_PN._byte_.TSC1 = pframe[pfrinfo->hdr_len+1];
|
|
last_PN._byte_.TSC2 = pframe[pfrinfo->hdr_len+4];
|
|
last_PN._byte_.TSC3 = pframe[pfrinfo->hdr_len+5];
|
|
last_PN._byte_.TSC4 = pframe[pfrinfo->hdr_len+6];
|
|
last_PN._byte_.TSC5 = pframe[pfrinfo->hdr_len+7];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (get_sta_encrypt_algthm(priv, pstat) == _CCMP_PRIVACY_ &&
|
|
sta_packet_number_check(priv, &last_PN, pframe, pfrinfo->hdr_len) != SUCCESS)
|
|
{
|
|
DEBUG_ERR("RX DROP: Non-consecutive Packet Number\n");
|
|
goto unchainned_all;
|
|
}
|
|
|
|
if (GetSequence(pframe) != seq)
|
|
{
|
|
DEBUG_ERR("RX DROP: Seq is not correct, seq=%d, GetSequence(pframe)=%d\n",
|
|
seq, GetSequence(pframe));
|
|
goto unchainned_all;
|
|
}
|
|
|
|
if (GetPrivacy(pframe) != privacy)
|
|
{
|
|
DEBUG_ERR("RX DROP: Privacy is not correct, privacy=%d, GetPrivacy(pframe)=%d\n",
|
|
privacy, GetPrivacy(pframe));
|
|
goto unchainned_all;
|
|
}
|
|
|
|
if (pfrinfo->to_fr_ds != tofr_ds)
|
|
{
|
|
DEBUG_ERR("RX DROP: to_fr_ds did not match, tofr_ds=%d, pfrinfo->to_fr_ds=%d\n",
|
|
tofr_ds, pfrinfo->to_fr_ds);
|
|
goto unchainned_all;
|
|
}
|
|
}
|
|
}
|
|
|
|
privacy = get_privacy(priv, pstat, &iv, &icv, &mic);
|
|
|
|
offset = iv;
|
|
offset += get_hdrlen(priv, pframe);
|
|
|
|
// below we are going to re-assemble the whole pkts...
|
|
for(i=0, plist=phead->next; plist!=phead; plist=plist->next, i++)
|
|
{
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, mpdu_list);
|
|
|
|
if (pfrinfo->pktlen <= (offset + icv + mic))
|
|
{
|
|
DEBUG_ERR("RX DROP: Frame length bad (%d)\n", pfrinfo->pktlen);
|
|
pfirstfrinfo = NULL;
|
|
goto unchainned_all;
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
pfirstfrinfo = pfrinfo;
|
|
pfirstframe = get_pframe(pfrinfo);
|
|
pfirstframe += pfrinfo->pktlen - (icv + mic);
|
|
|
|
if (icv + mic)
|
|
{
|
|
memcpy((void *)tail, (void *)(pfirstframe), (icv + mic));
|
|
pfirstfrinfo->pktlen -= (icv + mic);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// check if too many frags...
|
|
pfirstfrinfo->pktlen += (pfrinfo->pktlen - offset - icv - mic);
|
|
#if defined(CONFIG_PCI_HCI)
|
|
if (pfirstfrinfo->pktlen >= (RX_BUF_LEN - offset - icv - mic - 200))
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
if ((pfirstframe + (pfrinfo->pktlen - offset)) >=
|
|
((unsigned char *)((unsigned long)(pfirstfrinfo->pskb->end))))
|
|
#endif
|
|
{
|
|
DEBUG_ERR("RX DROP: over rx buf size after reassemble...\n");
|
|
pfirstfrinfo = NULL;
|
|
goto unchainned_all;
|
|
}
|
|
|
|
// here we should check if all these frags exceeds the buf size
|
|
memcpy(pfirstframe, get_pframe(pfrinfo) + offset, pfrinfo->pktlen - offset - icv - mic);
|
|
pfirstframe += (pfrinfo->pktlen - offset - icv - mic);
|
|
}
|
|
|
|
if (icv + mic)
|
|
{
|
|
memcpy((void *)pfirstframe, (void *)tail, (icv + mic));
|
|
pfirstfrinfo->pktlen += (icv + mic);
|
|
}
|
|
|
|
// take the first frame out of fragment list
|
|
plist = phead->next;
|
|
list_del_init(plist);
|
|
|
|
unchainned_all: // dequeue all the queued-up frag, free skb, and init_list_head again...
|
|
|
|
while (!list_empty(phead)) {
|
|
plist = phead->next;
|
|
list_del(plist);
|
|
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, mpdu_list);
|
|
pskb = get_pskb(pfrinfo);
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_IRQ_);
|
|
|
|
if (pfirstfrinfo == NULL)
|
|
priv->ext_stats.rx_data_drops++;
|
|
}
|
|
|
|
return pfirstfrinfo;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------------------
|
|
So far, only data pkt will be defragmented.
|
|
-----------------------------------------------------------------------------------------*/
|
|
static struct rx_frinfo *defrag_frame_main(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *da, *sa;
|
|
struct stat_info *pstat=NULL;
|
|
unsigned int res, hdr_len, len;
|
|
int status, privacy=0, pos;
|
|
unsigned long flags;
|
|
unsigned char tkipmic[8], rxmic[8];
|
|
unsigned char *pframe;
|
|
unsigned char hw_didnt_decrypt=0;
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
hdr_len = pfrinfo->hdr_len;
|
|
da = pfrinfo->da;
|
|
sa = pfrinfo->sa;
|
|
len = pfrinfo->pktlen;
|
|
|
|
/*---------first of all check if sa is assocated---------*/
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#if defined(CONFIG_RTK_MESH) || defined(WDS)
|
|
// for 802.11s case, pstat will not be NULL, because we have check it in validate-mpdu
|
|
if (pfrinfo->to_fr_ds == 3) {
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
if (pstat == NULL){
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX Drop: WDS rx data with pstat == NULL\n");
|
|
goto free_skb_in_defrag;
|
|
} else {
|
|
goto check_privacy;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef A4_STA
|
|
if (pfrinfo->to_fr_ds == 3 && priv->pshare->rf_ft_var.a4_enable) {
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
if (pstat && !(pstat->state & WIFI_A4_STA))
|
|
add_a4_client(priv, pstat);
|
|
|
|
a4_sta_add(priv, pstat, sa);
|
|
}
|
|
else
|
|
#endif
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
// printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
//if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, sa);
|
|
// printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & WIFI_STATION_STATE) {
|
|
unsigned char *bssid = GetAddr2Ptr(pframe);
|
|
pstat = get_stainfo(priv, bssid);
|
|
}
|
|
else // Ad-hoc
|
|
pstat = get_stainfo(priv, sa);
|
|
#endif
|
|
|
|
if (pstat == NULL)
|
|
{
|
|
status = _RSON_CLS2_;
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: class 2 error!\n");
|
|
goto data_defrag_error;
|
|
}
|
|
else if (!(pstat->state & WIFI_ASOC_STATE))
|
|
{
|
|
status = _RSON_CLS3_;
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: class 3 error!\n");
|
|
goto data_defrag_error;
|
|
}
|
|
else {}
|
|
|
|
/*-------------------get privacy-------------------*/
|
|
#if defined(CONFIG_RTK_MESH) || defined(WDS)
|
|
check_privacy:
|
|
#endif
|
|
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#ifdef CONFIG_RTK_MESH
|
|
//modify by Joule for SECURITY
|
|
if(pfrinfo->is_11s)
|
|
privacy = IS_MCAST(da) ? _NO_PRIVACY_ : get_sta_encrypt_algthm(priv, pstat);
|
|
else
|
|
#endif
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds == 3)
|
|
privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
|
|
else
|
|
#endif
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else {
|
|
if (IS_MCAST(da)) {
|
|
#if defined(UNIVERSAL_REPEATER) || defined(MBSSID)
|
|
if (!IS_ROOT_INTERFACE(priv) && !IEEE8021X_FUN &&
|
|
((priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_40_PRIVACY_) ||
|
|
(priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _WEP_104_PRIVACY_))){
|
|
privacy = priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm;
|
|
}else
|
|
#endif
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
if (pstat&&pstat->wapiInfo&&pstat->wapiInfo->wapiType!=wapiDisable){
|
|
privacy = _WAPI_SMS4_;
|
|
}else
|
|
#endif
|
|
{
|
|
// iv, icv and mic are not be used below. Don't care them!
|
|
privacy = priv->pmib->dot11GroupKeysTable.dot11Privacy;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
}
|
|
}
|
|
|
|
if (IS_MCAST(da))
|
|
{
|
|
if (GetTupleCache(pframe) == pstat->tpcache_mcast)
|
|
{
|
|
priv->ext_stats.rx_decache++;
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
goto free_skb_in_defrag;
|
|
}
|
|
else
|
|
pstat->tpcache_mcast = GetTupleCache(pframe);
|
|
}
|
|
else
|
|
#endif
|
|
/*-------------------check retry-------------------*/
|
|
if (is_qos_data(pframe)) {
|
|
pos = GetSequence(pframe) & (TUPLE_WINDOW - 1);
|
|
if (IS_MCAST(da)) {
|
|
// ignore check of multicast packet to workaround Veriware test.
|
|
}
|
|
else if (GetTupleCache(pframe) == pstat->tpcache[pfrinfo->tid][pos]) {
|
|
priv->ext_stats.rx_decache++;
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
goto free_skb_in_defrag;
|
|
}
|
|
else
|
|
pstat->tpcache[pfrinfo->tid][pos] = GetTupleCache(pframe);
|
|
}
|
|
else {
|
|
if (GetRetry(pframe)) {
|
|
if (GetTupleCache(pframe) == pstat->tpcache_mgt) {
|
|
priv->ext_stats.rx_decache++;
|
|
SNMP_MIB_INC(dot11FrameDuplicateCount, 1);
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
pstat->tpcache_mgt = GetTupleCache(pframe);
|
|
}
|
|
|
|
/*-------------------------------------------------------*/
|
|
/*-----------insert MPDU-based decrypt below-------------*/
|
|
/*-------------------------------------------------------*/
|
|
|
|
#ifdef SUPPORT_SNMP_MIB
|
|
if (GetPrivacy(pframe) && privacy == _NO_PRIVACY_)
|
|
SNMP_MIB_INC(dot11WEPUndecryptableCount, 1);
|
|
|
|
if (!GetPrivacy(pframe) && privacy != _NO_PRIVACY_)
|
|
SNMP_MIB_INC(dot11WEPExcludedCount, 1);
|
|
#endif
|
|
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
if (privacy==_WAPI_SMS4_)
|
|
{
|
|
//WAPI authentication packet is not encryption, but privacy==_WAPI_SMS4_. This can avoid WAPI authentication packet is droped!!!
|
|
}
|
|
else
|
|
#endif
|
|
if (!GetPrivacy(pframe) && privacy != _NO_PRIVACY_)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Recv unencrypted packet!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
if (GetPrivacy(pframe) && !UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe)), 0) && pfrinfo->sw_dec)
|
|
#else
|
|
if (GetPrivacy(pframe) && !UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe))) && pfrinfo->sw_dec)
|
|
#endif
|
|
{
|
|
printk( "Rx packet, hardware did not decrypt\n" );
|
|
hw_didnt_decrypt = 1;
|
|
}
|
|
|
|
// check whether WEP bit is set in mac header and sw encryption
|
|
#ifdef CONFIG_IEEE80211W
|
|
if (GetPrivacy(pframe) && (UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe)), 0) || hw_didnt_decrypt)) // 0: PMF
|
|
#else
|
|
if (GetPrivacy(pframe) && (UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe))) || hw_didnt_decrypt))
|
|
#endif
|
|
{
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
if (privacy==_WAPI_SMS4_)
|
|
{
|
|
/* Decryption */
|
|
// SAVE_INT_AND_CLI(flags);
|
|
res = SecSWSMS4Decryption(priv, pstat, pfrinfo);
|
|
// RESTORE_INT(flags);
|
|
if (res == FAIL)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: WAPI decrpt error!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
pframe = get_pframe(pfrinfo);
|
|
} else
|
|
#endif
|
|
if (privacy == _TKIP_PRIVACY_)
|
|
{
|
|
res = tkip_decrypt(priv, pfrinfo, pfrinfo->pktlen);
|
|
if (res == FAIL)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Tkip decrpt error!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
else if (privacy == _CCMP_PRIVACY_)
|
|
{
|
|
res = aesccmp_decrypt(priv, pfrinfo
|
|
#ifdef CONFIG_IEEE80211W
|
|
, 0
|
|
#endif
|
|
);
|
|
if (res == FAIL)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: AES decrpt error!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
else if (privacy == _WEP_40_PRIVACY_ || privacy == _WEP_104_PRIVACY_)
|
|
{
|
|
res = wep_decrypt(priv, pfrinfo, pfrinfo->pktlen, privacy, 0);
|
|
if (res == FAIL)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: WEP decrpt error!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG_ERR("RX DROP: encrypted packet but no key in sta or wrong enc type!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
|
|
}
|
|
/*----------------End of MPDU-based decrypt--------------*/
|
|
|
|
if (GetMFrag(pframe))
|
|
{
|
|
if (pstat->frag_count > MAX_FRAG_COUNT)
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: station has received too many frags!\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
|
|
DEFRAG_LOCK(flags);
|
|
|
|
if (pstat->frag_count == 0) // the first frag...
|
|
pstat->frag_to = priv->frag_to;
|
|
|
|
if (list_empty(&pstat->defrag_list))
|
|
list_add_tail(&pstat->defrag_list, &priv->defrag_list);
|
|
|
|
list_add_tail(&pfrinfo->mpdu_list, &pstat->frag_list);
|
|
pstat->frag_count++;
|
|
|
|
DEFRAG_UNLOCK(flags);
|
|
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
else
|
|
{
|
|
if(GetFragNum(pframe))
|
|
{
|
|
DEFRAG_LOCK(flags);
|
|
list_add_tail(&pfrinfo->mpdu_list, &pstat->frag_list);
|
|
DEFRAG_UNLOCK(flags);
|
|
|
|
pfrinfo = reassemble(priv, pstat);
|
|
if (pfrinfo == NULL)
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
}
|
|
|
|
/*-----discard non-authorized packet before MIC check----*/
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#if defined(CONFIG_RTK_MESH) || defined(WDS)
|
|
if (pfrinfo->to_fr_ds != 3)
|
|
#endif
|
|
if (auth_filter(priv, pstat, pfrinfo) == FAIL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: due to auth_filter fails\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & WIFI_STATION_STATE) {
|
|
if (auth_filter(priv, pstat, pfrinfo) == FAIL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: due to auth_filter fails\n");
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
//insert MSDU-based digest here!
|
|
/*------------------------------------------------------------------------*/
|
|
if (GetPrivacy(pframe) && (privacy == _TKIP_PRIVACY_))
|
|
{
|
|
pframe = get_pframe(pfrinfo);
|
|
len = pfrinfo->pktlen;
|
|
|
|
//truncate Michael...
|
|
memcpy((void *)rxmic, (void *)(pframe + len - 8 - 4), 8); // 8 michael, 4 icv
|
|
SAVE_INT_AND_CLI(flags);
|
|
tkip_rx_mic(priv, pframe, da, sa,
|
|
pfrinfo->tid, pframe + hdr_len + 8,
|
|
len - hdr_len - 8 - 8 - 4, tkipmic, 0); // 8 IV, 8 Mic, 4 ICV
|
|
RESTORE_INT(flags);
|
|
|
|
if(memcmp(rxmic, tkipmic, 8))
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
#ifdef _SINUX_
|
|
printk("RX DROP: MIC error! Indicate to protection mechanism\n");
|
|
mic_error_report(0);
|
|
#else
|
|
DEBUG_ERR("RX DROP: MIC error! Indicate to protection mechanism\n");
|
|
#endif
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
#ifdef RTL_WPA2
|
|
#ifdef _SINUX_
|
|
printk("%s: DOT11_Indicate_MIC_Failure %02X:%02X:%02X:%02X:%02X:%02X \n", (char *)__FUNCTION__,pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5]);
|
|
#else
|
|
PRINT_INFO("%s: DOT11_Indicate_MIC_Failure %02X:%02X:%02X:%02X:%02X:%02X \n", (char *)__FUNCTION__,pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5]);
|
|
#endif
|
|
|
|
#endif
|
|
#ifdef WDS
|
|
if ((pfrinfo->to_fr_ds == 3) &&
|
|
pstat && (pstat->state & WIFI_WDS))
|
|
goto free_skb_in_defrag;
|
|
#endif
|
|
DOT11_Indicate_MIC_Failure(priv->dev, pstat);
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & WIFI_STATION_STATE)
|
|
DOT11_Indicate_MIC_Failure_Clnt(priv, sa);
|
|
#endif
|
|
goto free_skb_in_defrag;
|
|
}
|
|
}
|
|
|
|
return pfrinfo;
|
|
|
|
data_defrag_error:
|
|
|
|
if (OPMODE & WIFI_AP_STATE){
|
|
issue_deauth(priv,sa,status);
|
|
if (pstat != NULL){
|
|
#if defined(CONFIG_PCI_HCI)
|
|
free_stainfo(priv, pstat);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_del_sta(priv, pstat);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else {
|
|
if (pstat == NULL) {
|
|
DEBUG_ERR("rx data with pstat == NULL\n");
|
|
}
|
|
else if (!(pstat->state & WIFI_ASOC_STATE)) {
|
|
DEBUG_ERR("rx data with pstat not associated\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
free_skb_in_defrag:
|
|
|
|
rtl_kfree_skb(priv, get_pskb(pfrinfo), _SKB_RX_);
|
|
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
|
|
|
|
static struct rx_frinfo *defrag_frame(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
struct sk_buff *pskb = get_pskb(pfrinfo);
|
|
struct rx_frinfo *prx_frinfo = NULL;
|
|
unsigned int encrypt;
|
|
unsigned char *pframe;
|
|
|
|
// rx a encrypt packet but encryption is not enabled in local mib, discard it
|
|
pframe = get_pframe(pfrinfo);
|
|
encrypt = GetPrivacy(pframe);
|
|
|
|
//modify by Joule for SECURITY
|
|
// here maybe need do some tune; plus
|
|
#ifdef CONFIG_RTK_MESH /*-------*/
|
|
if (encrypt && (
|
|
(pfrinfo->to_fr_ds==3 && (
|
|
#ifdef WDS
|
|
GET_MIB(priv)->dot1180211sInfo.mesh_enable ==0 ?
|
|
priv->pmib->dot11WdsInfo.wdsPrivacy==_NO_PRIVACY_ :
|
|
#endif
|
|
priv->pmib->dot11sKeysTable.dot11Privacy ==_NO_PRIVACY_ )) ||
|
|
(pfrinfo->to_fr_ds!=3 && priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm==_NO_PRIVACY_
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
&& priv->pmib->wapiInfo.wapiType==wapiDisable
|
|
#endif
|
|
)))
|
|
#else /*-------*/
|
|
// origin
|
|
#ifdef WDS
|
|
if (encrypt && (
|
|
(pfrinfo->to_fr_ds==3 && priv->pmib->dot11WdsInfo.wdsPrivacy==_NO_PRIVACY_) ||
|
|
(pfrinfo->to_fr_ds!=3 && priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm==_NO_PRIVACY_))
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
&& priv->pmib->wapiInfo.wapiType==wapiDisable
|
|
#endif
|
|
)
|
|
#else
|
|
if (encrypt && priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _NO_PRIVACY_
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
&& priv->pmib->wapiInfo.wapiType==wapiDisable
|
|
#endif
|
|
)
|
|
#endif
|
|
#endif/*-------*/
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Discard a encrypted packet!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
if (pfrinfo->to_fr_ds==3 && !encrypt && (
|
|
#ifdef WDS
|
|
GET_MIB(priv)->dot1180211sInfo.mesh_enable ==0 ?
|
|
priv->pmib->dot11WdsInfo.wdsPrivacy!=_NO_PRIVACY_ :
|
|
#endif
|
|
(priv->pmib->dot11sKeysTable.dot11Privacy != _NO_PRIVACY_ && !IS_MCAST(pfrinfo->da)))) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Discard a un-encrypted WDS/MESH packet!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
SNMP_MIB_INC(dot11WEPExcludedCount, 1);
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
#else
|
|
//origin
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds==3 && !encrypt && priv->pmib->dot11WdsInfo.wdsPrivacy!=_NO_PRIVACY_) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Discard a un-encrypted WDS packet!\n");
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
SNMP_MIB_INC(dot11WEPExcludedCount, 1);
|
|
return (struct rx_frinfo *)NULL;
|
|
}
|
|
#endif
|
|
#endif
|
|
prx_frinfo = defrag_frame_main(priv, pfrinfo);
|
|
|
|
return prx_frinfo;
|
|
}
|
|
|
|
|
|
static int auth_filter(struct rtl8192cd_priv *priv, struct stat_info *pstat,
|
|
struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned int hdr_len;
|
|
unsigned char *pframe, *pbuf;
|
|
unsigned short proto;
|
|
|
|
// hdr_len = pfrinfo->hdr_len;
|
|
// pframe = get_pframe(pfrinfo);
|
|
// pbuf = pframe + hdr_len + sizeof(struct wlan_llc_t) + 3;
|
|
// proto = *(unsigned short *)pbuf;
|
|
|
|
if(IEEE8021X_FUN) {
|
|
if (pstat) {
|
|
if (pstat->ieee8021x_ctrlport) // controlled port is enable...
|
|
return SUCCESS;
|
|
else {
|
|
//only 802.1x frame can pass...
|
|
hdr_len = pfrinfo->hdr_len;
|
|
pframe = get_pframe(pfrinfo);
|
|
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
if (GetPrivacy(pframe))
|
|
pbuf = pframe + hdr_len + sizeof(struct wlan_llc_t) + 3 + 8; // 8 bytes IV
|
|
else
|
|
#endif
|
|
pbuf = pframe + hdr_len + sizeof(struct wlan_llc_t) + 3;
|
|
|
|
proto = *(unsigned short *)pbuf;
|
|
if (proto == __constant_htons(0x888e))
|
|
return SUCCESS;
|
|
else {
|
|
return FAIL;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DEBUG_ERR("pstat == NULL in auth_filter\n");
|
|
return FAIL;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
void SendQosNullData(struct rtl8192cd_priv *priv, unsigned char *da)
|
|
{
|
|
struct wifi_mib *pmib;
|
|
unsigned char *hwaddr;
|
|
unsigned char tempQosControl[2];
|
|
DECLARE_TXINSN(txinsn);
|
|
|
|
txinsn.retry = priv->pmib->dot11OperationEntry.dot11ShortRetryLimit;
|
|
|
|
pmib = GET_MIB(priv);
|
|
|
|
hwaddr = pmib->dot11OperationEntry.hwaddr;
|
|
|
|
txinsn.q_num = MANAGE_QUE_NUM;
|
|
txinsn.tx_rate = find_rate(priv, NULL, 0, 1);
|
|
txinsn.lowest_tx_rate = txinsn.tx_rate;
|
|
txinsn.fixed_rate = 1;
|
|
txinsn.fr_type = _PRE_ALLOCHDR_;
|
|
txinsn.phdr = get_wlanhdr_from_poll(priv);
|
|
txinsn.pframe = NULL;
|
|
|
|
if (txinsn.phdr == NULL)
|
|
goto send_qos_null_fail;
|
|
|
|
memset((void *)(txinsn.phdr), 0, sizeof (struct wlan_hdr));
|
|
|
|
SetFrameSubType(txinsn.phdr, BIT(7) | WIFI_DATA_NULL);
|
|
SetFrDs(txinsn.phdr);
|
|
memcpy((void *)GetAddr1Ptr((txinsn.phdr)), da, MACADDRLEN);
|
|
memcpy((void *)GetAddr2Ptr((txinsn.phdr)), hwaddr, MACADDRLEN);
|
|
memcpy((void *)GetAddr3Ptr((txinsn.phdr)), hwaddr, MACADDRLEN);
|
|
txinsn.hdr_len = WLAN_HDR_A3_QOS_LEN;
|
|
|
|
memset(tempQosControl, 0, 2);
|
|
tempQosControl[0] = 0x07; //set priority to VO
|
|
tempQosControl[0] |= BIT(4); //set EOSP
|
|
memcpy((void *)GetQosControl((txinsn.phdr)), tempQosControl, 2);
|
|
|
|
if ((rtl8192cd_firetx(priv, &txinsn)) == SUCCESS)
|
|
return;
|
|
|
|
send_qos_null_fail:
|
|
|
|
if (txinsn.phdr)
|
|
release_wlanhdr_to_poll(priv, txinsn.phdr);
|
|
}
|
|
|
|
#ifdef CONFIG_PCI_HCI
|
|
static void process_APSD_dz_queue(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned short tid)
|
|
{
|
|
unsigned int deque_level = 1; // deque pkts level, VO = 4, VI = 3, BE = 2, BK = 1
|
|
struct sk_buff *pskb = NULL;
|
|
DECLARE_TXINSN(txinsn);
|
|
|
|
if ((((tid == 7) || (tid == 6)) && !(pstat->apsd_bitmap & 0x01))
|
|
|| (((tid == 5) || (tid == 4)) && !(pstat->apsd_bitmap & 0x02))
|
|
|| (((tid == 3) || (tid == 0)) && !(pstat->apsd_bitmap & 0x08))
|
|
|| (((tid == 2) || (tid == 1)) && !(pstat->apsd_bitmap & 0x04))) {
|
|
DEBUG_INFO("RcvQosNull legacy ps tid=%d", tid);
|
|
return;
|
|
}
|
|
|
|
if (pstat->apsd_pkt_buffering == 0)
|
|
goto sendQosNull;
|
|
|
|
if ((pstat->apsd_bitmap & 0x01) && (!isFFempty(pstat->VO_dz_queue->head, pstat->VO_dz_queue->tail)))
|
|
deque_level = 4;
|
|
else if ((pstat->apsd_bitmap & 0x02) && (!isFFempty(pstat->VI_dz_queue->head, pstat->VI_dz_queue->tail)))
|
|
deque_level = 3;
|
|
else if ((pstat->apsd_bitmap & 0x08) && (!isFFempty(pstat->BE_dz_queue->head, pstat->BE_dz_queue->tail)))
|
|
deque_level = 2;
|
|
else if ((!(pstat->apsd_bitmap & 0x04)) || (isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail))) {
|
|
//send QoS Null packet
|
|
sendQosNull:
|
|
SendQosNullData(priv, pstat->hwaddr);
|
|
DEBUG_INFO("sendQosNull tid=%d\n", tid);
|
|
return;
|
|
}
|
|
|
|
while(1) {
|
|
if (deque_level == 4) {
|
|
pskb = (struct sk_buff *)deque(priv, &(pstat->VO_dz_queue->head), &(pstat->VO_dz_queue->tail),
|
|
(unsigned long)(pstat->VO_dz_queue->pSkb), NUM_APSD_TXPKT_QUEUE);
|
|
if (pskb == NULL) {
|
|
if ((pstat->apsd_bitmap & 0x02) && (!isFFempty(pstat->VI_dz_queue->head, pstat->VI_dz_queue->tail)))
|
|
deque_level--;
|
|
else if ((pstat->apsd_bitmap & 0x08) && (!isFFempty(pstat->BE_dz_queue->head, pstat->BE_dz_queue->tail)))
|
|
deque_level = 2;
|
|
else if ((pstat->apsd_bitmap & 0x04) && (!isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail)))
|
|
deque_level = 1;
|
|
else
|
|
deque_level = 0;
|
|
}
|
|
else {
|
|
DEBUG_INFO("deque VO pkt\n");
|
|
}
|
|
}
|
|
else if (deque_level == 3) {
|
|
pskb = (struct sk_buff *)deque(priv, &(pstat->VI_dz_queue->head), &(pstat->VI_dz_queue->tail),
|
|
(unsigned long)(pstat->VI_dz_queue->pSkb), NUM_APSD_TXPKT_QUEUE);
|
|
if (pskb == NULL) {
|
|
if ((pstat->apsd_bitmap & 0x08) && (!isFFempty(pstat->BE_dz_queue->head, pstat->BE_dz_queue->tail)))
|
|
deque_level--;
|
|
else if ((pstat->apsd_bitmap & 0x04) && (!isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail)))
|
|
deque_level = 1;
|
|
else
|
|
deque_level = 0;
|
|
}
|
|
else {
|
|
DEBUG_INFO("deque VI pkt\n");
|
|
}
|
|
}
|
|
else if (deque_level == 2) {
|
|
pskb = (struct sk_buff *)deque(priv, &(pstat->BE_dz_queue->head), &(pstat->BE_dz_queue->tail),
|
|
(unsigned long)(pstat->BE_dz_queue->pSkb), NUM_APSD_TXPKT_QUEUE);
|
|
if (pskb == NULL) {
|
|
if ((pstat->apsd_bitmap & 0x04) && (!isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail)))
|
|
deque_level--;
|
|
else
|
|
deque_level = 0;
|
|
}
|
|
else {
|
|
DEBUG_INFO("deque BE pkt\n");
|
|
}
|
|
}
|
|
else if (deque_level == 1) {
|
|
pskb = (struct sk_buff *)deque(priv, &(pstat->BK_dz_queue->head), &(pstat->BK_dz_queue->tail),
|
|
(unsigned long)(pstat->BK_dz_queue->pSkb), NUM_APSD_TXPKT_QUEUE);
|
|
if(pskb)
|
|
DEBUG_INFO("deque BK pkt\n");
|
|
}
|
|
|
|
if (pskb) {
|
|
txinsn.q_num = BE_QUEUE;
|
|
txinsn.fr_type = _SKB_FRAME_TYPE_;
|
|
txinsn.pframe = pskb;
|
|
txinsn.phdr = (UINT8 *)get_wlanllchdr_from_poll(priv);
|
|
pskb->cb[1] = 0;
|
|
|
|
if (pskb->len > priv->pmib->dot11OperationEntry.dot11RTSThreshold)
|
|
txinsn.retry = priv->pmib->dot11OperationEntry.dot11LongRetryLimit;
|
|
else
|
|
txinsn.retry = priv->pmib->dot11OperationEntry.dot11ShortRetryLimit;
|
|
|
|
if (txinsn.phdr == NULL) {
|
|
DEBUG_ERR("Can't alloc wlan header!\n");
|
|
goto xmit_skb_fail;
|
|
}
|
|
|
|
memset((void *)txinsn.phdr, 0, sizeof(struct wlanllc_hdr));
|
|
|
|
SetFrDs(txinsn.phdr);
|
|
SetFrameSubType(txinsn.phdr, WIFI_QOS_DATA);
|
|
if (((deque_level == 4) && (!isFFempty(pstat->VO_dz_queue->head, pstat->VO_dz_queue->tail)) && (pstat->apsd_bitmap & 0x01)) ||
|
|
((deque_level >= 3) && (!isFFempty(pstat->VI_dz_queue->head, pstat->VI_dz_queue->tail)) && (pstat->apsd_bitmap & 0x02)) ||
|
|
((deque_level >= 2) && (!isFFempty(pstat->BE_dz_queue->head, pstat->BE_dz_queue->tail)) && (pstat->apsd_bitmap & 0x08)) ||
|
|
((deque_level >= 1) && (!isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail)) && (pstat->apsd_bitmap & 0x04)))
|
|
SetMData(txinsn.phdr);
|
|
|
|
if (rtl8192cd_wlantx(priv, &txinsn) == CONGESTED) {
|
|
|
|
xmit_skb_fail:
|
|
priv->ext_stats.tx_drops++;
|
|
DEBUG_WARN("TX DROP: Congested!\n");
|
|
if (txinsn.phdr)
|
|
release_wlanllchdr_to_poll(priv, txinsn.phdr);
|
|
if (pskb)
|
|
rtl_kfree_skb(priv, pskb, _SKB_TX_);
|
|
}
|
|
}
|
|
else if (deque_level <= 1) {
|
|
if ((pstat->apsd_pkt_buffering) &&
|
|
(isFFempty(pstat->VO_dz_queue->head, pstat->VO_dz_queue->tail)) &&
|
|
(isFFempty(pstat->VI_dz_queue->head, pstat->VI_dz_queue->tail)) &&
|
|
(isFFempty(pstat->BE_dz_queue->head, pstat->BE_dz_queue->tail)) &&
|
|
(isFFempty(pstat->BK_dz_queue->head, pstat->BK_dz_queue->tail)))
|
|
pstat->apsd_pkt_buffering = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif // CONFIG_PCI_HCI
|
|
|
|
|
|
static void process_qos_null(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *pframe;
|
|
struct stat_info *pstat = NULL;
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
//printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, get_sa(pframe));
|
|
//printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
|
|
if ((!(OPMODE & WIFI_AP_STATE)) || (pstat == NULL)) {
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
return;
|
|
}
|
|
|
|
if (pstat->apsd_bitmap & 0x0f)
|
|
process_APSD_dz_queue(priv, pstat, pfrinfo->tid);
|
|
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(DRVMAC_LB) && defined(WIFI_WMM)
|
|
static void process_lb_qos_null(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
// unsigned char *pframe;
|
|
// unsigned int aid;
|
|
// struct stat_info *pstat = NULL;
|
|
|
|
// pframe = get_pframe(pfrinfo);
|
|
// aid = GetAid(pframe);
|
|
// pstat = get_aidinfo(priv, aid);
|
|
|
|
// if ((!(OPMODE & WIFI_AP_STATE)) || (pstat == NULL) || (memcmp(pstat->hwaddr, get_sa(pframe), MACADDRLEN))) {
|
|
// rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
// return;
|
|
// }
|
|
// process_APSD_dz_queue(priv, pstat, pfrinfo->tid);
|
|
|
|
#if 0
|
|
if (pfrinfo->pskb && pfrinfo->pskb->data) {
|
|
unsigned int *p_skb_int = (unsigned int *)pfrinfo->pskb->data;
|
|
printk("LB RX FRAME =====>>\n");
|
|
printk("0x%08x 0x%08x 0x%08x 0x%08x\n", *p_skb_int, *(p_skb_int+1), *(p_skb_int+2), *(p_skb_int+3));
|
|
printk("0x%08x 0x%08x 0x%08x 0x%08x\n", *(p_skb_int+4), *(p_skb_int+5), *(p_skb_int+6), *(p_skb_int+7));
|
|
printk("LB RX FRAME <<=====\n");
|
|
}
|
|
#endif
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
|
|
|
|
static void process_lb_qos(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
// unsigned char *pframe;
|
|
// unsigned int aid;
|
|
// struct stat_info *pstat = NULL;
|
|
|
|
// pframe = get_pframe(pfrinfo);
|
|
// aid = GetAid(pframe);
|
|
// pstat = get_aidinfo(priv, aid);
|
|
|
|
// if ((!(OPMODE & WIFI_AP_STATE)) || (pstat == NULL) || (memcmp(pstat->hwaddr, get_sa(pframe), MACADDRLEN))) {
|
|
// rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
// return;
|
|
// }
|
|
// process_APSD_dz_queue(priv, pstat, pfrinfo->tid);
|
|
|
|
#if 1
|
|
if (pfrinfo->pskb && pfrinfo->pskb->data) {
|
|
unsigned char *p_skb_int = (unsigned char *)pfrinfo->pskb->data;
|
|
unsigned int payload_length = 0, i = 0, mismatch = 0;
|
|
unsigned char matching = 0;
|
|
|
|
if (pfrinfo->pktlen && pfrinfo->hdr_len && pfrinfo->pktlen > pfrinfo->hdr_len) {
|
|
payload_length = pfrinfo->pktlen - pfrinfo->hdr_len;
|
|
if (payload_length >= 2048)
|
|
printk("LB Qos RX, payload max hit!\n");
|
|
// if (payload_length > 32)
|
|
// payload_length = 32;
|
|
}
|
|
else {
|
|
if (!pfrinfo->pktlen)
|
|
printk("LB Qos RX, zero pktlen!!!\n");
|
|
else if (!pfrinfo->hdr_len)
|
|
printk("LB Qos RX, zero hdr_len!!!\n");
|
|
else if (pfrinfo->pktlen < pfrinfo->hdr_len)
|
|
printk("LB Qos RX, pktlen < hdr_len!!!\n");
|
|
else
|
|
printk("LB Qos RX, empty payload.\n");
|
|
goto out;
|
|
}
|
|
|
|
p_skb_int += pfrinfo->hdr_len;
|
|
|
|
// printk("LB RX >> ");
|
|
// for (i = 0; i < payload_length; i++) {
|
|
// if (i>0 && !(i%4))
|
|
// printk(" ");
|
|
// if (!(i%4))
|
|
// printk("0x");
|
|
// printk("%02x", *(p_skb_int+i));
|
|
// }
|
|
// printk(" <<\n");
|
|
|
|
for (i = 0; i < payload_length; i++) {
|
|
if (priv->pmib->miscEntry.lb_mlmp == 1) {
|
|
matching = 0;
|
|
if (memcmp((p_skb_int+i), &matching, 1)) {
|
|
mismatch++;
|
|
break;
|
|
}
|
|
}
|
|
else if (priv->pmib->miscEntry.lb_mlmp == 2) {
|
|
matching = 0xff;
|
|
if (memcmp((p_skb_int+i), &matching, 1)) {
|
|
mismatch++;
|
|
break;
|
|
}
|
|
}
|
|
else if ((priv->pmib->miscEntry.lb_mlmp == 3) || (priv->pmib->miscEntry.lb_mlmp == 4)) {
|
|
matching = i%0x100;
|
|
if (memcmp((p_skb_int+i), &matching, 1)) {
|
|
mismatch++;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
printk("LB Qos RX, wrong mlmp setting!\n");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (mismatch) {
|
|
printk("LB Qos RX, rx pattern mismatch!!\n");
|
|
priv->pmib->miscEntry.drvmac_lb = 0; // stop the test
|
|
}
|
|
}
|
|
#endif
|
|
|
|
out:
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_RTL8186_KB
|
|
int rtl8192cd_guestmac_valid(struct rtl8192cd_priv *priv, char *macaddr)
|
|
{
|
|
int i=0;
|
|
|
|
for (i=0; i<MAX_GUEST_NUM; i++)
|
|
{
|
|
if (priv->guestMac[i].valid && !memcmp(priv->guestMac[i].macaddr, macaddr, 6))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(CONFIG_RTL_IGMP_SNOOPING)
|
|
/*added by qinjunjie,to avoid igmpv1/v2 report suppress*/
|
|
int rtl8192cd_isIgmpV1V2Report(unsigned char *macFrame)
|
|
{
|
|
unsigned char *ptr;
|
|
#ifdef __ECOS
|
|
struct ip *iph=NULL;
|
|
#else
|
|
struct iphdr *iph=NULL;
|
|
#endif
|
|
unsigned int payloadLen;
|
|
|
|
if((macFrame[0]!=0x01) || (macFrame[1]!=0x00) || (macFrame[2]!=0x5e))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ptr=macFrame+12;
|
|
if(*(int16 *)(ptr)==(int16)htons(0x8100))
|
|
{
|
|
ptr=ptr+4;
|
|
}
|
|
|
|
/*it's not ipv4 packet*/
|
|
if(*(int16 *)(ptr)!=(int16)htons(0x0800))
|
|
{
|
|
return FALSE;
|
|
}
|
|
ptr=(ptr+2);
|
|
#ifdef __ECOS
|
|
iph=(struct ip *)ptr;
|
|
if(iph->ip_p!=0x02)
|
|
#else
|
|
iph=(struct iphdr *)ptr;
|
|
if(iph->protocol!=0x02)
|
|
#endif
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef __ECOS
|
|
payloadLen=(iph->ip_len-((iph->ip_hl&0x0f)<<2));
|
|
#else
|
|
payloadLen=(iph->tot_len-((iph->ihl&0x0f)<<2));
|
|
#endif
|
|
if(payloadLen>8)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef __ECOS
|
|
ptr=ptr+(((unsigned int)iph->ip_hl)<<2);
|
|
#else
|
|
ptr=ptr+(((unsigned int)iph->ihl)<<2);
|
|
#endif
|
|
if((*ptr==0x11) ||(*ptr==0x16))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
#if defined (CONFIG_RTL_MLD_SNOOPING)
|
|
#define IPV6_ROUTER_ALTER_OPTION 0x05020000
|
|
#define HOP_BY_HOP_OPTIONS_HEADER 0
|
|
#define ROUTING_HEADER 43
|
|
#define FRAGMENT_HEADER 44
|
|
#define DESTINATION_OPTION_HEADER 60
|
|
|
|
#define ICMP_PROTOCOL 58
|
|
|
|
#define MLD_QUERY 130
|
|
#define MLDV1_REPORT 131
|
|
#define MLDV1_DONE 132
|
|
#define MLDV2_REPORT 143
|
|
|
|
int rtl8192cd_isMldV1Report(unsigned char *macFrame)
|
|
{
|
|
unsigned char *ptr;
|
|
#ifdef __ECOS
|
|
struct ip6_hdr* ipv6h;
|
|
#else
|
|
struct ipv6hdr* ipv6h;
|
|
#endif
|
|
unsigned char *startPtr=NULL;
|
|
unsigned char *lastPtr=NULL;
|
|
unsigned char nextHeader=0;
|
|
unsigned short extensionHdrLen=0;
|
|
|
|
unsigned char optionDataLen=0;
|
|
unsigned char optionType=0;
|
|
unsigned int ipv6RAO=0;
|
|
|
|
if((macFrame[0]!=0x33) || (macFrame[1]!=0x33) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if(macFrame[2]==0xff)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ptr=macFrame+12;
|
|
if(*(int16 *)(ptr)==(int16)htons(0x8100))
|
|
{
|
|
ptr=ptr+4;
|
|
}
|
|
|
|
/*it's not ipv6 packet*/
|
|
if(*(int16 *)(ptr)!=(int16)htons(0x86dd))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ptr=(ptr+2);
|
|
|
|
#ifdef __ECOS
|
|
ipv6h= (struct ip6_hdr *) ptr;
|
|
if(ipv6h->ip6_vfc!=IPV6_VERSION)
|
|
#else
|
|
ipv6h= (struct ipv6hdr *) ptr;
|
|
if(ipv6h->version!=6)
|
|
#endif
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
startPtr= (unsigned char *)ptr;
|
|
#ifdef __ECOS
|
|
lastPtr=startPtr+sizeof(struct ip6_hdr)+(ipv6h->ip6_plen);
|
|
nextHeader= ipv6h ->ip6_nxt;
|
|
ptr=startPtr+sizeof(struct ip6_hdr);
|
|
#else
|
|
lastPtr=startPtr+sizeof(struct ipv6hdr)+(ipv6h->payload_len);
|
|
nextHeader= ipv6h ->nexthdr;
|
|
ptr=startPtr+sizeof(struct ipv6hdr);
|
|
#endif
|
|
|
|
while(ptr<lastPtr)
|
|
{
|
|
switch(nextHeader)
|
|
{
|
|
case HOP_BY_HOP_OPTIONS_HEADER:
|
|
/*parse hop-by-hop option*/
|
|
nextHeader=ptr[0];
|
|
extensionHdrLen=((uint16)(ptr[1])+1)*8;
|
|
ptr=ptr+2;
|
|
|
|
#ifdef __ECOS
|
|
while(ptr<(startPtr+extensionHdrLen+sizeof(struct ip6_hdr)))
|
|
#else
|
|
while(ptr<(startPtr+extensionHdrLen+sizeof(struct ipv6hdr)))
|
|
#endif
|
|
{
|
|
optionType=ptr[0];
|
|
/*pad1 option*/
|
|
if(optionType==0)
|
|
{
|
|
ptr=ptr+1;
|
|
continue;
|
|
}
|
|
|
|
/*padN option*/
|
|
if(optionType==1)
|
|
{
|
|
optionDataLen=ptr[1];
|
|
ptr=ptr+optionDataLen+2;
|
|
continue;
|
|
}
|
|
|
|
/*router altert option*/
|
|
if(ntohl(*(uint32 *)(ptr))==IPV6_ROUTER_ALTER_OPTION)
|
|
{
|
|
ipv6RAO=IPV6_ROUTER_ALTER_OPTION;
|
|
ptr=ptr+4;
|
|
continue;
|
|
}
|
|
|
|
/*other TLV option*/
|
|
if((optionType!=0) && (optionType!=1))
|
|
{
|
|
optionDataLen=ptr[1];
|
|
ptr=ptr+optionDataLen+2;
|
|
continue;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ROUTING_HEADER:
|
|
nextHeader=ptr[0];
|
|
extensionHdrLen=((uint16)(ptr[1])+1)*8;
|
|
ptr=ptr+extensionHdrLen;
|
|
break;
|
|
|
|
case FRAGMENT_HEADER:
|
|
nextHeader=ptr[0];
|
|
ptr=ptr+8;
|
|
break;
|
|
|
|
case DESTINATION_OPTION_HEADER:
|
|
nextHeader=ptr[0];
|
|
extensionHdrLen=((uint16)(ptr[1])+1)*8;
|
|
ptr=ptr+extensionHdrLen;
|
|
break;
|
|
|
|
case ICMP_PROTOCOL:
|
|
if(ptr[0]==MLDV1_REPORT)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef PREVENT_ARP_SPOOFING
|
|
static int check_arp_spoofing(struct rtl8192cd_priv *priv, struct sk_buff *pskb)
|
|
{
|
|
struct net_bridge_port *br_port;
|
|
struct arphdr *arp;
|
|
unsigned char *arp_ptr;
|
|
unsigned short protocol;
|
|
__be32 ipaddr = 0;
|
|
|
|
br_port = GET_BR_PORT(priv->dev);
|
|
if (!br_port)
|
|
return 0;
|
|
|
|
protocol = *((unsigned short *)(pskb->data + 2 * ETH_ALEN));
|
|
if (protocol == __constant_htons(ETH_P_ARP)) {
|
|
arp = (struct arphdr *)(pskb->data + ETH_HLEN);
|
|
if (arp->ar_pro == __constant_htons(ETH_P_IP)) {
|
|
arp_ptr = (unsigned char *)(arp + 1);
|
|
arp_ptr += arp->ar_hln;
|
|
|
|
ipaddr = inet_select_addr(br_port->br->dev, 0, RT_SCOPE_LINK);
|
|
if (!memcmp(&ipaddr, arp_ptr, arp->ar_pln))
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int process_datafrme(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *pframe, da[MACADDRLEN];
|
|
unsigned int privacy;
|
|
unsigned int res;
|
|
struct stat_info *pstat = NULL, *dst_pstat = NULL;
|
|
struct sk_buff *pskb = NULL, *pnewskb = NULL;
|
|
unsigned char qosControl[2];
|
|
int dontBcast2otherSta = 0, do_rc = 0;
|
|
struct net_bridge_port *br_port=NULL;
|
|
#ifdef RX_SHORTCUT
|
|
int i;
|
|
#endif
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
|
|
pskb = get_pskb(pfrinfo);
|
|
//skb_put(pskb, pfrinfo->pktlen); // pskb->tail will be wrong
|
|
pskb->tail = pskb->data + pfrinfo->pktlen;
|
|
pskb->len = pfrinfo->pktlen;
|
|
pskb->dev = priv->dev;
|
|
|
|
if ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11N) &&
|
|
priv->pmib->reorderCtrlEntry.ReorderCtrlEnable) {
|
|
if (!IS_MCAST(GetAddr1Ptr(pframe)))
|
|
do_rc = 1;
|
|
}
|
|
|
|
if (OPMODE & WIFI_AP_STATE)
|
|
{
|
|
memcpy(da, pfrinfo->da, MACADDRLEN);
|
|
|
|
#ifdef CONFIG_RTK_MESH
|
|
if (pfrinfo->is_11s)
|
|
{
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
rx_sum_up(NULL, pstat, pfrinfo->pktlen, 0);
|
|
priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
|
|
update_sta_rssi(priv, pstat, pfrinfo);
|
|
return process_11s_datafrme(priv,pfrinfo, pstat);
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds == 3) {
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
pskb->dev = getWdsDevByAddr(priv, GetAddr2Ptr(pframe));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef A4_STA
|
|
if (pfrinfo->to_fr_ds == 3 && priv->pshare->rf_ft_var.a4_enable)
|
|
pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef HW_FILL_MACID
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
pstat = get_HW_mapping_sta(priv,pfrinfo->macid);
|
|
// printk("%s %d HW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
#endif
|
|
|
|
//if(!pstat)
|
|
{
|
|
pstat = get_stainfo(priv, pfrinfo->sa);
|
|
// printk("%s %d SW MACID = %x pstat = %x \n",__FUNCTION__,__LINE__,pfrinfo->macid,pstat);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
#if defined(CONFIG_PCI_HCI)
|
|
if (wapiHandleRecvPacket(pfrinfo, pstat)==SUCCESS)
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
if (pstat->wapiInfo && (wapiDisable != pstat->wapiInfo->wapiType))
|
|
{
|
|
int waiOffset;
|
|
if ((SecIsWAIPacket(pskb, &waiOffset) == SUCCESS) ||
|
|
(pstat->wapiInfo->wapiState != ST_WAPI_AE_MSKA_ESTABLISH))
|
|
{
|
|
notify_recv_wai_frame(priv, pfrinfo);
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
#endif
|
|
#endif // CONFIG_RTL_WAPI_SUPPORT
|
|
|
|
// log rx statistics...
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds == 3) {
|
|
privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
}
|
|
rx_sum_up(NULL, pstat, pfrinfo->pktlen, 0);
|
|
priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
|
|
update_sta_rssi(priv, pstat, pfrinfo);
|
|
|
|
#ifdef DETECT_STA_EXISTANCE
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
if (pstat->leave!= 0)
|
|
RTL8188E_MACID_NOLINK(priv, 0, REMAP_AID(pstat));
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
{
|
|
if (pstat->leave!= 0)
|
|
{
|
|
#if defined(CONFIG_PCI_HCI)
|
|
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
|
|
pstat->bDrop = 0;
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_update_sta_msr(priv, pstat, INCREASE);
|
|
#endif
|
|
}
|
|
pstat->rx_last_good_time = priv->up_time;
|
|
}
|
|
#endif //#ifdef CONFIG_WLAN_HAL
|
|
|
|
pstat->leave = 0;
|
|
#endif
|
|
|
|
#ifdef SUPPORT_SNMP_MIB
|
|
if (IS_MCAST(da))
|
|
SNMP_MIB_INC(dot11MulticastReceivedFrameCount, 1);
|
|
#endif
|
|
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if(
|
|
#ifdef CLIENT_MODE
|
|
(OPMODE & WIFI_AP_STATE) &&
|
|
#endif
|
|
(QOS_ENABLE) && (APSD_ENABLE) && (pstat->QosEnabled) && (pstat->apsd_bitmap & 0x0f) &&
|
|
((pstat->state & (WIFI_ASOC_STATE|WIFI_SLEEP_STATE)) == (WIFI_ASOC_STATE|WIFI_SLEEP_STATE)) &&
|
|
(GetFrameSubType(get_pframe(pfrinfo)) == (WIFI_QOS_DATA))) {
|
|
process_APSD_dz_queue(priv, pstat, pfrinfo->tid);
|
|
}
|
|
#endif
|
|
|
|
// Process A-MSDU
|
|
if (is_qos_data(pframe)) {
|
|
memcpy(qosControl, GetQosControl(pframe), 2);
|
|
if (qosControl[0] & BIT(7)) // A-MSDU present
|
|
{
|
|
|
|
if (!pstat->is_realtek_sta && (pstat->IOTPeer!=HT_IOT_PEER_RALINK) && (pstat->IOTPeer!=HT_IOT_PEER_MARVELL)) {
|
|
pstat->IOTPeer=HT_IOT_PEER_MARVELL;
|
|
if (priv->pshare->is_40m_bw){
|
|
setSTABitMap(&priv->pshare->marvellMapBit, pstat->aid);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL_8881A)
|
|
if((GET_CHIP_VER(priv)== VERSION_8812E) || (GET_CHIP_VER(priv)== VERSION_8881A)) {
|
|
//Do Nothing
|
|
}
|
|
else
|
|
#endif
|
|
if (priv->pshare->is_40m_bw && (pstat->IOTPeer==HT_IOT_PEER_MARVELL) && (priv->pshare->Reg_RRSR_2 == 0) && (priv->pshare->Reg_81b == 0)){
|
|
#if defined(CONFIG_PCI_HCI)
|
|
priv->pshare->Reg_RRSR_2 = RTL_R8(RRSR+2);
|
|
priv->pshare->Reg_81b = RTL_R8(0x81b);
|
|
RTL_W8(RRSR+2, priv->pshare->Reg_RRSR_2 | 0x60);
|
|
RTL_W8(0x81b, priv->pshare->Reg_81b | 0x0E);
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
notify_40M_RRSR_SC_change(priv);
|
|
#endif
|
|
}
|
|
|
|
process_amsdu(priv, pstat, pfrinfo);
|
|
return SUCCESS;
|
|
}
|
|
#ifdef RX_BUFFER_GATHER
|
|
else if (!list_empty(&priv->pshare->gather_list))
|
|
flush_rx_list(priv);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PREVENT_BROADCAST_STORM
|
|
// if (get_free_memory() < FREE_MEM_LOWER_BOUND) {
|
|
if (da[0] == 0xff) {
|
|
pstat->rx_pkts_bc++;
|
|
#if 0
|
|
if (pstat->rx_pkts_bc > BROADCAST_STORM_THRESHOLD) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Broadcast storm happened!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// AP always receive unicast frame only
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds!=3 && IS_MCAST(da))
|
|
#else
|
|
if (IS_MCAST(da))
|
|
#endif
|
|
{
|
|
#ifdef DRVMAC_LB
|
|
if (priv->pmib->miscEntry.drvmac_lb) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: drop br/ml packet in loop-back mode!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
|
|
#if 0 //def PREVENT_BROADCAST_STORM
|
|
// if (get_free_memory() < FREE_MEM_LOWER_BOUND) {
|
|
if (da[0] == 0xff) {
|
|
pstat->rx_pkts_bc++;
|
|
if (pstat->rx_pkts_bc > BROADCAST_STORM_THRESHOLD) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Broadcast storm happened!\n");
|
|
return FAIL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// This is a legal frame, convert it to skb
|
|
res = skb_p80211_to_ether(priv->dev, privacy, pfrinfo);
|
|
if (res == FAIL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: skb_p80211_to_ether fail!\n");
|
|
return FAIL;
|
|
}
|
|
|
|
#ifdef PREVENT_ARP_SPOOFING
|
|
if (check_arp_spoofing(priv, pskb)) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Detected ARP spoofing!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef SUPPORT_TX_MCAST2UNI
|
|
if(IP_MCAST_MAC(pskb->data) && IS_IGMP_PROTO(pskb->data))
|
|
{
|
|
dontBcast2otherSta=1;
|
|
}
|
|
#endif
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(CONFIG_RTL_IGMP_SNOOPING)
|
|
/*added by qinjunjie,to avoid igmpv1/v2 report suppress*/
|
|
if(rtl8192cd_isIgmpV1V2Report(pskb->data))
|
|
{
|
|
//printk("%s:%d,receive igmpv1/v2 report\n",__FUNCTION__,__LINE__);
|
|
goto mcast_netif_rx;
|
|
}
|
|
#if defined (CONFIG_RTL_MLD_SNOOPING)
|
|
if(rtl8192cd_isMldV1Report(pskb->data))
|
|
{
|
|
goto mcast_netif_rx;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
#ifndef CONFIG_RTL8196C_KLD
|
|
br_port = GET_BR_PORT(priv->dev);
|
|
|
|
// if we are STP aware, don't broadcast received BPDU
|
|
if (!(br_port &&
|
|
br_port->br->stp_enabled &&
|
|
!memcmp(pskb->data, "\x01\x80\xc2\x00\x00\x00", 6)))
|
|
#endif
|
|
#endif
|
|
{
|
|
if (!priv->pmib->dot11OperationEntry.block_relay)
|
|
{
|
|
#if defined(_SINUX_) && defined(CONFIG_RTL865X_ETH_PRIV_SKB)
|
|
extern struct sk_buff *priv_skb_copy(struct sk_buff *skb);
|
|
pnewskb = priv_skb_copy(pskb);
|
|
#else
|
|
pnewskb = skb_copy(pskb, GFP_ATOMIC);
|
|
#endif
|
|
if (pnewskb) {
|
|
#ifdef GBWC
|
|
if (GBWC_forward_check(priv, pnewskb, pstat)) {
|
|
// packet is queued, nothing to do
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef TX_SCATTER
|
|
pnewskb->list_num = 0;
|
|
#endif
|
|
if(dontBcast2otherSta){
|
|
dev_kfree_skb_any(pnewskb);
|
|
}else{
|
|
#ifdef PREVENT_BROADCAST_STORM
|
|
if (da[0] == 0xff) {
|
|
if (pstat->rx_pkts_bc > BROADCAST_STORM_THRESHOLD) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Broadcast storm happened!\n");
|
|
dev_kfree_skb_any(pnewskb);
|
|
}
|
|
else {
|
|
if (rtl8192cd_start_xmit(pnewskb, priv->dev))
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_TX_);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (rtl8192cd_start_xmit(pnewskb, priv->dev))
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_TX_);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if (defined(__LINUX_2_6__) || defined(__ECOS)) && defined(CONFIG_RTL_IGMP_SNOOPING)
|
|
mcast_netif_rx:
|
|
#endif
|
|
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = 0;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo))
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
else
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
else
|
|
{
|
|
// unicast.. the status of sa has been checked in defrag_frame.
|
|
// however, we should check if the da is in the WDS to see if we should
|
|
res = skb_p80211_to_ether(pskb->dev, privacy, pfrinfo);
|
|
if (res == FAIL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: skb_p80211_to_ether fail!\n");
|
|
return FAIL;
|
|
}
|
|
|
|
#ifdef PREVENT_ARP_SPOOFING
|
|
if (check_arp_spoofing(priv, pskb)) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Detected ARP spoofing!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
|
|
dst_pstat = get_stainfo(priv, da);
|
|
|
|
#if defined(CONFIG_RTK_MESH)
|
|
if(isMeshPoint(dst_pstat))
|
|
dst_pstat = NULL;
|
|
#endif
|
|
|
|
#ifdef A4_STA
|
|
if (priv->pshare->rf_ft_var.a4_enable && (dst_pstat == NULL))
|
|
dst_pstat = a4_sta_lookup(priv, da);
|
|
#endif
|
|
|
|
#ifdef WDS
|
|
if ((pfrinfo->to_fr_ds==3) ||
|
|
(dst_pstat == NULL) || !(dst_pstat->state & WIFI_ASOC_STATE))
|
|
#else
|
|
if ((dst_pstat == NULL) || (!(dst_pstat->state & WIFI_ASOC_STATE)))
|
|
#endif
|
|
{
|
|
#ifndef __ECOS
|
|
if (priv->pmib->dot11OperationEntry.guest_access
|
|
#ifdef CONFIG_RTL8186_KB
|
|
||(pstat && pstat->ieee8021x_ctrlport == DOT11_PortStatus_Guest)
|
|
#endif
|
|
) {
|
|
br_port = GET_BR_PORT(priv->dev);
|
|
|
|
if (
|
|
(*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) != __constant_htons(0x888e)) &&
|
|
(*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) != __constant_htons(0x86dd))
|
|
#ifndef CONFIG_RTL8196C_KLD
|
|
&& br_port
|
|
#ifdef __LINUX_2_6__
|
|
#if defined(CONFIG_RTL_EAP_RELAY) || defined(CONFIG_RTK_INBAND_HOST_HACK)
|
|
&& memcmp(da, inband_Hostmac, MACADDRLEN)
|
|
#else
|
|
&& memcmp(da, br_port->br->dev->dev_addr, MACADDRLEN)
|
|
#endif
|
|
#else
|
|
&& memcmp(da, priv->dev->br_port->br->dev.dev_addr, MACADDRLEN)
|
|
#endif
|
|
#endif
|
|
) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: guest access fail!\n");
|
|
return FAIL;
|
|
}
|
|
#if !defined(NOT_RTK_BSP) && !defined(CONFIG_OPENWRT_SDK)
|
|
pskb->__unused = 0xe5;
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL8186_KB
|
|
if (priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == 0)
|
|
{
|
|
/* hotel style guest access */
|
|
if (!rtl8192cd_guestmac_valid(priv, SKB_MAC_HEADER(pskb)+MACADDRLEN))
|
|
{
|
|
#if !defined(NOT_RTK_BSP) && !defined(CONFIG_OPENWRT_SDK)
|
|
pskb->__unused = 0xd3;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* wpa/wp2 guest access */
|
|
/* just let __unused flag be 0xe5 */
|
|
}
|
|
#endif
|
|
|
|
//printk("guest packet, addr: %0x2:%02x:%02x:%02x:%02x:%02x\n",da[0],da[1],da[2],da[3],da[4],da[5]);
|
|
}
|
|
#if !defined(NOT_RTK_BSP) && !defined(CONFIG_OPENWRT_SDK)
|
|
else
|
|
pskb->__unused = 0;
|
|
#endif
|
|
|
|
#ifdef __LINUX_2_6__
|
|
if(pskb->dev)
|
|
pskb->protocol = eth_type_trans(pskb,pskb->dev);
|
|
else
|
|
#endif
|
|
pskb->protocol = eth_type_trans(pskb, priv->dev);
|
|
|
|
#if defined(HS2_SUPPORT)
|
|
/* Hotspot 2.0 Release 1 */
|
|
if(pskb->protocol == __constant_htons(ETHER_TDLS))
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
HS2_DEBUG_INFO("RX DROP: TDLS!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef EAPOLSTART_BY_QUEUE
|
|
if (*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) == __constant_htons(0x888e))
|
|
{
|
|
unsigned char szEAPOL[] = {0x01, 0x01, 0x00, 0x00};
|
|
DOT11_EAPOL_START Eapol_Start;
|
|
|
|
if (!memcmp(pskb->data, szEAPOL, sizeof(szEAPOL)))
|
|
{
|
|
Eapol_Start.EventId = DOT11_EVENT_EAPOLSTART;
|
|
Eapol_Start.IsMoreEvent = FALSE;
|
|
memcpy(&Eapol_Start.MACAddr, SKB_MAC_HEADER(pskb) + MACADDRLEN, WLAN_ETHHDR_LEN);
|
|
DOT11_EnQueue((unsigned long)priv, priv->pevent_queue, (unsigned char*)&Eapol_Start, sizeof(DOT11_EAPOL_START));
|
|
event_indicate(priv, SKB_MAC_HEADER(pskb) + MACADDRLEN, 4);
|
|
return FAIL; // let dsr free this skb
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
#ifdef CONFIG_RTL_819X_ECOS
|
|
if (priv->pmib->dot11OperationEntry.guest_access)
|
|
{
|
|
if((*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) != __constant_htons(0x888e)) &&
|
|
(*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) != __constant_htons(0x86dd)) &&
|
|
memcmp(da, freebsd_Hostmac, MACADDRLEN)
|
|
)
|
|
{
|
|
//wlan sta can't access LAN when guest access is enabled
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: guest access fail!\n");
|
|
return FAIL;
|
|
}
|
|
else
|
|
pskb->__unused = 0xe5;
|
|
}
|
|
#endif
|
|
#endif /* __ECOS */
|
|
|
|
#if defined(WIFI_WPAS_CLI) || (defined(RTK_NL80211) && defined(NON_NL80211_AP))
|
|
if (!(OPMODE & WIFI_STATION_STATE))
|
|
#endif
|
|
{
|
|
#if (defined(EAP_BY_QUEUE) || defined(INCLUDE_WPA_PSK)) && (!defined(WIFI_HAPD) || defined(HAPD_DRV_PSK_WPS))
|
|
#ifdef WDS
|
|
if ((pfrinfo->to_fr_ds != 3) && (*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) == __constant_htons(0x888e)))
|
|
#else
|
|
if (*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) == __constant_htons(0x888e))
|
|
#endif
|
|
{
|
|
if (IEEE8021X_FUN
|
|
#ifdef INCLUDE_WPA_PSK
|
|
|| (priv->pmib->dot1180211AuthEntry.dot11EnablePSK &&
|
|
((priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _TKIP_PRIVACY_) ||
|
|
(priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == _CCMP_PRIVACY_)))
|
|
#endif
|
|
#ifdef WIFI_SIMPLE_CONFIG
|
|
|| priv->pmib->wscEntry.wsc_enable
|
|
#endif
|
|
) {
|
|
unsigned short pkt_len;
|
|
|
|
#ifdef __ECOS
|
|
pkt_len = pskb->len;
|
|
#else
|
|
pkt_len = WLAN_ETHHDR_LEN + pskb->len;
|
|
#endif
|
|
priv->Eap_packet->EventId = DOT11_EVENT_EAP_PACKET;
|
|
priv->Eap_packet->IsMoreEvent = FALSE;
|
|
memcpy(&(priv->Eap_packet->packet_len), &pkt_len, sizeof(unsigned short));
|
|
#ifdef __ECOS
|
|
memcpy(&priv->Eap_packet->packet, pskb->data, pskb->len);
|
|
#else
|
|
memcpy(&(priv->Eap_packet->packet[0]), SKB_MAC_HEADER(pskb), WLAN_ETHHDR_LEN);
|
|
memcpy(&(priv->Eap_packet->packet[WLAN_ETHHDR_LEN]), pskb->data, pskb->len);
|
|
#endif
|
|
#ifdef EAP_BY_QUEUE
|
|
|
|
#ifdef INCLUDE_WPS
|
|
|
|
wps_NonQueue_indicate_evt(priv ,
|
|
(char *)priv->Eap_packet, sizeof(DOT11_EAP_PACKET));
|
|
#else
|
|
DOT11_EnQueue((unsigned long)priv, priv->pevent_queue,
|
|
(unsigned char*)priv->Eap_packet,sizeof(DOT11_EAP_PACKET));
|
|
|
|
event_indicate(priv, NULL, -1);
|
|
#endif
|
|
|
|
#endif
|
|
#ifdef INCLUDE_WPA_PSK
|
|
#ifdef __ECOS
|
|
psk_indicate_evt(priv, DOT11_EVENT_EAP_PACKET, (unsigned char*)&(priv->Eap_packet->packet[6]),
|
|
(unsigned char*)priv->Eap_packet->packet, pskb->len);
|
|
#else
|
|
psk_indicate_evt(priv, DOT11_EVENT_EAP_PACKET, (unsigned char*)&(priv->Eap_packet->packet[6]),
|
|
(unsigned char*)priv->Eap_packet->packet, WLAN_ETHHDR_LEN+pskb->len);
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(WIFI_HAPD) && (!defined(RTK_NL80211) || defined(NON_NL80211_AP))
|
|
return FAIL; // let dsr free this skb
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
} // WIFI_WPAS_CLI
|
|
#ifndef __ECOS
|
|
skb_push(pskb, WLAN_ETHHDR_LEN); // push back due to be pulled by eth_type_trans()
|
|
#endif
|
|
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = 0;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo))
|
|
rtl_netif_rx(priv, pfrinfo->pskb, pstat);
|
|
}
|
|
else
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
else
|
|
{
|
|
if (priv->pmib->dot11OperationEntry.block_relay == 1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Relay unicast packet is blocked!\n");
|
|
#ifdef RX_SHORTCUT
|
|
for (i=0; i<RX_SC_ENTRY_NUM; i++) { // shortcut data saved, clear it
|
|
dst_pstat->rx_sc_ent[i].rx_payload_offset = 0;
|
|
}
|
|
#endif
|
|
return FAIL;
|
|
}
|
|
else if (priv->pmib->dot11OperationEntry.block_relay == 2) {
|
|
DEBUG_INFO("Relay unicast packet is blocked! Indicate to bridge.\n");
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
#ifdef HS2_SUPPORT
|
|
/* Hotspot 2.0 Release 1 */
|
|
else if (priv->pmib->dot11OperationEntry.block_relay == 3) {
|
|
HS2_DEBUG_INFO("block_relay=3\n");
|
|
|
|
if(IS_ICMPV4_PROTO(pfrinfo->pskb->data)) {
|
|
if(IS_ICMPV4_ECHO_TYPE(pfrinfo->pskb->data)) {
|
|
if(priv->pmib->hs2Entry.ICMPv4ECHO == 2) {
|
|
memcpy(&pfrinfo->pskb->data[0], priv->pmib->hs2Entry.redir_mac, 6);
|
|
HS2_DEBUG_INFO("redirect ICMPv4 Packet to connected portal\n");
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
else if(priv->pmib->hs2Entry.ICMPv4ECHO == 0) {
|
|
HS2_DEBUG_INFO("Drop ICMPv4 Packet\n");
|
|
return FAIL;
|
|
}
|
|
/*
|
|
else if(priv->pmib->hs2Entry.ICMPv4ECHO == 1) {
|
|
panic_printk("Allow ICMPv4 Echo Requests\n");
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = (unsigned int)dst_pstat; // backup pstat pointer
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, isMeshPoint(dst_pstat)? priv->mesh_dev: priv->dev))
|
|
#else
|
|
if (rtl8192cd_start_xmit(pfrinfo->pskb, priv->dev))
|
|
#endif
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_TX_);
|
|
}
|
|
*/
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#ifdef GBWC
|
|
if (GBWC_forward_check(priv, pfrinfo->pskb, pstat)) {
|
|
// packet is queued, nothing to do
|
|
}
|
|
else
|
|
#endif
|
|
if (do_rc) {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = (unsigned int)dst_pstat; // backup pstat pointer
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo)) {
|
|
#ifdef TX_SCATTER
|
|
pskb->list_num = 0;
|
|
#endif
|
|
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
//Joule 2009.03.10
|
|
#ifdef CONFIG_RTK_MESH
|
|
if (rtl8192cd_start_xmit(pskb, isMeshPoint(dst_pstat) ? priv->mesh_dev: priv->dev))
|
|
#else
|
|
if (rtl8192cd_start_xmit(pskb, priv->dev))
|
|
#endif
|
|
rtl_kfree_skb(priv, pskb, _SKB_TX_);
|
|
}
|
|
} else {
|
|
#ifdef TX_SCATTER
|
|
pskb->list_num = 0;
|
|
#endif
|
|
#ifdef CONFIG_RTK_MESH
|
|
// mantis bug 0000081 2008.07.16
|
|
if (rtl8192cd_start_xmit(pskb, isMeshPoint(dst_pstat) ? priv->mesh_dev: priv->dev))
|
|
#else
|
|
if (rtl8192cd_start_xmit(pskb, priv->dev))
|
|
#endif
|
|
rtl_kfree_skb(priv, pskb, _SKB_TX_);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
|
|
// I am station, and just report every frame I received to protocol statck
|
|
if (OPMODE & WIFI_STATION_STATE)
|
|
pstat = get_stainfo(priv, BSSID);
|
|
else // Ad-hoc
|
|
pstat = get_stainfo(priv, pfrinfo->sa);
|
|
|
|
if (IS_MCAST(pfrinfo->da)) {
|
|
// iv, icv and mic are not be used below. Don't care them!
|
|
privacy = get_mcast_encrypt_algthm(priv);
|
|
} else {
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
}
|
|
|
|
rx_sum_up(NULL, pstat, pfrinfo->pktlen, 0);
|
|
priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
|
|
update_sta_rssi(priv, pstat, pfrinfo);
|
|
priv->rxDataNumInPeriod++;
|
|
if (IS_MCAST(pfrinfo->da)) {
|
|
priv->rxMlcstDataNumInPeriod++;
|
|
#ifdef SUPPORT_SNMP_MIB
|
|
SNMP_MIB_INC(dot11MulticastReceivedFrameCount, 1);
|
|
#endif
|
|
} else if ((OPMODE & WIFI_STATION_STATE) && (priv->ps_state)) {
|
|
if ((GetFrameSubType(get_pframe(pfrinfo)) == WIFI_DATA)
|
|
#ifdef WIFI_WMM
|
|
|| (QOS_ENABLE && pstat->QosEnabled && (GetFrameSubType(get_pframe(pfrinfo)) == WIFI_QOS_DATA))
|
|
#endif
|
|
) {
|
|
if (GetMData(pframe)) {
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if (QOS_ENABLE && APSD_ENABLE && priv->uapsd_assoc) {
|
|
if (!((priv->pmib->dot11QosEntry.UAPSD_AC_BE && ((pfrinfo->tid == 0) || (pfrinfo->tid == 3))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_BK && ((pfrinfo->tid == 1) || (pfrinfo->tid == 2))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_VI && ((pfrinfo->tid == 4) || (pfrinfo->tid == 5))) ||
|
|
(priv->pmib->dot11QosEntry.UAPSD_AC_VO && ((pfrinfo->tid == 6) || (pfrinfo->tid == 7)))))
|
|
issue_PsPoll(priv);
|
|
} else
|
|
#endif
|
|
{
|
|
issue_PsPoll(priv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_RTL_WAPI_SUPPORT)
|
|
if (privacy==_WAPI_SMS4_) {
|
|
#if defined(CONFIG_PCI_HCI)
|
|
if (wapiHandleRecvPacket(pfrinfo, pstat)==SUCCESS)
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
#elif defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
if (pstat->wapiInfo && (wapiDisable != pstat->wapiInfo->wapiType))
|
|
{
|
|
int waiOffset;
|
|
if ((SecIsWAIPacket(pskb, &waiOffset) == SUCCESS) ||
|
|
(pstat->wapiInfo->wapiState != ST_WAPI_AE_MSKA_ESTABLISH))
|
|
{
|
|
notify_recv_wai_frame(priv, pfrinfo);
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
// Process A-MSDU
|
|
if (is_qos_data(pframe)) {
|
|
memcpy(qosControl, GetQosControl(pframe), 2);
|
|
if (qosControl[0] & BIT(7)) // A-MSDU present
|
|
{
|
|
process_amsdu(priv, pstat, pfrinfo);
|
|
return SUCCESS;
|
|
}
|
|
#ifdef RX_BUFFER_GATHER
|
|
else if (!list_empty(&priv->pshare->gather_list))
|
|
flush_rx_list(priv);
|
|
#endif
|
|
}
|
|
|
|
res = skb_p80211_to_ether(priv->dev, privacy, pfrinfo);
|
|
if (res == FAIL) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: skb_p80211_to_ether fail!\n");
|
|
return FAIL;
|
|
}
|
|
|
|
#ifdef RTK_BR_EXT
|
|
if(nat25_handle_frame(priv, pskb) == -1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n");
|
|
return FAIL;
|
|
}
|
|
#endif
|
|
|
|
#if 0 //rtk_nl80211 (for debug)
|
|
#ifdef __ECOS
|
|
if (*(unsigned short *)(pskb->data + MACADDRLEN*2) == __constant_htons(0x888e))
|
|
#else
|
|
if (*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) == __constant_htons(0x888e))
|
|
#endif
|
|
{
|
|
|
|
printk("[%s][%d]rx eap packets len = %d!!\n\n", __FUNCTION__, __LINE__, pskb->len);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
pskb->protocol = eth_type_trans(pskb, priv->dev);
|
|
#endif
|
|
|
|
#if defined(WIFI_WPAS_CLI) || (defined(RTK_NL80211) && defined(NON_NL80211_AP))
|
|
if (!(OPMODE & WIFI_STATION_STATE))
|
|
#endif
|
|
{
|
|
#if (defined(EAP_BY_QUEUE) || defined(INCLUDE_WPA_PSK)) && (!defined(WIFI_HAPD) || defined(HAPD_DRV_PSK_WPS))
|
|
if (*(unsigned short *)(SKB_MAC_HEADER(pskb) + MACADDRLEN*2) == __constant_htons(0x888e))
|
|
{
|
|
unsigned short pkt_len;
|
|
|
|
#ifdef __ECOS
|
|
pkt_len = pskb->len;
|
|
#else
|
|
pkt_len = WLAN_ETHHDR_LEN + pskb->len;
|
|
#endif
|
|
priv->Eap_packet->EventId = DOT11_EVENT_EAP_PACKET;
|
|
priv->Eap_packet->IsMoreEvent = FALSE;
|
|
memcpy(&(priv->Eap_packet->packet_len), &pkt_len, sizeof(unsigned short));
|
|
#ifdef __ECOS
|
|
memcpy(&priv->Eap_packet->packet, pskb->data, pskb->len);
|
|
#else
|
|
memcpy(&(priv->Eap_packet->packet[0]), SKB_MAC_HEADER(pskb), WLAN_ETHHDR_LEN);
|
|
memcpy(&(priv->Eap_packet->packet[WLAN_ETHHDR_LEN]), pskb->data, pskb->len);
|
|
#endif
|
|
#ifdef EAP_BY_QUEUE
|
|
|
|
#ifdef INCLUDE_WPS
|
|
|
|
wps_NonQueue_indicate_evt(priv ,
|
|
(char *)priv->Eap_packet, sizeof(DOT11_EAP_PACKET));
|
|
#else
|
|
DOT11_EnQueue((unsigned long)priv, priv->pevent_queue,
|
|
(unsigned char*)priv->Eap_packet, sizeof(DOT11_EAP_PACKET));
|
|
event_indicate(priv, NULL, -1);
|
|
#endif
|
|
#endif
|
|
#ifdef INCLUDE_WPA_PSK
|
|
#ifdef __ECOS
|
|
psk_indicate_evt(priv, DOT11_EVENT_EAP_PACKET, (unsigned char*)&(priv->Eap_packet->packet[6]),
|
|
(unsigned char*)priv->Eap_packet->packet, pskb->len);
|
|
#else
|
|
psk_indicate_evt(priv, DOT11_EVENT_EAP_PACKET, (unsigned char*)&(priv->Eap_packet->packet[6]),
|
|
(unsigned char*)priv->Eap_packet->packet, WLAN_ETHHDR_LEN+pskb->len);
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(WIFI_HAPD) && (!defined(RTK_NL80211) || defined(NON_NL80211_AP))
|
|
return FAIL; // let dsr free this skb
|
|
#endif
|
|
}
|
|
#endif
|
|
} // WIFI_WPAS_CLI
|
|
|
|
#ifdef __KERNEL__
|
|
skb_push(pskb, WLAN_ETHHDR_LEN); // push back due to be pulled by eth_type_trans()
|
|
#endif
|
|
if (do_rc) {
|
|
*(unsigned int *)&(pfrinfo->pskb->cb[4]) = 0;
|
|
if (reorder_ctrl_check(priv, pstat, pfrinfo))
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
else
|
|
rtl_netif_rx(priv, pskb, pstat);
|
|
}
|
|
#endif // CLIENT_MODE
|
|
else
|
|
{
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Non supported mode in process_datafrme\n");
|
|
return FAIL;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
Actually process RX management frame:
|
|
|
|
Process management frame stored in "inputPfrinfo" or gotten from "list",
|
|
only one of them is used to get Frame information.
|
|
|
|
Note that:
|
|
1. If frame information is gotten from "list", "inputPfrinfo" MUST be NULL.
|
|
2. If frame information is gotten from "inputPfrinfo", "list" MUST be NULL
|
|
*/
|
|
void rtl8192cd_rx_mgntframe(struct rtl8192cd_priv *priv, struct list_head *list,
|
|
struct rx_frinfo *inputPfrinfo)
|
|
{
|
|
struct rx_frinfo *pfrinfo = NULL;
|
|
|
|
// for SW LED
|
|
if (priv->pshare->LED_cnt_mgn_pkt)
|
|
priv->pshare->LED_rx_cnt++;
|
|
|
|
/* Get RX frame info */
|
|
if (list) {
|
|
/* Indicate the frame information can be gotten from "list" */
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
}
|
|
else {
|
|
/* Indicate the frame information is stored in "inputPfrinfo" */
|
|
pfrinfo = inputPfrinfo;
|
|
}
|
|
|
|
if (pfrinfo == NULL)
|
|
goto out;
|
|
|
|
mgt_handler(priv, pfrinfo);
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
Actually process RX control frame:
|
|
|
|
Process control frame stored in "inputPfrinfo" or gotten from "list",
|
|
only one of them is used to get Frame information.
|
|
|
|
Note that:
|
|
1. If frame information is gotten from "list", "inputPfrinfo" MUST be NULL.
|
|
2. If frame information is gotten from "inputPfrinfo", "list" MUST be NULL
|
|
*/
|
|
static void rtl8192cd_rx_ctrlframe(struct rtl8192cd_priv *priv, struct list_head *list,
|
|
struct rx_frinfo *inputPfrinfo)
|
|
{
|
|
struct rx_frinfo *pfrinfo = NULL;
|
|
|
|
/* Get RX frame info */
|
|
if (list) {
|
|
/* Indicate the frame information can be gotten from "list" */
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
}
|
|
else {
|
|
/* Indicate the frame information is stored in "inputPfrinfo " */
|
|
pfrinfo = inputPfrinfo;
|
|
}
|
|
|
|
if (pfrinfo == NULL)
|
|
goto out;
|
|
|
|
ctrl_handler(priv, pfrinfo);
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
Actually process RX data frame:
|
|
|
|
Process data frame stored in "inputPfrinfo" or gotten from "list",
|
|
only one of them is used to get Frame information.
|
|
|
|
Note that:
|
|
1. If frame information is gotten from "list", "inputPfrinfo" MUST be NULL.
|
|
2. If frame information is gotten from "inputPfrinfo", "list" MUST be NULL
|
|
*/
|
|
__MIPS16
|
|
__IRAM_IN_865X
|
|
void rtl8192cd_rx_dataframe(struct rtl8192cd_priv *priv, struct list_head *list,
|
|
struct rx_frinfo *inputPfrinfo)
|
|
{
|
|
struct rx_frinfo *pfrinfo = NULL;
|
|
unsigned char *pframe;
|
|
|
|
/* ============== Do releted process for Packet RX ============== */
|
|
// for SW LED
|
|
priv->pshare->LED_rx_cnt++;
|
|
|
|
// for Rx dynamic tasklet
|
|
priv->pshare->rxInt_data_delta++;
|
|
|
|
/* Get RX frame info */
|
|
if (list) {
|
|
/* Indicate the frame information can be gotten from "list" */
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
}
|
|
else {
|
|
/* Indicate the frame information is stored in "inputPfrinfo " */
|
|
pfrinfo = inputPfrinfo;
|
|
}
|
|
|
|
if (pfrinfo == NULL) {
|
|
printk("pfrinfo == NULL\n");
|
|
goto out;
|
|
}
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
|
|
#ifdef WIFI_WMM
|
|
if (is_qos_data(pframe)) {
|
|
if ((OPMODE & WIFI_AP_STATE) && (QOS_ENABLE)) {
|
|
if ((pfrinfo->tid == 7) || (pfrinfo->tid == 6)) {
|
|
priv->pshare->phw->VO_pkt_count++;
|
|
} else if ((pfrinfo->tid == 5) || (pfrinfo->tid == 4)) {
|
|
priv->pshare->phw->VI_pkt_count++;
|
|
if (priv->pshare->rf_ft_var.wifi_beq_iot)
|
|
priv->pshare->phw->VI_rx_pkt_count++;
|
|
} else if ((pfrinfo->tid == 2) || (pfrinfo->tid == 1)) {
|
|
priv->pshare->phw->BK_pkt_count++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// check power save state
|
|
#ifndef DRVMAC_LB
|
|
if (OPMODE & WIFI_AP_STATE) {
|
|
if (get_stainfo(priv, GetAddr2Ptr(pframe)) != NULL) {
|
|
if (IS_BSSID(priv, GetAddr1Ptr(pframe))) {
|
|
struct stat_info *pstat = get_stainfo(priv, pfrinfo->sa);
|
|
#ifdef HW_DETEC_POWER_STATE
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
// 8813 power state control only by HW, not by SW.
|
|
// Only if HW detect macid not ready, SW patch this packet
|
|
if(pfrinfo->macid == HW_MACID_SEARCH_NOT_READY)
|
|
{
|
|
printk("%s %d HW_MACID_SEARCH_NOT_READY",__FUNCTION__,__LINE__);
|
|
if(priv->pshare->HWPwrStateUpdate[pstat->aid]==false)
|
|
{
|
|
printk("%s %d HW not update By SW Aid = %x \n",__FUNCTION__,__LINE__,pstat->aid);
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
else if(pfrinfo->macid > HW_MACID_SEARCH_SUPPORT_NUM)
|
|
{
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
} else
|
|
#endif // #ifdef HW_DETEC_POWER_STATE
|
|
{
|
|
if (pstat && (pstat->state & WIFI_ASOC_STATE) &&
|
|
(GetPwrMgt(pframe) != ((pstat->state & WIFI_SLEEP_STATE ? 1 : 0))))
|
|
pwr_state(priv, pfrinfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* ============== Start to process RX dataframe ============== */
|
|
#if defined(CONFIG_RTK_VOIP_QOS)|| defined(CONFIG_RTK_VLAN_WAN_TAG_SUPPORT)
|
|
#ifdef MBSSID
|
|
if(IS_VAP_INTERFACE(priv))
|
|
pfrinfo->pskb->srcPhyPort += (priv->vap_id+1);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(DRVMAC_LB) && defined(WIFI_WMM)
|
|
if(priv->pmib->miscEntry.drvmac_lb /*&& priv->pmib->miscEntry.lb_tps*/) {
|
|
if ((QOS_ENABLE) && (GetFrameSubType(get_pframe(pfrinfo)) == (BIT(7)|WIFI_DATA_NULL)))
|
|
process_lb_qos_null(priv, pfrinfo);
|
|
else if ((QOS_ENABLE) && (GetFrameSubType(get_pframe(pfrinfo)) == (WIFI_QOS_DATA)))
|
|
process_lb_qos(priv, pfrinfo);
|
|
else {
|
|
#if 0
|
|
if (!QOS_ENABLE)
|
|
printk("wifi qos not enabled, ");
|
|
printk("cannot match loopback pkt pattern!!!\n");
|
|
if (pfrinfo->pskb && pfrinfo->pskb->data) {
|
|
unsigned int *p_skb_int = (unsigned int *)pfrinfo->pskb->data;
|
|
printk("ERROR PKT===>> 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x <<===\n",
|
|
*p_skb_int, *(p_skb_int+1), *(p_skb_int+2), *(p_skb_int+3), *(p_skb_int+4), *(p_skb_int+5),
|
|
*(p_skb_int+6), *(p_skb_int+7));
|
|
}
|
|
#endif
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
if (GetFrameSubType(pframe) == (BIT(7)|WIFI_DATA_NULL)) { //Intel 6205 IOT issue
|
|
//printk("\n receive qos_null !!\n\n");
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if((OPMODE & WIFI_AP_STATE) && (QOS_ENABLE)) {
|
|
rtl8192cd_rx_handle_Spec_Null_Data(priv, pfrinfo); // for AR5007 IOT ISSUE
|
|
process_qos_null(priv, pfrinfo);
|
|
}
|
|
else
|
|
#endif
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
goto out;
|
|
}
|
|
|
|
#if 0
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
if(
|
|
#ifdef CLIENT_MODE
|
|
(OPMODE & WIFI_AP_STATE) &&
|
|
#endif
|
|
(QOS_ENABLE) && (APSD_ENABLE) && (GetFrameSubType(get_pframe(pfrinfo)) == (BIT(7)|WIFI_DATA_NULL))) {
|
|
rtl8192cd_rx_handle_Spec_Null_Data(priv, pfrinfo); // for AR5007 IOT ISSUE
|
|
process_qos_null(priv, pfrinfo);
|
|
goto out;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// for AR5007 IOT ISSUE
|
|
if ( (GetFrameSubType(pframe) == WIFI_DATA_NULL)
|
|
#ifdef WIFI_WMM
|
|
|| ((QOS_ENABLE) && ((GetFrameSubType(pframe)) == (WIFI_DATA_NULL | BIT(7))))
|
|
#endif
|
|
){
|
|
rtl8192cd_rx_handle_Spec_Null_Data(priv, pfrinfo);
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
goto out;
|
|
}
|
|
|
|
#ifdef RX_SHORTCUT
|
|
if (!priv->pmib->dot11OperationEntry.disable_rxsc &&
|
|
!IS_MCAST(pfrinfo->da)
|
|
#if defined(WIFI_WMM) && defined(WMM_APSD)
|
|
&& (!(
|
|
#ifdef CLIENT_MODE
|
|
(OPMODE & WIFI_AP_STATE) &&
|
|
#endif
|
|
(APSD_ENABLE) && (GetFrameSubType(pframe) == (WIFI_QOS_DATA)) && (GetPwrMgt(pframe))))
|
|
#endif
|
|
) {
|
|
if (rx_shortcut(priv, pfrinfo) >= 0) {
|
|
#if defined(SHORTCUT_STATISTIC) //defined(__ECOS) && defined(_DEBUG_RTL8192CD_)
|
|
priv->ext_stats.rx_cnt_sc++;
|
|
#endif
|
|
goto out;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0//rtk_nl80211 (for debug)
|
|
{
|
|
struct sk_buff *pskb = get_pskb(pfrinfo);
|
|
unsigned int encrypt;
|
|
unsigned char *pframe;
|
|
unsigned short proto;
|
|
|
|
unsigned int hdr_len;
|
|
unsigned char *pbuf;
|
|
|
|
// rx a encrypt packet but encryption is not enabled in local mib, discard it
|
|
hdr_len = pfrinfo->hdr_len;
|
|
pframe = get_pframe(pfrinfo);
|
|
pbuf = pframe + hdr_len + sizeof(struct wlan_llc_t) + 3;
|
|
proto = *(unsigned short *)pbuf;
|
|
|
|
if (proto == __constant_htons(0x888e))
|
|
printk("[rx eap] from 0x%02x 0x%02x 0x%02x\n", pfrinfo->sa[3], pfrinfo->sa[4], pfrinfo->sa[5]);
|
|
}
|
|
#endif
|
|
|
|
#if defined(SHORTCUT_STATISTIC) //defined(__ECOS) && defined(_DEBUG_RTL8192CD_)
|
|
priv->ext_stats.rx_cnt_nosc++;
|
|
#endif
|
|
pfrinfo = defrag_frame(priv, pfrinfo);
|
|
|
|
if (pfrinfo == NULL)
|
|
goto out;
|
|
|
|
if (process_datafrme(priv, pfrinfo) == FAIL) {
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
|
|
out:
|
|
return;
|
|
}
|
|
|
|
#ifdef CONFIG_PCI_HCI
|
|
#if !(defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX))
|
|
void process_all_queues(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct list_head *list = NULL;
|
|
|
|
#if defined(SMP_SYNC)
|
|
unsigned long x;
|
|
#endif
|
|
// processing data frame first...
|
|
while(1)
|
|
{
|
|
SMP_LOCK_RX_DATA(x);
|
|
list = dequeue_frame(priv, &(priv->rx_datalist));
|
|
SMP_UNLOCK_RX_DATA(x);
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
rtl8192cd_rx_dataframe(priv, list, NULL);
|
|
}
|
|
|
|
// going to process management frame
|
|
while(1)
|
|
{
|
|
SMP_LOCK_RX_MGT(x);
|
|
list = dequeue_frame(priv, &(priv->rx_mgtlist));
|
|
SMP_UNLOCK_RX_MGT(x);
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
rtl8192cd_rx_mgntframe(priv, list, NULL);
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
SMP_LOCK_RX_CTRL(x);
|
|
list = dequeue_frame(priv, &(priv->rx_ctrllist));
|
|
SMP_UNLOCK_RX_CTRL(x);
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
rtl8192cd_rx_ctrlframe(priv, list, NULL);
|
|
}
|
|
|
|
if (!list_empty(&priv->wakeup_list))
|
|
process_dzqueue(priv);
|
|
}
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
__IRAM_IN_865X
|
|
static void rtl88XX_rx_dsr(unsigned long task_priv)
|
|
{
|
|
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
unsigned long mask, mask_rx;
|
|
#ifdef MBSSID
|
|
int i;
|
|
#endif
|
|
|
|
#ifndef __ASUS_DVD__
|
|
extern int r3k_flush_dcache_range(int, int);
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
// disable rx interrupt in DSR
|
|
SAVE_INT_AND_CLI(flags);
|
|
GET_HAL_INTERFACE(priv)->DisableRxRelatedInterruptHandler(priv);
|
|
#endif
|
|
|
|
rtl8192cd_rx_isr(priv);
|
|
|
|
#ifdef __KERNEL__
|
|
RESTORE_INT(flags);
|
|
#endif
|
|
|
|
process_all_queues(priv);
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
process_all_queues(GET_VXD_PRIV(priv));
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i]))
|
|
process_all_queues(priv->pvap_priv[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
GET_HAL_INTERFACE(priv)->EnableRxRelatedInterruptHandler(priv);
|
|
#endif
|
|
}
|
|
#endif // CONFIG_WLAN_HAL
|
|
|
|
__IRAM_IN_865X
|
|
void rtl8192cd_rx_dsr(unsigned long task_priv)
|
|
{
|
|
struct rtl8192cd_priv *priv = (struct rtl8192cd_priv *)task_priv;
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
unsigned long mask, mask_rx, mask_ext, mask_ext_rx=0;
|
|
#ifdef MBSSID
|
|
int i;
|
|
#endif
|
|
|
|
#ifndef __ASUS_DVD__
|
|
extern int r3k_flush_dcache_range(int, int);
|
|
#endif
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if (IS_HAL_CHIP(priv)) {
|
|
rtl88XX_rx_dsr(task_priv);
|
|
return;
|
|
}else if(CONFIG_WLAN_NOT_HAL_EXIST)
|
|
#endif //CONFIG_WLAN_HAL
|
|
{//not HAL
|
|
#ifdef __KERNEL__
|
|
// disable rx interrupt in DSR
|
|
SAVE_INT_AND_CLI(flags);
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
if (priv->pshare->InterruptMask & HIMR_88E_ROK)
|
|
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask & ~HIMR_88E_ROK);
|
|
if (priv->pshare->InterruptMaskExt & HIMRE_88E_RXFOVW)
|
|
RTL_W32(REG_88E_HIMRE, priv->pshare->InterruptMaskExt & ~HIMRE_88E_RXFOVW);
|
|
} else
|
|
#endif
|
|
{
|
|
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
{
|
|
mask = RTL_R32(REG_92E_HIMR);
|
|
mask_rx = mask & HIMR_92E_ROK;
|
|
RTL_W32(REG_92E_HIMR, mask & ~mask_rx);
|
|
|
|
mask_ext = RTL_R32(REG_92E_HIMRE);
|
|
mask_ext_rx = mask_ext & HIMRE_92E_RXFOVW;
|
|
RTL_W32(REG_92E_HIMRE, mask_ext & ~mask_ext_rx);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
mask = RTL_R32(HIMR);
|
|
//mask_rx = mask & (HIMR_RXFOVW | HIMR_RDU | HIMR_ROK);
|
|
mask_rx = mask & (HIMR_RXFOVW | HIMR_ROK);
|
|
RTL_W32(HIMR, mask & ~mask_rx);
|
|
//RTL_W32(HISR, mask_rx);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
rtl8192cd_rx_isr(priv);
|
|
|
|
#ifdef __KERNEL__
|
|
RESTORE_INT(flags);
|
|
#endif
|
|
|
|
process_all_queues(priv);
|
|
|
|
#ifdef UNIVERSAL_REPEATER
|
|
if (IS_DRV_OPEN(GET_VXD_PRIV(priv)))
|
|
process_all_queues(GET_VXD_PRIV(priv));
|
|
#endif
|
|
|
|
#ifdef MBSSID
|
|
if (GET_ROOT(priv)->pmib->miscEntry.vap_enable) {
|
|
for (i=0; i<RTL8192CD_NUM_VWLAN; i++) {
|
|
if (IS_DRV_OPEN(priv->pvap_priv[i]))
|
|
process_all_queues(priv->pvap_priv[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8188E) {
|
|
if (priv->pshare->InterruptMask & HIMR_88E_ROK)
|
|
RTL_W32(REG_88E_HIMR, priv->pshare->InterruptMask);
|
|
if (priv->pshare->InterruptMaskExt & HIMRE_88E_RXFOVW)
|
|
RTL_W32(REG_88E_HIMRE, priv->pshare->InterruptMaskExt);
|
|
} else
|
|
#endif
|
|
{
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
{
|
|
RTL_W32(REG_92E_HIMR, RTL_R32(REG_92E_HIMR) | mask_rx);
|
|
RTL_W32(REG_92E_HIMRE, RTL_R32(REG_92E_HIMRE) | mask_ext_rx);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
mask = RTL_R32(HIMR);
|
|
RTL_W32(HIMR, mask | mask_rx);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif // !(defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX))
|
|
#endif // CONFIG_PCI_HCI
|
|
|
|
#if !(defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX))
|
|
void flush_rx_queue(struct rtl8192cd_priv *priv)
|
|
{
|
|
struct list_head *list = NULL;
|
|
struct rx_frinfo *pfrinfo = NULL;
|
|
|
|
while(1)
|
|
{
|
|
list = dequeue_frame(priv, &(priv->rx_datalist));
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
list = dequeue_frame(priv, &(priv->rx_mgtlist));
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
list = dequeue_frame(priv, &(priv->rx_ctrllist));
|
|
|
|
if (list == NULL)
|
|
break;
|
|
|
|
pfrinfo = list_entry(list, struct rx_frinfo, rx_list);
|
|
rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
|
|
}
|
|
}
|
|
#endif // !(defined(RTL8190_ISR_RX) && defined(RTL8190_DIRECT_RX))
|
|
|
|
|
|
#if defined(CONFIG_WLAN_HAL) || defined(CONFIG_RTL_8812_SUPPORT)|| defined(CONFIG_RTL_88E_SUPPORT)
|
|
static __inline__ unsigned char parse_ps_poll(struct rtl8192cd_priv *priv, struct stat_info *pstat) {
|
|
unsigned char Q_id[8];
|
|
unsigned char Q_pktnum[8];
|
|
int i=0;
|
|
unsigned int packet_num=0;
|
|
unsigned char hw_queue_num = 0;
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv)) {
|
|
hw_queue_num = 8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E){
|
|
hw_queue_num = 8;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8188E){
|
|
hw_queue_num = 4;
|
|
}
|
|
#endif
|
|
|
|
if(hw_queue_num) {
|
|
if(pstat->sta_in_firmware == 1)
|
|
{
|
|
/* check how many packet in hw queue now*/
|
|
#if defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_WLAN_HAL)
|
|
if(hw_queue_num == 8) { /* for 92E, 8812, & 8881A*/
|
|
for(i=0; i<4; i++) {
|
|
Q_pktnum[i] = (RTL_R8(0x400+i*4+1) & 0x7f); // 14:8 7b
|
|
if(Q_pktnum[i]) {
|
|
Q_id[i] = (RTL_R8(0x400+i*4+3)>>1) & 0x7f; //31:25 7b
|
|
} else {
|
|
Q_id[i] = 0;
|
|
}
|
|
Q_pktnum[i+4] = (RTL_R8(0x468+i*4+1) & 0x7f); // 14:8 7b
|
|
if(Q_pktnum[i+4]) {
|
|
Q_id[i+4] = (RTL_R8(0x468+i*4+3)>>1) & 0x7f; //31:25 7b
|
|
} else {
|
|
Q_id[i+4] = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(hw_queue_num == 4) { /* 88E */
|
|
for(i=0; i<4; i++) {
|
|
Q_pktnum[i] = RTL_R8(0x400+i*4+1);
|
|
if(Q_pktnum[i]) { // 15:8 7b
|
|
Q_id[i] = (RTL_R8(0x400+i*4+3)>>2) & 0x3f; //31:26 7b
|
|
} else {
|
|
Q_id[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for(i=0; i<hw_queue_num; i++) {
|
|
if (pstat->aid == Q_id[i]) {
|
|
packet_num += Q_pktnum[i];
|
|
}
|
|
}
|
|
|
|
|
|
if(pstat->txpause_flag == 1) {
|
|
if(packet_num > 1) {
|
|
/* drop packet in hw queue for 11n logo test 4.2.47,
|
|
DO NOT change the sequence!!*/
|
|
|
|
/*1. drop packet command*/
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, DECREASE);
|
|
#endif
|
|
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
UpdateHalMSRRPT8812(priv, pstat, DECREASE);
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8188E)
|
|
RTL8188E_MACID_NOLINK(priv, 1, REMAP_AID(pstat));
|
|
#endif
|
|
|
|
/*2. wait 500 us to make sure the H2C command is sent to hw, only 92E, 8812, and 8881A needed*/
|
|
if(hw_queue_num == 8)
|
|
delay_us(500);
|
|
|
|
|
|
/*3. relase tx pause*/
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
GET_HAL_INTERFACE(priv)->SetMACIDSleepHandler(priv, 0 , REMAP_AID(pstat));
|
|
#endif
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8812E)
|
|
RTL8812_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8188E)
|
|
RTL8188E_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
|
|
#endif
|
|
|
|
|
|
|
|
pstat->txpause_flag = 0;
|
|
|
|
|
|
/*4. wait 50*hwq_num us for hw to deque*/
|
|
if(hw_queue_num == 8)
|
|
delay_us(50*packet_num);
|
|
else
|
|
delay_us(120*packet_num); /* for 88E*/
|
|
|
|
|
|
/*5. cancel drop packet command*/
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat, INCREASE);
|
|
#endif
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8812E)
|
|
UpdateHalMSRRPT8812(priv, pstat, INCREASE);
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8188E)
|
|
RTL8188E_MACID_NOLINK(priv, 0, REMAP_AID(pstat));
|
|
#endif
|
|
}
|
|
|
|
if(pstat->txpause_flag){
|
|
/*relase tx pause*/
|
|
#ifdef CONFIG_WLAN_HAL
|
|
if(IS_HAL_CHIP(priv))
|
|
GET_HAL_INTERFACE(priv)->SetMACIDSleepHandler(priv, 0 , REMAP_AID(pstat));
|
|
#endif
|
|
#ifdef CONFIG_RTL_8812_SUPPORT
|
|
if (GET_CHIP_VER(priv)==VERSION_8812E)
|
|
RTL8812_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
|
|
#endif
|
|
#ifdef CONFIG_RTL_88E_SUPPORT
|
|
if(GET_CHIP_VER(priv)== VERSION_8188E)
|
|
RTL8188E_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
|
|
#endif
|
|
pstat->txpause_flag = 0;
|
|
|
|
}
|
|
|
|
if(packet_num == 1) {
|
|
return 1;
|
|
}
|
|
}
|
|
else {
|
|
if(packet_num > 0)
|
|
return 1;
|
|
}
|
|
|
|
|
|
DEBUG_WARN("%s %d OnPsPoll, set MACID 0 AID = %x \n",__FUNCTION__,__LINE__,REMAP_AID(pstat));
|
|
}
|
|
else
|
|
{
|
|
DEBUG_WARN(" MACID sleep only support %d STA \n", priv->pshare->fw_support_sta_num-1);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
#endif
|
|
|
|
static void ctrl_handler(struct rtl8192cd_priv *priv, struct rx_frinfo *pfrinfo)
|
|
{
|
|
struct sk_buff *pskbpoll, *pskb;
|
|
unsigned char *pframe;
|
|
struct stat_info *pstat;
|
|
unsigned short aid;
|
|
|
|
// 2009.09.08
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
|
|
DECLARE_TXINSN(txinsn);
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
pskbpoll = get_pskb(pfrinfo);
|
|
|
|
aid = GetAid(pframe);
|
|
|
|
pstat = get_aidinfo(priv, aid);
|
|
|
|
if (pstat == NULL)
|
|
goto end_ctrl;
|
|
|
|
// check if hardware address matches...
|
|
if (memcmp(pstat->hwaddr, (void *)(pframe + 10), MACADDRLEN))
|
|
goto end_ctrl;
|
|
|
|
#if defined(CONFIG_PCI_HCI)
|
|
#if defined(CONFIG_WLAN_HAL) || defined(CONFIG_RTL_8812_SUPPORT) || defined(CONFIG_RTL_88E_SUPPORT)
|
|
if ((GetFrameSubType(pframe)) == WIFI_PSPOLL)
|
|
{
|
|
if(parse_ps_poll(priv, pstat) == 1)
|
|
goto end_ctrl;
|
|
}
|
|
#endif
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
|
|
// now dequeue from the pstat's dz_queue
|
|
pskb = __skb_dequeue(&pstat->dz_queue);
|
|
|
|
RESTORE_INT(flags);
|
|
|
|
|
|
if (pskb == NULL)
|
|
goto end_ctrl;
|
|
|
|
txinsn.q_num = BE_QUEUE; //using low queue for data queue
|
|
txinsn.fr_type = _SKB_FRAME_TYPE_;
|
|
txinsn.pframe = pskb;
|
|
txinsn.phdr = (UINT8 *)get_wlanllchdr_from_poll(priv);
|
|
pskb->cb[1] = 0;
|
|
|
|
if (pskb->len > priv->pmib->dot11OperationEntry.dot11RTSThreshold)
|
|
txinsn.retry = priv->pmib->dot11OperationEntry.dot11LongRetryLimit;
|
|
else
|
|
txinsn.retry = priv->pmib->dot11OperationEntry.dot11ShortRetryLimit;
|
|
|
|
if (txinsn.phdr == NULL) {
|
|
DEBUG_ERR("Can't alloc wlan header!\n");
|
|
goto xmit_skb_fail;
|
|
}
|
|
|
|
memset((void *)txinsn.phdr, 0, sizeof(struct wlanllc_hdr));
|
|
|
|
SetFrDs(txinsn.phdr);
|
|
#ifdef WIFI_WMM
|
|
if (pstat && (QOS_ENABLE) && (pstat->QosEnabled))
|
|
SetFrameSubType(txinsn.phdr, WIFI_QOS_DATA);
|
|
else
|
|
#endif
|
|
SetFrameSubType(txinsn.phdr, WIFI_DATA);
|
|
|
|
if (skb_queue_len(&pstat->dz_queue))
|
|
SetMData(txinsn.phdr);
|
|
|
|
#ifdef A4_STA
|
|
if ((pstat->state & WIFI_A4_STA) && IS_MCAST(pskb->data)) {
|
|
txinsn.pstat = pstat;
|
|
SetToDs(txinsn.phdr);
|
|
}
|
|
#endif
|
|
|
|
if (rtl8192cd_wlantx(priv, &txinsn) == CONGESTED)
|
|
{
|
|
|
|
xmit_skb_fail:
|
|
|
|
priv->ext_stats.tx_drops++;
|
|
DEBUG_WARN("TX DROP: Congested!\n");
|
|
if (txinsn.phdr)
|
|
release_wlanllchdr_to_poll(priv, txinsn.phdr);
|
|
if (pskb)
|
|
rtl_kfree_skb(priv, pskb, _SKB_TX_);
|
|
}
|
|
|
|
#ifdef CONFIG_WLAN_HAL
|
|
// if ((GetFrameSubType(pframe)) == WIFI_PSPOLL)
|
|
{
|
|
if(IS_HAL_CHIP(priv))
|
|
{
|
|
#ifdef CONFIG_WLAN_HAL_8814AE
|
|
if (GET_CHIP_VER(priv) == VERSION_8814A) {
|
|
// Release one packet
|
|
GET_HAL_INTERFACE(priv)->ReleaseOnePacketHandler(priv,REMAP_AID(pstat));
|
|
}
|
|
#endif // #ifdef CONFIG_WLAN_HAL_8814AE
|
|
}
|
|
}
|
|
#endif
|
|
#endif // CONFIG_PCI_HCI
|
|
|
|
#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI)
|
|
pstat->sleep_time = jiffies;
|
|
if (tx_servq_len(&pstat->tx_queue[BE_QUEUE])) {
|
|
rtw_pspoll_sta_enqueue(priv, pstat, ENQUEUE_TO_TAIL);
|
|
tasklet_hi_schedule(&priv->pshare->xmit_tasklet);
|
|
}
|
|
#endif
|
|
|
|
end_ctrl:
|
|
|
|
if (pskbpoll) {
|
|
rtl_kfree_skb(priv, pskbpoll, _SKB_RX_);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
typedef struct tx_sts_struct
|
|
{
|
|
// DW 1
|
|
UINT8 TxRateid;
|
|
UINT8 TxRate;
|
|
} tx_sts;
|
|
|
|
typedef struct tag_Tx_Status_Feedback
|
|
{
|
|
// For endian transfer --> for driver
|
|
// DW 0
|
|
UINT16 Length; // Command packet length
|
|
UINT8 Reserve1;
|
|
UINT8 Element_ID; // Command packet type
|
|
|
|
tx_sts Tx_Sts[NUM_STAT];
|
|
} CMPK_TX_STATUS_T;
|
|
*/
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
static struct sk_buff *get_next_skb(struct rtl8192cd_priv *priv, int remove, int *is_last)
|
|
{
|
|
struct rx_frinfo *pfrinfo = NULL;
|
|
struct sk_buff *pskb = NULL;
|
|
struct list_head *phead, *plist;
|
|
#ifndef SMP_SYNC
|
|
unsigned long flags;
|
|
#endif
|
|
|
|
SAVE_INT_AND_CLI(flags);
|
|
|
|
phead = &priv->pshare->gather_list;
|
|
plist = phead->next;
|
|
|
|
if (plist != phead) {
|
|
pfrinfo = list_entry(plist, struct rx_frinfo, rx_list);
|
|
pskb = get_pskb(pfrinfo);
|
|
if (pskb) {
|
|
pskb->tail = pskb->data + pfrinfo->pktlen;
|
|
pskb->len = pfrinfo->pktlen;
|
|
pskb->dev = priv->dev;
|
|
if (remove)
|
|
list_del_init(plist);
|
|
}
|
|
}
|
|
|
|
if (is_last && pskb && pfrinfo->gather_flag == GATHER_LAST)
|
|
*is_last = 1;
|
|
|
|
RESTORE_INT(flags);
|
|
return pskb;
|
|
}
|
|
|
|
static struct sk_buff *shift_padding_len(struct rtl8192cd_priv *priv, struct sk_buff *skb, int len, int *is_last)
|
|
{
|
|
struct sk_buff *nskb= skb ;
|
|
|
|
if (skb->len < len) {
|
|
if (*is_last)
|
|
return NULL;
|
|
|
|
nskb = get_next_skb(priv, 1, is_last);
|
|
if (nskb)
|
|
skb_pull(nskb, len - skb->len);
|
|
else
|
|
DEBUG_ERR("Shift len error (%d, %d)!\n", skb->len, len);
|
|
}
|
|
else
|
|
skb_pull(nskb, len);
|
|
|
|
return nskb;
|
|
}
|
|
|
|
static int get_subframe_len(struct rtl8192cd_priv *priv, struct sk_buff *skb, int is_last)
|
|
{
|
|
u8 sub_len[2];
|
|
struct sk_buff *nskb;
|
|
int offset;
|
|
u16 u16_len;
|
|
|
|
if (skb->len < WLAN_ETHHDR_LEN) {
|
|
if (is_last)
|
|
return 0;
|
|
|
|
if (skb->len == WLAN_ETHHDR_LEN -1) {
|
|
sub_len[0] = skb->data[MACADDRLEN*2];
|
|
offset = 1;
|
|
}
|
|
else
|
|
offset = WLAN_ETHHDR_LEN -2 - skb->len;
|
|
|
|
nskb = get_next_skb(priv, 0, NULL);
|
|
if (nskb == NULL)
|
|
return -1;
|
|
|
|
if (offset == 1)
|
|
sub_len[1] = nskb->data[0];
|
|
else
|
|
memcpy(sub_len, nskb->data + offset, 2);
|
|
}
|
|
else
|
|
memcpy(sub_len, &skb->data[MACADDRLEN*2], 2);
|
|
|
|
u16_len = ntohs(*((u16 *)sub_len));
|
|
return ((int)u16_len);
|
|
}
|
|
|
|
static struct sk_buff *get_subframe(struct rtl8192cd_priv *priv, struct sk_buff *skb, struct sk_buff **orgskb, int len, int *is_last)
|
|
{
|
|
struct sk_buff *nextskb=NULL, *joinskb;
|
|
int offset, copy_len;
|
|
|
|
if (skb->len < len+WLAN_ETHHDR_LEN) {
|
|
int rest_len = len + WLAN_ETHHDR_LEN - skb->len;
|
|
|
|
if (*is_last)
|
|
return NULL;
|
|
|
|
joinskb = dev_alloc_skb(len + WLAN_ETHHDR_LEN);
|
|
if (joinskb == NULL) {
|
|
DEBUG_ERR("dev_alloc_skb() failed!\n");
|
|
return NULL;
|
|
}
|
|
memcpy(joinskb->data, skb->data, skb->len);
|
|
offset = skb->len;
|
|
|
|
do {
|
|
if (nextskb)
|
|
rtl_kfree_skb(priv, nextskb, _SKB_RX_);
|
|
|
|
nextskb = get_next_skb(priv, 1, is_last);
|
|
if (nextskb == NULL) {
|
|
dev_kfree_skb_any(joinskb);
|
|
return NULL;
|
|
}
|
|
|
|
if (nextskb->len < rest_len && *is_last) {
|
|
dev_kfree_skb_any(joinskb);
|
|
rtl_kfree_skb(priv, nextskb, _SKB_RX_);
|
|
return NULL;
|
|
}
|
|
if (nextskb->len < rest_len)
|
|
copy_len = nextskb->len;
|
|
else
|
|
copy_len = rest_len;
|
|
|
|
memcpy(joinskb->data+offset, nextskb->data, copy_len);
|
|
rest_len -= copy_len;
|
|
offset += copy_len;
|
|
skb_pull(nextskb, copy_len);
|
|
}while (rest_len > 0);
|
|
rtl_kfree_skb(priv, *orgskb, _SKB_RX_);
|
|
*orgskb = nextskb;
|
|
skb = joinskb;
|
|
}
|
|
else
|
|
skb_pull(*orgskb, len+WLAN_ETHHDR_LEN);
|
|
|
|
return skb;
|
|
}
|
|
#endif /* RX_BUFFER_GATHER */
|
|
|
|
#ifdef CONFIG_RTL_KERNEL_MIPS16_WLAN
|
|
__NOMIPS16
|
|
#endif
|
|
static void process_amsdu(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct rx_frinfo *pfrinfo)
|
|
{
|
|
unsigned char *pframe, *da;
|
|
struct stat_info *dst_pstat = NULL;
|
|
struct sk_buff *pskb = NULL, *pnewskb = NULL;
|
|
unsigned char *next_head;
|
|
int rest, agg_pkt_num=0, i, privacy;
|
|
unsigned int subfr_len, padding;
|
|
const unsigned char rfc1042_ip_header[8]={0xaa,0xaa,0x03,00,00,00,0x08,0x00};
|
|
#ifdef RX_BUFFER_GATHER
|
|
struct sk_buff *nskb;
|
|
int rx_gather = 0;
|
|
int is_last = 0;
|
|
#endif
|
|
|
|
pframe = get_pframe(pfrinfo);
|
|
pskb = get_pskb(pfrinfo);
|
|
|
|
rest = pfrinfo->pktlen - pfrinfo->hdr_len;
|
|
next_head = pframe + pfrinfo->hdr_len;
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
if (pfrinfo->gather_flag == GATHER_FIRST) {
|
|
skb_pull(pskb, pfrinfo->hdr_len);
|
|
rest = pfrinfo->gather_len - pfrinfo->hdr_len;
|
|
rx_gather = 1;
|
|
}
|
|
#endif
|
|
|
|
if (GetPrivacy(pframe)) {
|
|
#ifdef WDS
|
|
if (pfrinfo->to_fr_ds==3)
|
|
privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
|
|
else
|
|
#endif
|
|
privacy = get_sta_encrypt_algthm(priv, pstat);
|
|
if ((privacy == _CCMP_PRIVACY_) || (privacy == _TKIP_PRIVACY_)) {
|
|
rest -= 8;
|
|
next_head += 8;
|
|
#ifdef RX_BUFFER_GATHER
|
|
pskb->data += 8;
|
|
pskb->len -= 8;
|
|
#endif
|
|
|
|
}
|
|
else { // WEP
|
|
rest -= 4;
|
|
next_head += 4;
|
|
#ifdef RX_BUFFER_GATHER
|
|
pskb->data += 4;
|
|
pskb->len -= 4;
|
|
#endif
|
|
|
|
}
|
|
}
|
|
//Wifi Logo FFD 4.2.1
|
|
if (isEqualMACAddr(next_head, rfc1042_ip_header))
|
|
{
|
|
DEBUG_ERR("RX DROP: LLC header within an A-MSDU subframe!\n");
|
|
#ifdef RX_BUFFER_GATHER_REORDER
|
|
if(pfrinfo->gather_flag == GATHER_FIRST)
|
|
flush_rx_list_inq(priv, pfrinfo);
|
|
#endif
|
|
priv->ext_stats.rx_data_drops++;
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
return;
|
|
}
|
|
while (rest > WLAN_ETHHDR_LEN) {
|
|
pnewskb = skb_clone(pskb, GFP_ATOMIC);
|
|
if (pnewskb) {
|
|
pnewskb->data = next_head;
|
|
#ifdef RX_BUFFER_GATHER
|
|
if (rx_gather) {
|
|
subfr_len = get_subframe_len(priv, pnewskb, is_last);
|
|
if (subfr_len <= 0) {
|
|
DEBUG_ERR("invalid subfr_len=%d, discard AMSDU!\n", subfr_len);
|
|
dev_kfree_skb_any(pnewskb);
|
|
break;
|
|
}
|
|
nskb = get_subframe(priv, pnewskb, &pskb, subfr_len, &is_last);
|
|
if (nskb == NULL) {
|
|
DEBUG_ERR("get_subframe() failed, discard AMSDU!\n");
|
|
dev_kfree_skb_any(pnewskb);
|
|
priv->ext_stats.rx_data_drops++;
|
|
break;
|
|
}
|
|
if (nskb != pnewskb) {
|
|
nskb->dev = pnewskb->dev;
|
|
dev_kfree_skb_any(pnewskb);
|
|
pnewskb = nskb;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
subfr_len = (*(next_head + MACADDRLEN*2) << 8) + (*(next_head + MACADDRLEN*2 + 1));
|
|
|
|
pnewskb->len = WLAN_ETHHDR_LEN + subfr_len;
|
|
pnewskb->tail = pnewskb->data + pnewskb->len;
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_inc(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
|
|
if(pnewskb->tail > pnewskb->end) {
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_RX_);
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: sub-frame length too large!\n");
|
|
break;
|
|
}
|
|
|
|
if (!memcmp(rfc1042_ip_header, pnewskb->data+WLAN_ETHHDR_LEN, 8)) {
|
|
for (i=0; i<MACADDRLEN*2; i++)
|
|
pnewskb->data[19-i] = pnewskb->data[11-i];
|
|
pnewskb->data += 8;
|
|
pnewskb->len -= 8;
|
|
}
|
|
else
|
|
strip_amsdu_llc(priv, pnewskb, pstat);
|
|
agg_pkt_num++;
|
|
|
|
if (OPMODE & WIFI_AP_STATE)
|
|
{
|
|
da = pnewskb->data;
|
|
dst_pstat = get_stainfo(priv, da);
|
|
if ((dst_pstat == NULL) || (!(dst_pstat->state & WIFI_ASOC_STATE)))
|
|
rtl_netif_rx(priv, pnewskb, pstat);
|
|
else
|
|
{
|
|
if (priv->pmib->dot11OperationEntry.block_relay == 1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: Relay unicast packet is blocked!\n");
|
|
#ifdef RX_SHORTCUT
|
|
for (i=0; i<RX_SC_ENTRY_NUM; i++) { // shortcut data saved, clear it
|
|
dst_pstat->rx_sc_ent[i].rx_payload_offset = 0;
|
|
}
|
|
#endif
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_RX_);
|
|
}
|
|
else if (priv->pmib->dot11OperationEntry.block_relay == 2) {
|
|
DEBUG_INFO("Relay unicast packet is blocked! Indicate to bridge.\n");
|
|
rtl_netif_rx(priv, pnewskb, pstat);
|
|
}
|
|
else {
|
|
#ifdef ENABLE_RTL_SKB_STATS
|
|
rtl_atomic_dec(&priv->rtl_rx_skb_cnt);
|
|
#endif
|
|
#ifdef GBWC
|
|
if (GBWC_forward_check(priv, pnewskb, pstat)) {
|
|
// packet is queued, nothing to do
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef TX_SCATTER
|
|
pnewskb->list_num = 0;
|
|
#endif
|
|
#ifdef CONFIG_RTK_MESH
|
|
if (rtl8192cd_start_xmit(pnewskb, isMeshPoint(dst_pstat) ? priv->mesh_dev: priv->dev))
|
|
#else
|
|
if (rtl8192cd_start_xmit(pnewskb, priv->dev))
|
|
#endif
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_TX_);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef CLIENT_MODE
|
|
else if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE))
|
|
{
|
|
#ifdef RTK_BR_EXT
|
|
if(nat25_handle_frame(priv, pnewskb) == -1) {
|
|
priv->ext_stats.rx_data_drops++;
|
|
DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n");
|
|
rtl_kfree_skb(priv, pnewskb, _SKB_RX_);
|
|
} else
|
|
#endif
|
|
rtl_netif_rx(priv, pnewskb, pstat);
|
|
}
|
|
#endif
|
|
|
|
padding = 4 - ((WLAN_ETHHDR_LEN + subfr_len) % 4);
|
|
if (padding == 4)
|
|
padding = 0;
|
|
rest -= (WLAN_ETHHDR_LEN + subfr_len + padding);
|
|
|
|
#ifdef RX_BUFFER_GATHER
|
|
if (rx_gather) {
|
|
if ((rest <= WLAN_ETHHDR_LEN) && is_last)
|
|
break;
|
|
|
|
nskb = shift_padding_len(priv, pskb, padding, &is_last);
|
|
if (nskb == NULL) {
|
|
DEBUG_ERR("shift AMSDU padding len error!\n");
|
|
break;
|
|
}
|
|
if (nskb != pskb) {
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
pskb = nskb;
|
|
}
|
|
next_head = pskb->data;
|
|
}
|
|
else
|
|
#endif
|
|
next_head += (WLAN_ETHHDR_LEN + subfr_len + padding);
|
|
}
|
|
else {
|
|
// Can't get new skb header, drop this packet
|
|
break;
|
|
}
|
|
}
|
|
|
|
// clear saved shortcut data
|
|
#ifdef RX_SHORTCUT
|
|
for (i=0; i<RX_SC_ENTRY_NUM; i++) {
|
|
pstat->rx_sc_ent[i].rx_payload_offset = 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _DEBUG_RTL8192CD_
|
|
switch (agg_pkt_num) {
|
|
case 0:
|
|
pstat->rx_amsdu_err++;
|
|
break;
|
|
case 1:
|
|
pstat->rx_amsdu_1pkt++;
|
|
break;
|
|
case 2:
|
|
pstat->rx_amsdu_2pkt++;
|
|
break;
|
|
case 3:
|
|
pstat->rx_amsdu_3pkt++;
|
|
break;
|
|
case 4:
|
|
pstat->rx_amsdu_4pkt++;
|
|
break;
|
|
case 5:
|
|
pstat->rx_amsdu_5pkt++;
|
|
break;
|
|
default:
|
|
pstat->rx_amsdu_gt5pkt++;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
rtl_kfree_skb(priv, pskb, _SKB_RX_);
|
|
}
|
|
|