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