summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c')
-rw-r--r--target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c8482
1 files changed, 8482 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c b/target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c
new file mode 100644
index 000000000..9bf52e538
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/wireless/rtl8192e/8192cd_rx.c
@@ -0,0 +1,8482 @@
+/*
+ * 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>
+#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
+#include <net/rtl/rtl_types.h>
+#ifndef __ECOS
+#ifdef NOT_RTK_BSP
+#include "br_private.h"
+#else
+#include <../net/bridge/br_private.h>
+#endif
+#endif
+#endif
+#endif
+
+#ifdef _BROADLIGHT_FASTPATH_
+extern int (*send_packet_to_upper_layer)(struct sk_buff *skb);
+#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 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[MACADDRLEN];
+__DRAM_IN_865X struct net_device *cached_mesh_dev = NULL;
+#endif
+#ifdef CLIENT_MODE
+__DRAM_IN_865X unsigned char cached_sta_mac[MACADDRLEN];
+__DRAM_IN_865X struct net_device *cached_sta_dev = NULL;
+#endif
+
+#if defined(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;
+extern struct net_device *get_shortcut_dev(unsigned char *da);
+#endif
+
+#endif
+
+//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
+// MBSSID Port Mapping
+extern struct port_map wlanDev[];
+extern int g_port_mapping;
+#endif
+
+#ifdef 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
+
+#if defined(CONFIG_RTL_EAP_RELAY) || defined(CONFIG_RTK_INBAND_HOST_HACK)
+extern unsigned char inband_Hostmac[]; //it's from br.c
+#endif
+/* ======================== RX procedure declarations ======================== */
+#ifndef CONFIG_RTK_MESH
+static
+#endif
+ void rtl8192cd_rx_mgntframe(struct rtl8192cd_priv *priv,
+ struct list_head *list, struct rx_frinfo *inputPfrinfo);
+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);
+
+
+#ifndef USE_OUT_SRC
+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;
+}
+
+#ifndef USE_OUT_SRC
+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;
+ unsigned char *frame = get_pframe(pfrinfo) + (pfrinfo->rxbuf_shift + pfrinfo->driver_info_size);
+ struct stat_info *pstat = get_stainfo(priv, GetAddr2Ptr(frame));
+
+ 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 = 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)
+ if ((GET_CHIP_VER(priv) == VERSION_8812E && !IS_C_CUT_8812(priv))
+ || (GET_CHIP_VER(priv) == VERSION_8881A)) {
+ 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
+
+
+}
+#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);
+
+ /*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;
+ }
+
+ 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 Jacken from Bryant 2008-03-20
+ //Original value is -38 , -26 , -14 , -2
+ //Fixed value is -35 , -23 , -11 , 6
+ case 0x3:
+ rx_pwr_all = -35 - (pCck_buf->cck_agc_rpt & 0x3e);
+ break;
+ case 0x2:
+ rx_pwr_all = -23 - (pCck_buf->cck_agc_rpt & 0x3e);
+ break;
+ case 0x1:
+ rx_pwr_all = -11 - (pCck_buf->cck_agc_rpt & 0x3e);
+ break;
+ case 0x0:
+ rx_pwr_all = 8 - (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 Jacken from Bryant 2008-03-20
+ case 0x3:
+ rx_pwr_all = -35 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
+ break;
+ case 0x2:
+ rx_pwr_all = -23 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
+ break;
+ case 0x1:
+ rx_pwr_all = -11 - ((pCck_buf->cck_agc_rpt & 0x1f)<<1);
+ break;
+ case 0x0:
+ rx_pwr_all = -8 - ((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)) {
+ 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 {
+ if (PWDB_ALL > 99)
+ PWDB_ALL -= 8;
+ else if (PWDB_ALL > 50 && PWDB_ALL <= 68)
+ PWDB_ALL += 4;
+ }
+
+ pfrinfo->rssi = PWDB_ALL;
+ if (priv->pshare->rf_ft_var.use_ext_lna)
+ pfrinfo->rssi+=10;
+ } 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
+ ) && (priv->pshare->rf_ft_var.use_ext_lna)) {
+ 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
+ //
+ if ((pfrinfo->rx_rate >= 0x88) && (pfrinfo->rx_rate <= 0x8f))
+ 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
+
+
+#ifdef 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);
+
+ DaIpAddr = iph->daddr;
+ //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)
+{
+#if defined(__LINUX_2_6__) //&& !defined(CONFIG_RTL8672)
+ struct ipv6hdr *iph = (struct ipv6hdr *)(skb_mac_header(pskb) + ETH_HLEN);
+ unsigned char *DDA=skb_mac_header(pskb);
+#else
+ struct ipv6hdr *iph = (struct ipv6hdr *)(pskb->mac.raw + ETH_HLEN);
+ unsigned char *DDA=pskb->mac.raw;
+#endif
+
+
+ /*ip(v6) format is multicast ip*/
+ if (iph->daddr.s6_addr[0] == 0xff){
+
+ /*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;
+ memcpy(DDA+2, &iph->daddr.s6_addr[12], 4);
+ }
+ }
+}
+#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;
+
+#ifdef BR_SHORTCUT_C2
+ extern unsigned char cached_eth_addr2[MACADDRLEN];
+ extern struct net_device *cached_dev2;
+#endif
+
+ if (cached_dev && !memcmp(da, cached_eth_addr, MACADDRLEN))
+ return cached_dev;
+#ifdef BR_SHORTCUT_C2
+ else if (cached_dev2 && !memcmp(da, cached_eth_addr2, MACADDRLEN))
+ return cached_dev2;
+#endif
+ 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 ___igmp_type_check(struct sk_buff *skb, unsigned char *gmac)
+{
+ struct iphdr *iph;
+ __u8 hdrlen;
+ struct igmphdr *igmph;
+
+#if 1
+ unsigned int IGMP_Group;// add for fit igmp v3
+#endif
+
+ /* check IP header information */
+ iph = ip_hdr(skb);
+ hdrlen = iph->ihl << 2;
+ if ((iph->version != 4) && (hdrlen < 20))
+ return -1;
+ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+ return -1;
+ { /* check the length */
+ __u32 len = ntohs(iph->tot_len);
+ if (skb->len < len || len < hdrlen)
+ return -1;
+ }
+ /* parsing the igmp packet */
+ igmph = (struct igmphdr *)((u8*)iph+hdrlen);
+
+#if 1
+ /*IGMP-V3 type Report*/
+ if(igmph->type == IGMPV3_HOST_MEMBERSHIP_REPORT)
+ {
+ //printk("rec v3 report 1\n");
+ /*in 11n seem need no care igmpProxy is opened or not,plus 2008-0612*/
+ #if 0
+ if(IGMPProxyOpened==0){
+ IGMP_Group = *(unsigned int*)((unsigned int*)igmph + 3);
+
+ //printk("v3_group:%02X:%02X:%02X:%02X\n",
+ //IGMP_Group>>24,(IGMP_Group<<8)>>24,(IGMP_Group<<16)>>24,(IGMP_Group<<24)>>24);
+ }else{
+ return -1;//don't care v3 report
+ }
+ #else
+ IGMP_Group = *(unsigned int*)((unsigned int*)igmph + 3);
+ #endif
+
+ }else{ //4 V2 or V1
+ //printk("igmph->group:%04X\n",igmph->group);
+ IGMP_Group = igmph->group;
+ }
+#endif
+#if 1
+
+ /*check if it's protocol reserved group */
+ if(!IN_MULTICAST(IGMP_Group))
+ {
+ return -1;
+ }
+ //Brad disable 20080619
+ /*
+ if((IGMP_Group&0xFFFFFF00)==0xE0000000){
+ return -1;
+ }
+ */
+ ___ConvertMulticatIPtoMacAddr(IGMP_Group, gmac);
+
+#else
+ if(!IN_MULTICAST(igmph->group))
+ return -1;
+ /* check if it's protocol reserved group */
+ if((igmph->group&0xFFFFFF00)==0xE0000000)
+ return -1;
+
+ ConvertMulticatIPtoMacAddr(igmph->group, gmac);
+#endif
+
+ if ((igmph->type==IGMP_HOST_MEMBERSHIP_REPORT) ||
+ (igmph->type==IGMPV2_HOST_MEMBERSHIP_REPORT))
+ {
+ return 1; /* report and add it */
+ }
+
+ else if (igmph->type==IGMPV3_HOST_MEMBERSHIP_REPORT) {
+
+ /*for support igmp v3 ; plusWang add 2009-0311*/
+
+ struct igmpv3_grec *v3grec = (struct igmpv3_grec *)((unsigned char*)igmph + 8);
+
+
+ if(v3grec->grec_type == IGMPV3_CHANGE_TO_INCLUDE){
+
+ //printk("igmp-v3 C2I\n");
+ return 2; /* leave and delete it */
+
+ }else if(v3grec->grec_type == IGMPV3_CHANGE_TO_EXCLUDE){
+
+ //printk("igmp-v3 C2E\n");
+ return 1;
+ }
+ /*
+ else{
+ printk("v3grec->grec_type =%d\n",v3grec->grec_type);
+ printk("no yet support igmp-v3 type\n");
+ }
+ */
+
+
+ }
+ else if (igmph->type==IGMP_HOST_LEAVE_MESSAGE){
+ return 2; /* leave and delete it */
+ }
+
+ return -1;
+}
+
+
+
+
+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];
+
+ if (strncmp(skb->dev->name,"wlan",4))
+ return;
+
+
+ type = ___igmp_type_check(skb,StaMacAndGroup);
+ //printk("%s(%d): got msg %x\n", __FUNCTION__,__LINE__,type);
+
+ switch (type) {
+ case 1:
+ op = 0x8B80;
+ //printk("op = 0x8B80\n");
+ break;
+ case 2:
+ op = 0x8B81;
+ //printk("op = 0x8B81\n");
+ break;
+ default:
+ return;
+
+ }
+ memcpy(StaMacAndGroup+6, skb_mac_header(skb)+6, 6);
+ rtl8192cd_ioctl(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;
+
+ if (IS_MCAST(dest))
+ {
+ if (unlikely((*(unsigned short *)(skb_mac_header(pskb) + ETH_ALEN * 2) == __constant_htons(ETH_P_IP))))
+ {
+ iph = (struct iphdr *)(skb_mac_header(pskb) + ETH_HLEN);
+ pskb->network_header = (sk_buff_data_t)iph;
+ 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]);
+ pskb->transport_header = pskb->network_header + (iph->ihl * 4);
+ rtl_igmp_notify(pskb, pskb->transport_header);
+ }
+ }
+ }
+}
+
+
+#endif //_FULLY_WIFI_IGMP_SNOOPING_SUPPORT_
+
+#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
+
+#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)
+ if (SUCCESS==rtl_isPassthruFrame(pskb->data)) {
+#ifdef CLIENT_MODE
+ if(priv &&((GET_MIB(priv))->dot11OperationEntry.opmode)& WIFI_STATION_STATE)
+ {
+ #if defined(CONFIG_RTL_92D_SUPPORT)
+ unsigned int wispWlanIndex=(passThruStatusWlan&WISP_WLAN_IDX_MASK)>>WISP_WLAN_IDX_RIGHT_SHIFT;
+ if((priv==(GET_VXD_PRIV((wlan_device[wispWlanIndex].priv))))
+ ||(priv == wlan_device[wispWlanIndex].priv))
+ {
+ pskb->dev = wlan_device[passThruWanIdx].priv->pWlanDev;
+ }
+ #else
+ pskb->dev = wlan_device[passThruWanIdx].priv->pWlanDev;
+ #endif
+
+ }
+#endif
+ }
+#endif
+
+#ifdef CONFIG_RTL8672
+ int k;
+ // Modofied by Mason Yu
+ // MBSSID Port Mapping
+ if ( g_port_mapping == TRUE ) {
+ for (k=0; k<5; k++) {
+ if ( priv->dev == wlanDev[k].dev_pointer ) {
+ pskb->vlan_member = wlanDev[k].dev_ifgrp_member;
+ break;
+ }
+ }
+ }
+#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 int)(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 int)(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
+
+#ifdef _11s_TEST_MODE_
+ mesh_debug_rx1(priv, pskb);
+#endif
+
+#ifdef 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)
+ netif_receive_skb(pskb);
+ #else
+ netif_rx(pskb);
+ #endif
+ }
+ }
+ }
+ else
+#endif
+ {
+#ifdef CONFIG_RTK_VLAN_SUPPORT
+ if (rtk_vlan_support_enable && priv->pmib->vlan.global_vlan) {
+#if defined(CONFIG_RTK_VLAN_NEW_FEATURE)
+ if (rx_vlan_process(priv->dev, &priv->pmib->vlan, pskb, NULL)){
+#else
+ if (rx_vlan_process(priv->dev, &priv->pmib->vlan, pskb)){
+#endif
+ priv->ext_stats.rx_data_drops++;
+ DEBUG_ERR("RX DROP: by vlan!\n");
+ rtl_kfree_skb(priv, pskb, _SKB_RX_);
+ 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(BR_SHORTCUT)
+ {
+ struct net_device *cached_dev=NULL;
+
+#ifdef CONFIG_RTK_MESH
+
+ if (pskb->dev && (pskb->dev == priv->mesh_dev))
+ {
+ //chris:
+ proxy_table_chkcln(priv, pskb);
+ memcpy(cached_mesh_mac, &pskb->data[6], 6);
+ cached_mesh_dev = 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) {
+ memcpy(cached_sta_mac, &pskb->data[6], 6);
+ cached_sta_dev = pskb->dev;
+
+ if (!(pskb->data[0] & 0x01) &&
+ !priv->pmib->dot11OperationEntry.disable_brsc &&
+#ifdef __KERNEL__
+ (priv->dev->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 &&
+#ifdef __KERNEL__
+ (priv->dev->br_port) &&
+#endif
+ (!memcmp(cached_sta_mac,pskb->data,6)) &&
+ (cached_sta_dev !=NULL)
+ && netif_running(cached_sta_dev)) {
+ pskb->dev = cached_sta_dev;
+#if !defined(__LINUX_2_6__) || defined(CONFIG_COMPAT_NET_DEV_OPS)
+ cached_sta_dev->hard_start_xmit(pskb, cached_sta_dev);
+#else
+ cached_sta_dev->netdev_ops->ndo_start_xmit(pskb,cached_sta_dev);
+#endif
+ return;
+ }
+ }
+#endif
+#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
+#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)
+ (priv->dev->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_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(__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 (priv->dev->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[8]) = 0x86518190; // means from wlan interface
+ *(unsigned int *)&(pskb->cb[12]) = priv->pmib->miscEntry.groupID; // remember group ID
+ }
+#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 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;
+#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))
+ {
+ 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) &&
+#if defined(__LINUX_2_6__) && !defined(CONFIG_RTL8672)
+ (*((unsigned char *)(skb_mac_header(pskb) + 0)) & 0x01) &&
+#else
+ (*((unsigned char *)pskb->mac.raw) & 0x01) &&
+#endif
+ !priv->pmib->dot11OperationEntry.disable_brsc &&
+ (priv->dev->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
+
+#if 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)
+ netif_receive_skb(pskb);
+ #else
+#if defined(__ECOS) && defined(ISR_DIRECT)
+ netif_rx(pskb, wlan_device[0].priv->dev);
+#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 int)(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 int)(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 CONFIG_ETHWAN
+__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 TX_SCATTER
+ pskb->list_num = 0;
+#endif
+#ifdef CONFIG_RTK_MESH
+ #ifdef RX_RL_SHORTCUT
+ if (GET_MIB(priv)->dot1180211sInfo.mesh_enable && isMeshPoint(pstat) && isMeshPoint(dst_pstat)){
+ DECLARE_TXINSN(txinsn);
+ memcpy(txinsn.nhop_11s, dst_pstat->hwaddr, MACADDRLEN);
+ txinsn.is_11s = RELAY_11S;
+ fire_data_frame(pskb, priv->mesh_dev, &txinsn);
+ } else
+ #endif
+ 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_RX_);
+ }
+}
+
+
+__MIPS16
+#ifndef CONFIG_ETHWAN
+__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 CONFIG_ETHWAN
+__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_sync(&priv->pshare->rc_sys_timer);
+#ifdef __ECOS
+ reorder_ctrl_timeout((void *)priv);
+#else
+ reorder_ctrl_timeout((unsigned long)priv);
+#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_sync(&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 CONFIG_ETHWAN
+__IRAM_IN_865X
+#endif
+#if defined(__ECOS)
+void reorder_ctrl_timeout(void *task_priv)
+#elif defined(USE_WLAN_TIMER_FOR_RC) || defined(__KERNEL__)
+void reorder_ctrl_timeout(unsigned long task_priv)
+#endif
+{
+ 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(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) <= 1)) {
+ 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(flags);
+ return;
+ }
+ }
+
+ priv->pshare->rc_timer_tail = (priv->pshare->rc_timer_tail + 1) & (RC_TIMER_NUM - 1);
+
+ if (pstat) {
+ if (!(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(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 CONFIG_ETHWAN
+__IRAM_IN_865X
+#endif
+static 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;
+
+ 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))
+ 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;
+ return TRUE;
+ }
+ else
+ {
+ segment = check_win_seqment(win_start, win_end, seq);
+ if (segment == 1) {
+#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);
+ }
+ return FALSE;
+ }
+ else if (segment == 3) {
+ index = seq & (win_size - 1);
+ if (rc_entry->packet_q[index]) {
+#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);
+ }
+ 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);
+ 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)
+{
+ 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);
+}
+
+
+__MIPS16
+__IRAM_IN_865X
+int get_rx_sc_index(struct stat_info *pstat, unsigned char *pframe)
+{
+ int i;
+
+ for (i=0; i<RX_SC_ENTRY_NUM; i++) {
+ if (!memcmp(GetAddr1Ptr(pframe), pstat->rx_wlanhdr[i].wlanhdr.addr1, 18))
+ return i;
+ }
+
+ return -1;
+}
+
+
+__MIPS16
+__IRAM_IN_865X
+int get_rx_sc_free_entry(struct stat_info *pstat, unsigned char *pframe)
+{
+ int i;
+
+ i = get_rx_sc_index(pstat, pframe);
+ if (i >= 0)
+ return i;
+ else {
+ for (i=0; i<RX_SC_ENTRY_NUM; i++) {
+ if (pstat->rx_payload_offset[i] == 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;
+}
+
+
+unsigned char rfc1042_header[WLAN_LLC_HEADER_SIZE]={0xaa,0xaa,0x03,00,00,00};
+
+/*---------------------------------------------------------------
+ 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 CONFIG_ETHWAN
+__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)
+
+ unsigned char *meshHdrPtr=NULL;
+ //unsigned char zeromac[6]={0x00,0x00,0x00,0x00,0x00,0x00};
+ struct path_sel_entry *pEntry = NULL;
+#endif
+ unsigned char is_qos_datafrm=0;
+
+ pstat = get_stainfo(priv, GetAddr2Ptr(pframe));
+ is_qos_datafrm = is_qos_data(pframe);
+/*
+ printk("pfrinfo->is_11s = %d\n", pfrinfo->is_11s);
+ //printk("pfrinfo->mesh_header.DestMACAddr = %02x\n", pfrinfo->mesh_header.DestMACAddr[5]);
+ //printk("pfrinfo->mesh_header.SrcMACAddr = %02x\n", pfrinfo->mesh_header.SrcMACAddr[5]);
+ printk("pstat->rx_wlanhdr.wlanhdr.meshhdr.DestMACAddr = %02x\n", pstat->rx_wlanhdr.wlanhdr.meshhdr.DestMACAddr[5]);
+ printk("pstat->rx_wlanhdr.wlanhdr.meshhdr.SrcMACAddr = %02x\n", pstat->rx_wlanhdr.wlanhdr.meshhdr.SrcMACAddr[5]);
+ printk("pstat->rx_payload_offset = %d\n", pstat->rx_payload_offset);
+ */
+
+#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 int)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) &&
+ pstat->rx_payload_offset[idx] &&
+ (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)
+ extern void mesh_shortcut_update(DRV_PRIV *priv, struct rx_frinfo *pfrinfo);
+
+ if (pfrinfo->is_11s) {
+
+ if (memcmp(GetAddr4Ptr(pframe), pstat->rx_wlanhdr[idx].wlanhdr.addr4, MACADDRLEN)){
+ goto shouldnot_rxsc;
+ }
+ if (memcmp(GetAddr3Ptr(pframe), GET_MY_HWADDR, MACADDRLEN)) {
+ pEntry = priv->pathsel_table->search_entry(priv->pathsel_table, GetAddr3Ptr(pframe));
+ if (pEntry) {
+ //printk("pEntry -> nh %02x \n", pEntry->nexthopMAC[5]);
+ }
+ else
+ goto shouldnot_rxsc;
+ }
+
+
+ meshHdrPtr = getMeshHeader(priv, priv->pmib->dot11sKeysTable.dot11Privacy, pframe);
+ if( meshHdrPtr )
+ {
+ if((int)(*(meshHdrPtr+1)) == 0) // *(meshHdrPtr+1)) = TTL; filter packets due to duplicate
+ goto shouldnot_rxsc;
+
+ memcpy(&(pfrinfo->mesh_header), meshHdrPtr, sizeof(struct lls_mesh_header) );
+ }
+ else {
+ goto shouldnot_rxsc;
+ }
+
+
+ if (( pfrinfo->mesh_header.mesh_flag)&1) //only shorcut 6 address
+ {
+ if (memcmp(pfrinfo->mesh_header.DestMACAddr, pstat->rx_wlanhdr[idx].wlanhdr.meshhdr.DestMACAddr, 6) ||
+ memcmp(pfrinfo->mesh_header.SrcMACAddr, pstat->rx_wlanhdr[idx].wlanhdr.meshhdr.SrcMACAddr, 6)) {
+ goto shouldnot_rxsc;
+ }
+ } else {
+ goto shouldnot_rxsc;
+ }
+
+ mesh_shortcut_update(priv, pfrinfo);
+ 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), pstat->rx_wlanhdr[idx].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), pstat->rx_wlanhdr[idx].wlanhdr.addr4, 6))
+ goto shouldnot_rxsc;
+ a4_sta_add(priv, pstat, GetAddr4Ptr(pframe));
+ }
+#endif
+ pfrinfo->pskb->dev = priv->dev;
+
+ offset = pstat->rx_payload_offset[idx] + sizeof(rfc1042_header);
+
+/*
+ printk("pstat->rx_payload_offset = %02x, 0xaa, cmp = %d \n",pframe[pstat->rx_payload_offset[idx]],
+ memcmp(&pframe[pstat->rx_payload_offset[idx]], rfc1042_header, 6));
+ printk("pstat->rx_ethhdr.type = %02x, pframe[offset] = %02x, cmp= %d \n", pstat->rx_ethhdr.type, pframe[offset],
+ memcmp(&pstat->rx_ethhdr[idx].type,&pframe[offset], 2));
+*/
+ // check snap header
+ if (memcmp(&pframe[pstat->rx_payload_offset[idx]], rfc1042_header, 6) ||
+ memcmp(&pstat->rx_ethhdr[idx].type,&pframe[offset], 2))
+ goto shouldnot_rxsc;
+
+ payload_length = pfrinfo->pktlen - offset - pstat->rx_trim_pad[idx] - 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");
+ priv->ext_stats.rx_data_drops++;
+ 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++;
+#ifdef USE_OUT_SRC
+#ifdef _OUTSRC_COEXIST
+ if(IS_OUTSRC_CHIP(priv))
+#endif
+ priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
+#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)
+ {
+ GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, REMAP_AID(pstat), INCREASE);
+ }
+ 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 *)&pstat->rx_ethhdr[idx], 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)
+ {
+
+// Button 2009.7.31
+#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
+ if (pfrinfo->is_11s )
+ dst_pstat = (pEntry) ? get_stainfo(priv, pEntry->nexthopMAC) : 0;
+ else
+#endif
+ dst_pstat = get_stainfo(priv, da);
+
+#ifdef A4_STA
+ if (priv->pshare->rf_ft_var.a4_enable && (dst_pstat == NULL))
+ dst_pstat = a4_sta_lookup(priv, da);
+#endif
+
+#if defined(CONFIG_RTK_MESH) || defined(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
+ {
+
+// Button 2009.7.31
+#if defined(CONFIG_RTK_MESH) && defined(RX_RL_SHORTCUT)
+ if (pfrinfo->is_11s && (pEntry!=NULL)) {
+ //chris 080409
+ DECLARE_TXINSN(txinsn);
+ memcpy(txinsn.nhop_11s, pEntry->nexthopMAC, MACADDRLEN);
+ (int)(*(meshHdrPtr+1))--;
+ txinsn.is_11s = RELAY_11S;
+ if (do_rc) {
+ *(unsigned int *)&(pfrinfo->pskb->cb[4]) = dst_pstat;
+ if (reorder_ctrl_check(priv, pstat, pfrinfo)) {
+ fire_data_frame(pfrinfo->pskb, priv->mesh_dev, &txinsn);
+ }
+ } else {
+ fire_data_frame(pfrinfo->pskb, priv->mesh_dev, &txinsn);
+ }
+ } else
+#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);
+ }
+ 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) {
+ *(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
+#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_RX_);
+ }
+ }
+ else {
+#ifdef TX_SCATTER
+ pfrinfo->pskb->list_num = 0;
+#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_RX_);
+ }
+ }
+ }
+ 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);
+ 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);
+
+#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;
+
+ // check power save state
+ if (get_stainfo(priv, GetAddr2Ptr(pframe)) != NULL)
+ 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 = get_stainfo(priv, sa);
+ unsigned char *pframe = get_pframe(pfrinfo);
+
+#if defined(SMP_SYNC)
+ unsigned long x;
+#endif
+#ifdef UNIVERSAL_REPEATER
+ if ((pstat == NULL) && IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
+ pstat = get_stainfo(GET_VXD_PRIV(priv), sa);
+ if (pstat)
+ priv = GET_VXD_PRIV(priv);
+ }
+#endif
+
+#ifdef MBSSID
+ if ((pstat == NULL)
+ && GET_ROOT(priv)->pmib->miscEntry.vap_enable
+ && (vap_idx >= 0)) {
+ pstat = get_stainfo(priv->pvap_priv[vap_idx], sa);
+ if (pstat)
+ priv = priv->pvap_priv[vap_idx];
+ }
+#endif
+
+ if (pstat && (pstat->state & WIFI_ASOC_STATE)) {
+#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)
+ {
+ GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, REMAP_AID(pstat), INCREASE);
+ }
+ 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) {
+ if (IS_BSSID(priv, GetAddr1Ptr(pframe)))
+ pwr_state(priv, pfrinfo);
+ }
+#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
+
+ // 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))))
+ {
+#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;
+ unsigned char *pframe = get_pframe(pfrinfo);
+ unsigned long flags;
+
+ SAVE_INT_AND_CLI(flags);
+ sa = pfrinfo->sa;
+ pstat = get_stainfo(priv, sa);
+ 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);
+}
+
+
+/*
+ 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 (frame_type == WIFI_BEACON || frame_type == WIFI_PROBERSP) {
+ pfrinfo->is_br_mgnt = 1;
+ goto put_in_que;
+ }
+
+ 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) {
+ priv = priv->pvap_priv[vap_idx];
+ goto put_in_que;
+ }
+ }
+#endif
+#ifdef UNIVERSAL_REPEATER
+ if (!memcmp(GET_VXD_PRIV(priv)->pmib->dot11Bss.bssid, bssid, MACADDRLEN)) {
+ if (!vxd_interface_ready) goto out;
+ priv = GET_VXD_PRIV(priv);
+ opmode = OPMODE;
+ }
+#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 // 802.11s Draft 1.0: page 11, Line 19~20
+ // wildcard bssid is also acceptable -- chris
+ || (GET_MIB(priv)->dot1180211sInfo.mesh_enable
+ && (!memcmp(bssid, "\x0\x0\x0\x0\x0\x0", 6) || !memcmp(bssid, "\xff\xff\xff\xff\xff\xff", 6))
+ && (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
+ rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
+#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
+
+ unsigned char *myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
+ if (IS_MCAST(da) || !memcmp(da, myhwaddr, MACADDRLEN))
+ reuse = 0;
+
+ if (!reuse) {
+ if (frtype == WIFI_MGT_TYPE)
+ {
+#ifdef RTL8190_DIRECT_RX
+ rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
+#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
+ rtl8192cd_rx_mgntframe(priv, NULL, pfrinfo);
+#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)
+{
+ 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 *myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
+ unsigned char *bssid = GetAddr2Ptr(pframe);
+#if defined(SMP_SYNC)
+ unsigned long x;
+#endif
+
+#ifdef CONFIG_RTK_MESH
+ struct stat_info *pstat = get_stainfo(priv, pfrinfo->sa);
+
+ if (((opmode & WIFI_AP_STATE) && (GET_MIB(priv)->dot1180211sInfo.mesh_enable))
+ && ((pstat == NULL) || isPossibleNeighbor(pstat)))
+ goto out;
+#endif // CONFIG_RTK_MESH
+
+#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)))
+ {
+ 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;
+
+ if (opmode & WIFI_AP_STATE)
+ {
+#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
+ // 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 ((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
+
+
+/*---------------------------------------------------------------
+ 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
+
+#ifdef __LINUX_2_6__
+ if(pfrinfo == NULL || pfrinfo->pskb==NULL || pfrinfo->pskb->data == NULL)
+ return 1;
+#endif
+
+ pframe = get_pframe(pfrinfo);
+
+#if 1 //Filen_Debug
+ if ((unsigned int)pframe & BIT0) {
+ panic_printk("Error: pframe(0x%x), pfrinfo->pskb(0x%x), pfrinfo(0x%x)\n", pframe, pfrinfo->pskb, 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 int)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;
+ }
+
+ 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 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;
+ }
+
+ myhwaddr = priv->pmib->dot11OperationEntry.hwaddr;
+
+#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
+ if (!memcmp(myhwaddr, sa, MACADDRLEN)
+#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 (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])) {
+ if (((pfrinfo->to_fr_ds == 0x00) || (pfrinfo->to_fr_ds == 0x02)) &&
+ !memcmp(priv->pvap_priv[i]->pmib->dot11StationConfigEntry.dot11Bssid, GetAddr1Ptr(pframe), MACADDRLEN)) {
+ vap_idx = i;
+ 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
+ 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);
+#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;
+}
+
+
+static 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
+
+#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(SMP_SYNC) || defined(__ECOS)
+ unsigned long x, flags;
+#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)) {
+ 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 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
+#endif
+ //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
+#endif
+#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
+
+#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
+)
+{
+ struct rtl8192cd_hw *phw=GET_HW(priv);
+ struct sk_buff *new_skb;
+#if defined(__LINUX_2_6__) && 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(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)) {
+#ifdef CONFIG_WLAN_HAL
+// cur_q->host_idx != cur_q->cur_host_idx) {
+ IS_HAL_CHIP(priv) ?
+ (((cur_q->host_idx + cur_q->rxbd_ok_cnt)%cur_q->total_rxbd_num) != cur_q->cur_host_idx) :
+#endif // CONFIG_WLAN_HAL
+ (phw->cur_rx_refill != phw->cur_rx) ) {
+
+
+ if (skb) {
+ new_skb = skb;
+ } else {
+ new_skb = dev_alloc_8190_skb(data, RX_BUF_LEN);
+ if (new_skb == NULL) {
+ DEBUG_ERR("out of skb struct!\n");
+#if defined(__LINUX_2_6__) && defined(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 0;
+ }
+ }
+#ifdef CONFIG_WLAN_HAL
+ if (IS_HAL_CHIP(priv)) {
+ 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++;
+ } else
+#endif // CONFIG_WLAN_HAL
+ {
+ 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_WLAN_HAL
+ if (IS_HAL_CHIP(priv)) {
+ //Filen: It is not necessary to clear HISR
+ } else
+#endif //CONFIG_WLAN_HAL
+ {
+#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
+ {
+ RTL_W32(HISR,(HIMR_RXFOVW | HIMR_RDU));
+ }
+ }
+
+
+#if defined(__LINUX_2_6__) && defined(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 1;
+ }
+ else {
+#if defined(__LINUX_2_6__) && defined(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 0;
+ }
+}
+#endif
+#endif // CONFIG_WLAN_HAL
+
+#ifdef DELAY_REFILL_RX_BUF
+#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(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(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 {
+ new_skb = dev_alloc_8190_skb(data, RX_BUF_LEN);
+ if (new_skb == NULL) {
+ DEBUG_ERR("out of skb struct!\n");
+#if defined(__LINUX_2_6__) && defined(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 0;
+ }
+ }
+
+ 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(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 1;
+ }
+ else {
+#if defined(__LINUX_2_6__) && defined(RX_TASKLET)
+ RESTORE_INT(x);
+ SMP_UNLOCK_SKB(x);
+#endif
+ return 0;
+ }
+}
+#endif
+
+#ifdef RX_BUFFER_GATHER
+void flush_rx_list(struct rtl8192cd_priv *priv)
+{
+ struct rx_frinfo *pfrinfo;
+ struct list_head *phead, *plist;
+ unsigned long flags;
+
+ SAVE_INT_AND_CLI(flags);
+
+ phead = &priv->pshare->gather_list;
+ if (!phead) {
+ RESTORE_INT(flags);
+ return;
+ }
+
+ plist = phead->next;
+ while (plist != phead) {
+ pfrinfo = list_entry(plist, struct rx_frinfo, rx_list);
+ if (pfrinfo->pskb)
+ rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
+ plist = plist->next;
+ }
+ 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;
+ unsigned long flags;
+ unsigned char *pframe;
+ u8 qosControl[4];
+
+ SAVE_INT_AND_CLI(flags);
+
+ phead = &priv->pshare->gather_list;
+ if (phead)
+ 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_);
+ 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
+#endif
+ {
+ 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 */
+
+#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
+)
+{
+ // 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
+ unsigned int rtl8192cd_ICV, privacy;
+ struct stat_info *pstat;
+#if (defined(__ECOS) || defined(__LINUX_2_6__)) && defined(RX_TASKLET)
+ unsigned long x;
+#if defined(SMP_SYNC)
+ unsigned long y;
+#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 /*defined(__ECOS) ||*/ (defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST))
+ unsigned long start_time = jiffies;
+ int n = 0;
+#endif
+ int update = 0;
+ u4Byte skb_shift_size = 0;
+ u4Byte skb_used_size;
+
+ 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 0 //def __ECOS
+ if ((n++ > 100) || ((jiffies - start_time) >= 1))
+ {
+ 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;
+#endif // DELAY_REFILL_RX_BUF
+
+#if defined(RX_BUFFER_GATHER)
+ pfrinfo_update = 0;
+#endif
+
+#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); //sky
+ }
+#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) ) {
+ pfrinfo = NULL;
+ 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 (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;
+ 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);
+ 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;
+
+ 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 = 0x80 + (rx_desc_status.RX_RATE - 12);
+ } else{
+ pfrinfo->rx_rate = 0x90 + (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 = 0x80|(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)
+ // 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
+ 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) */
+ // 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
+
+ /*-----------------------------------------------------
+ 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) {
+ rtl8192cd_ICV = 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) {
+ rtl8192cd_ICV++;
+ } else {
+ 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_)
+ rtl8192cd_ICV++;
+ }
+
+ if (rtl8192cd_ICV) {
+ 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
+ {
+ 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(CONFIG_RTL8190_PRIV_SKB) && defined(DELAY_REFILL_RX_BUF)
+#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;
+ }
+
+ 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) || (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
+ skb_reserve(pskb, 128);
+#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) */
+ {
+#if defined(RX_BUFFER_GATHER)
+ if (pfrinfo != NULL) {
+ pfrinfo->gather_flag = 0;
+ }
+#endif
+
+#if defined(CONFIG_NET_PCI) && !defined(USE_RTL8186_SDK)
+ rtl_cache_sync_wback(priv, bus_to_virt(phw->rx_infoL[cur_q->cur_host_idx].paddr),
+ RX_BUF_LEN - sizeof(struct rx_frinfo) - GetOffsetStartToRXDESC(priv, pskb),
+ PCI_DMA_FROMDEVICE);
+#else
+ rtl_cache_sync_wback(priv, phw->rx_infoL[cur_q->cur_host_idx].paddr,
+ RX_BUF_LEN - sizeof(struct rx_frinfo) - GetOffsetStartToRXDESC(priv, pskb),
+ PCI_DMA_FROMDEVICE);
+#endif
+
+ }
+
+rx_done:
+
+ cur_q->cur_host_idx = (cur_q->cur_host_idx+1) % cur_q->total_rxbd_num;
+
+ update = 0;
+ if(cur_q->cur_host_idx == cur_q->hw_idx) {
+ GET_HAL_INTERFACE(priv)->UpdateRXBDHWIdxHandler(priv, q_num);
+ update = 1;
+ }
+
+#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, privacy;
+ struct stat_info *pstat;
+#if (defined(__ECOS) ||defined(__LINUX_2_6__)) && defined(RX_TASKLET)
+ unsigned long x;
+#if defined(SMP_SYNC)
+ unsigned long y;
+#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 CONFIG_WLAN_HAL
+ if(IS_HAL_CHIP(priv)) {
+ rtl88XX_rx_isr(priv);
+ return;
+ }
+#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 int)prxdesc, sizeof(struct rx_desc), PCI_DMA_FROMDEVICE);
+#else
+#if defined(__MIPSEB__)
+ prxdesc = (struct rx_desc *)((unsigned int)(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
+#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, (RX_BUF_LEN - sizeof(struct rx_frinfo)), PCI_DMA_FROMDEVICE); //sky
+ }
+ #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
+ {
+ //printk("pfrinfo->pktlen=%d, goto rx_reuse\n",pfrinfo->pktlen);
+ 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_8192E) || (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 = 0x80 +(rxdesc_rate - 12);
+ } else{
+ pfrinfo->rx_rate = 0x90 +(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 = 0x80|((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) */
+ // 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
+
+ /*-----------------------------------------------------
+ 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 = 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) {
+ rtl8192cd_ICV++;
+ } else {
+ 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_)
+ rtl8192cd_ICV++;
+ }
+
+ 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
+ {
+ 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(CONFIG_RTL8190_PRIV_SKB) && defined(DELAY_REFILL_RX_BUF)
+#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;
+ }
+
+ 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, 128);
+#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);
+ pdesc->Dword6 = set_desc(phw->rx_infoL[tail].paddr);
+ rtl_cache_sync_wback(priv, (unsigned int)bus_to_virt(phw->rx_infoL[tail].paddr), RX_BUF_LEN - sizeof(struct rx_frinfo)-64, PCI_DMA_FROMDEVICE);
+ 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
+
+// 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;
+
+ phead = &pstat->frag_list;
+
+ SAVE_INT_AND_CLI(flags);
+
+ // 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;
+ }
+ else
+ {
+ 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...
+ if ((pfirstfrinfo->pktlen += (pfrinfo->pktlen - offset - icv - mic)) >=
+ (RX_BUF_LEN - offset - icv - mic - 200))
+ {
+ 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;
+ pfrinfo = list_entry(plist, struct rx_frinfo, mpdu_list);
+ pskb = get_pskb(pfrinfo);
+ list_del_init(plist);
+ if (pfirstfrinfo == NULL)
+ priv->ext_stats.rx_data_drops++;
+ rtl_kfree_skb(priv, pskb, _SKB_RX_IRQ_);
+ }
+ INIT_LIST_HEAD(phead);
+
+ list_del_init(&pstat->defrag_list);
+ pstat->frag_count = 0;
+
+ RESTORE_INT(flags);
+
+ 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;
+
+ 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
+ pstat = get_stainfo(priv, sa);
+ }
+ }
+#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_VXD_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 (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
+
+ // check whether WEP bit is set in mac header and sw encryption
+ if (GetPrivacy(pframe) && UseSwCrypto(priv, pstat, IS_MCAST(GetAddr1Ptr(pframe))))
+ {
+#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);
+ 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;
+ }
+
+ SAVE_INT_AND_CLI(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++;
+
+ RESTORE_INT(flags);
+ return (struct rx_frinfo *)NULL;
+ }
+ else
+ {
+ if(GetFragNum(pframe))
+ {
+ SAVE_INT_AND_CLI(flags);
+ list_add_tail(&pfrinfo->mpdu_list, &pstat->frag_list);
+ RESTORE_INT(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 (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);
+#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...
+ 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.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);
+}
+
+
+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 int)(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 int)(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 int)(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 int)(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;
+ }
+ }
+}
+
+
+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);
+ pstat = get_stainfo(priv, get_sa(pframe));
+
+ if ((!(OPMODE & WIFI_AP_STATE)) || (pstat == NULL)) {
+ rtl_kfree_skb(priv, pfrinfo->pskb, _SKB_RX_);
+ return;
+ }
+ 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 (CONFIG_RTL_IGMP_SNOOPING)
+ /*added by qinjunjie,to avoid igmpv1/v2 report suppress*/
+int rtl8192cd_isIgmpV1V2Report(unsigned char *macFrame)
+{
+ unsigned char *ptr;
+ struct iphdr *iph=NULL;
+ 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);
+ iph=(struct iphdr *)ptr;
+
+ if(iph->protocol!=0x02)
+ {
+ return FALSE;
+ }
+
+ payloadLen=(iph->tot_len-((iph->ihl&0x0f)<<2));
+ if(payloadLen>8)
+ {
+ return FALSE;
+ }
+
+ ptr=ptr+(((unsigned int)iph->ihl)<<2);
+ 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;
+ struct ipv6hdr* ipv6h;
+ 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);
+
+ ipv6h= (struct ipv6hdr *) ptr;
+ if(ipv6h->version!=6)
+ {
+ return FALSE;
+ }
+
+ startPtr= (unsigned char *)ptr;
+ lastPtr=startPtr+sizeof(struct ipv6hdr)+(ipv6h->payload_len);
+ nextHeader= ipv6h ->nexthdr;
+ ptr=startPtr+sizeof(struct ipv6hdr);
+
+ 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;
+
+ while(ptr<(startPtr+extensionHdrLen+sizeof(struct ipv6hdr)))
+ {
+ 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
+
+
+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;
+#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);
+#ifdef USE_OUT_SRC
+#ifdef _OUTSRC_COEXIST
+ if(IS_OUTSRC_CHIP(priv))
+#endif
+ priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
+#endif
+ 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
+ pstat = get_stainfo(priv, pfrinfo->sa);
+ }
+
+#if defined(CONFIG_RTL_WAPI_SUPPORT)
+ if (wapiHandleRecvPacket(pfrinfo, pstat)==SUCCESS)
+ {
+ return SUCCESS;
+ }
+
+#endif
+
+ // 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);
+#ifdef USE_OUT_SRC
+#ifdef _OUTSRC_COEXIST
+ if(IS_OUTSRC_CHIP(priv))
+#endif
+ priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
+#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)
+ {
+ GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, REMAP_AID(pstat), INCREASE);
+ }
+ 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 1
+ {
+ 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){
+#ifdef STA_EXT
+ if (pstat->aid > FW_NUM_STAT)
+ priv->pshare->marvellMapBitExt |= BIT(pstat->aid - FW_NUM_STAT - 1);
+ else
+#endif
+#ifdef CONFIG_RTL_88E_SUPPORT
+ if ((GET_CHIP_VER(priv) == VERSION_8188E) && (pstat->aid > 32))
+ priv->pshare->marvellMapBit_88e_hw_ext |= BIT(pstat->aid - 32 - 1);
+ else
+#endif
+ priv->pshare->marvellMapBit |= BIT(pstat->aid - 1);
+ }
+ }
+
+#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)){
+ 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);
+ }
+ }
+#endif
+
+#if 0
+//#if !defined(USE_OUT_SRC) || defined(_OUTSRC_COEXIST)
+#ifdef _OUTSRC_COEXIST
+ if(!IS_OUTSRC_CHIP(priv))
+#endif
+ {
+ if (!pstat->is_realtek_sta && !pstat->is_ralink_sta && !pstat->is_marvell_sta) {
+ pstat->is_marvell_sta = 1;
+ if (priv->pshare->is_40m_bw){
+#ifdef STA_EXT
+ if (pstat->aid > FW_NUM_STAT)
+ priv->pshare->marvellMapBitExt |= BIT(pstat->aid - FW_NUM_STAT - 1);
+ else
+#endif
+#ifdef CONFIG_RTL_88E_SUPPORT
+ if ((GET_CHIP_VER(priv) == VERSION_8188E) && (pstat->aid > 32))
+ priv->pshare->marvellMapBit_88e_hw_ext |= BIT(pstat->aid - 32 - 1);
+ else
+#endif
+ priv->pshare->marvellMapBit |= BIT(pstat->aid - 1);
+ }
+ }
+
+#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 Nohting
+ } else
+#endif
+ if (priv->pshare->is_40m_bw && pstat->is_marvell_sta && (priv->pshare->Reg_RRSR_2 == 0) && (priv->pshare->Reg_81b == 0)){
+ 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);
+ }
+ }
+#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 SUPPORT_TX_MCAST2UNI
+ if(IP_MCAST_MAC(pskb->data) && IS_IGMP_PROTO(pskb->data))
+ {
+ dontBcast2otherSta=1;
+ }
+#endif
+#if defined (__LINUX_2_6__) && 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 SUPPORT_TX_MCAST2UNI
+ if(IP_MCAST_MAC(pskb->data) && IS_IGMP_PROTO(pskb->data))
+ {
+ dontBcast2otherSta=1;
+ }
+#endif
+
+#ifdef __KERNEL__
+#ifndef CONFIG_RTL8196C_KLD
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
+ // if we are STP aware, don't broadcast received BPDU
+ if (!(priv->dev->br_port &&
+ priv->dev->br_port->br->stp_enabled &&
+ !memcmp(pskb->data, "\x01\x80\xc2\x00\x00\x00", 6)))
+#endif
+#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){
+ rtl_kfree_skb(priv, pnewskb, _SKB_TX_);
+ }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");
+ rtl_kfree_skb(priv, pnewskb, _SKB_TX_);
+ }
+ 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 (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;
+ }
+
+ dst_pstat = get_stainfo(priv, da);
+
+#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
+ ) {
+ if (
+#ifdef LINUX_2_6_22_
+ (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) != __constant_htons(0x888e)) &&
+ (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) != __constant_htons(0x86dd)) &&
+#else
+ (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) != __constant_htons(0x888e)) &&
+ (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) != __constant_htons(0x86dd)) &&
+#endif
+#ifdef CONFIG_RTL8196C_KLD
+ 1
+#else
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
+ priv->dev->br_port &&
+#endif
+#ifdef __LINUX_2_6__
+ #if defined(CONFIG_RTL_EAP_RELAY) || defined(CONFIG_RTK_INBAND_HOST_HACK)
+ memcmp(da, inband_Hostmac, MACADDRLEN)
+ #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
+ memcmp(da, priv->dev->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;
+ }
+#ifndef NOT_RTK_BSP
+ pskb->__unused = 0xe5;
+#endif
+
+#ifdef CONFIG_RTL8186_KB
+ if (priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm == 0)
+ {
+ /* hotel style guest access */
+ if (!rtl8192cd_guestmac_valid(priv, pskb->mac.raw+MACADDRLEN))
+ {
+#ifndef NOT_RTK_BSP
+ 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]);
+ }
+#ifndef NOT_RTK_BSP
+ 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);
+
+#ifdef EAPOLSTART_BY_QUEUE
+#ifdef LINUX_2_6_22_
+ if (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) == __constant_htons(0x888e))
+#else
+ if (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) == __constant_htons(0x888e))
+#endif
+ {
+ 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;
+#ifdef LINUX_2_6_22_
+ memcpy(&Eapol_Start.MACAddr, pskb->mac_header + MACADDRLEN, WLAN_ETHHDR_LEN);
+#else
+ memcpy(&Eapol_Start.MACAddr, pskb->mac.raw + MACADDRLEN, WLAN_ETHHDR_LEN);
+#endif
+ DOT11_EnQueue((unsigned long)priv, priv->pevent_queue, (unsigned char*)&Eapol_Start, sizeof(DOT11_EAPOL_START));
+#ifdef LINUX_2_6_22_
+ event_indicate(priv, pskb->mac_header + MACADDRLEN, 4);
+#else
+ event_indicate(priv, pskb->mac.raw + MACADDRLEN, 4);
+#endif
+ return FAIL; // let dsr free this skb
+ }
+ }
+#endif
+#endif /* __ECOS */
+
+#if (defined(EAP_BY_QUEUE) || defined(INCLUDE_WPA_PSK)) && (!defined(WIFI_HAPD) || defined(HAPD_DRV_PSK_WPS))
+#ifdef WDS
+#ifdef LINUX_2_6_22_
+ if ((pfrinfo->to_fr_ds != 3) && (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) == __constant_htons(0x888e)))
+#else
+#ifdef __ECOS
+ if ((pfrinfo->to_fr_ds != 3) && (*(unsigned short *)(pskb->data + MACADDRLEN*2) == __constant_htons(0x888e)))
+#else
+ if ((pfrinfo->to_fr_ds != 3) && (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) == __constant_htons(0x888e)))
+#endif
+#endif
+#else
+#ifdef LINUX_2_6_22_
+ if (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) == __constant_htons(0x888e))
+#else
+#ifdef __ECOS
+ if (*(unsigned short *)(pskb->data + MACADDRLEN*2) == __constant_htons(0x888e))
+#else
+ if (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) == __constant_htons(0x888e))
+#endif
+#endif
+#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;
+
+ pkt_len = WLAN_ETHHDR_LEN + pskb->len;
+ 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);
+ pskb->len -= WLAN_ETHHDR_LEN;
+#else
+#ifdef LINUX_2_6_22_
+ memcpy(&(priv->Eap_packet->packet[0]), pskb->mac_header, WLAN_ETHHDR_LEN);
+#else
+ memcpy(&(priv->Eap_packet->packet[0]), pskb->mac.raw, WLAN_ETHHDR_LEN);
+#endif
+ 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
+ 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
+
+#ifndef WIFI_HAPD
+ return FAIL; // let dsr free this skb
+#endif
+ }
+ }
+#endif
+
+#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
+ if (dst_pstat->rx_payload_offset[i])
+ dst_pstat->rx_payload_offset[i] = 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);
+ }
+ 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) {
+ *(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
+//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_RX_);
+ }
+ } 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_RX_);
+ }
+ }
+ }
+ }
+ }
+#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);
+#ifdef USE_OUT_SRC
+#ifdef _OUTSRC_COEXIST
+ if(IS_OUTSRC_CHIP(priv))
+#endif
+ priv->pshare->NumRxBytesUnicast += pfrinfo->pktlen;
+#endif
+ 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_&&wapiHandleRecvPacket(pfrinfo, pstat)==SUCCESS)
+ {
+ return SUCCESS;
+ }
+ #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
+
+#ifdef __KERNEL__
+ pskb->protocol = eth_type_trans(pskb, priv->dev);
+#endif
+
+#if (defined(EAP_BY_QUEUE) || defined(INCLUDE_WPA_PSK)) && (!defined(WIFI_HAPD) || defined(HAPD_DRV_PSK_WPS))
+#ifdef LINUX_2_6_22_
+ if (*(unsigned short *)(pskb->mac_header + MACADDRLEN*2) == __constant_htons(0x888e))
+#else
+#ifdef __ECOS
+ if (*(unsigned short *)(pskb->data + MACADDRLEN*2) == __constant_htons(0x888e))
+#else
+ if (*(unsigned short *)(pskb->mac.raw + MACADDRLEN*2) == __constant_htons(0x888e))
+#endif
+#endif
+ {
+ unsigned short pkt_len;
+
+ pkt_len = WLAN_ETHHDR_LEN + pskb->len;
+ 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);
+ pskb->len -= WLAN_ETHHDR_LEN;
+#else
+#ifdef LINUX_2_6_22_
+ memcpy(&(priv->Eap_packet->packet[0]), pskb->mac_header, WLAN_ETHHDR_LEN);
+#else
+ memcpy(&(priv->Eap_packet->packet[0]), pskb->mac.raw, WLAN_ETHHDR_LEN);
+#endif
+ 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
+ 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
+
+#ifndef WIFI_HAPD
+ return FAIL; // let dsr free this skb
+#endif
+ }
+#endif
+
+#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
+*/
+#ifndef CONFIG_RTK_MESH
+static
+#endif
+ 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);
+ 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(get_pframe(pfrinfo)) == (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) {
+ 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(get_pframe(pfrinfo)) == (WIFI_QOS_DATA)) && (GetPwrMgt(get_pframe(pfrinfo)))))
+#endif
+ ) {
+ if (rx_shortcut(priv, pfrinfo) >= 0) {
+#if defined(__ECOS) && defined(_DEBUG_RTL8192CD_)
+ priv->ext_stats.rx_cnt_sc++;
+#endif
+ goto out;
+ }
+ }
+#endif
+
+#if 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;
+}
+
+#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);
+}
+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_);
+ }
+}
+
+#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;
+ unsigned long flags;
+ 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);
+
+#ifdef CONFIG_WLAN_HAL
+ GET_HAL_INTERFACE(priv)->DisableRxRelatedInterruptHandler(priv);
+#else
+ {
+ 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 //CONFIG_WLAN_HAL
+#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_WLAN_HAL
+ GET_HAL_INTERFACE(priv)->EnableRxRelatedInterruptHandler(priv);
+#else
+ {
+ mask = RTL_R32(HIMR);
+ RTL_W32(HIMR, mask | mask_rx);
+ }
+#endif
+#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;
+ unsigned long flags;
+ unsigned long mask, mask_rx, mask_ext, mask_ext_rx;
+#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;
+ }
+#endif //CONFIG_WLAN_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_rx);
+
+ mask_ext = RTL_R32(REG_92E_HIMRE);
+ mask_ext_rx = mask_ext & HIMRE_92E_RXFOVW;
+ RTL_W32(REG_92E_HIMRE, ~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))
+
+
+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
+ unsigned long flags;
+
+ 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;
+
+#ifdef CONFIG_WLAN_HAL
+ if ((GetFrameSubType(pframe)) == WIFI_PSPOLL)
+ {
+ if(IS_HAL_CHIP(priv))
+ {
+ if(REMAP_AID(pstat) < 128)
+ {
+ GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat->aid, DECREASE);
+ GET_HAL_INTERFACE(priv)->SetMACIDSleepHandler(priv, 0 , REMAP_AID(pstat));
+
+ delay_us(10); //delay 10us wait drop packet
+ GET_HAL_INTERFACE(priv)->UpdateHalMSRRPTHandler(priv, pstat->aid, INCREASE);
+ DEBUG_WARN("%s %d OnPsPoll, set MACID 0 AID = %x \n",__FUNCTION__,__LINE__,REMAP_AID(pstat));
+ }
+ else
+ {
+ DEBUG_WARN(" MACID sleep only support 128 STA \n");
+ }
+ }
+ }
+#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_);
+ }
+
+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;
+ unsigned long flags;
+
+ 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
+
+ }
+ }
+
+ 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;
+
+ 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
+ if (dst_pstat->rx_payload_offset[i])
+ dst_pstat->rx_payload_offset[i] = 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_RX_);
+ }
+ }
+ }
+ }
+#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_);
+ }
+#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++) {
+ if (pstat->rx_payload_offset[i])
+ pstat->rx_payload_offset[i] = 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_);
+}
+