/* * 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 #include #include #include #include #include #elif defined(__ECOS) #include #include #include #include #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 #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 #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; iadc_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; itrsw_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; irxevm_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 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)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; irx_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; irx_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; jtpcache[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; ipvap_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; ipvap_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; ipvap_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; ipvap_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; iguestMac[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(ptrpktlen); // 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; irx_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; ipvap_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; ipvap_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; idata[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; irx_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; irx_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_); }