/**************************************************************************** * Ralink Tech Inc. * 4F, No. 2 Technology 5th Rd. * Science-based Industrial Park * Hsin-chu, Taiwan, R.O.C. * (c) Copyright 2002, Ralink Technology, Inc. * * All rights reserved. Ralink's source code is an unpublished work and the * use of a copyright notice does not imply otherwise. This source code * contains confidential trade secret material of Ralink Tech. Any attemp * or participation in deciphering, decoding, reverse engineering or in any * way altering the source code is stricitly prohibited, unless the prior * written consent of Ralink Technology, Inc. is obtained. **************************************************************************** Module Name: cmm_data.c Abstract: Revision History: Who When What --------- ---------- ---------------------------------------------- */ #include "rt_config.h" UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; UCHAR EAPOL[] = {0x88, 0x8e}; UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ UCHAR IPX[] = {0x81, 0x37}; UCHAR APPLE_TALK[] = {0x80, 0xf3}; // UserPriority To AccessCategory mapping UCHAR WMM_UP2AC_MAP[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; struct WCID_TABLE{ DL_LIST list; UCHAR wcid; }; static struct WCID_TABLE wcid_table[MAX_LEN_OF_TR_TABLE]; #ifdef DBG_DIAGNOSE VOID dbg_diag_deque_log(RTMP_ADAPTER *pAd) { struct dbg_diag_info *diag_info; UCHAR QueIdx = 0; diag_info = &pAd->DiagStruct.diag_info[pAd->DiagStruct.ArrayCurIdx]; #ifdef RTMP_MAC_PCI #ifdef DBG_TX_RING_DEPTH if ((pAd->DiagStruct.diag_cond & DIAG_COND_TX_RING_DEPTH) != DIAG_COND_TX_RING_DEPTH) { for (QueIdx = 0; QueIdx < 4 /* 4 */; QueIdx++) { UINT free_cnt, desc_num; UINT32 dma_id, cpu_id, hw_cnt; free_cnt = GET_TXRING_FREENO(pAd, QueIdx); #if 0 desc_num = (TX_RING_SIZE - free_cnt); /* Number of occupied hw desc.*/ desc_num = ((desc_num <=15) ? desc_num : 15); diag_info->TxDescCnt[desc_num]++; #else RTMP_IO_READ32(pAd, pAd->TxRing[QueIdx].hw_didx_addr, &dma_id); RTMP_IO_READ32(pAd, pAd->TxRing[QueIdx].hw_cidx_addr, &cpu_id); if (dma_id > cpu_id) hw_cnt = TX_RING_SIZE - dma_id + cpu_id; else if (cpu_id > dma_id) hw_cnt = cpu_id - dma_id; else hw_cnt = ((free_cnt > 0) ? 0 : TX_RING_SIZE); hw_cnt = ((hw_cnt <=15) ? hw_cnt : 15); diag_info->TxDescCnt[QueIdx][hw_cnt]++; #endif } } #endif /* DBG_TX_RING_DEPTH */ #ifdef MT_MAC #ifdef DBG_PSE_DEPTH if ((pAd->DiagStruct.diag_cond & DIAG_COND_PSE_DEPTH) != DIAG_COND_PSE_DEPTH) { UINT32 mac_val; RTMP_IO_READ32(pAd, 0x8148, &mac_val); mac_val = ((mac_val & 0xfff) / 13); if (mac_val > 48) mac_val = 49; diag_info->pse_pg_cnt[mac_val]++; } #endif /* DBG_PSE_DEPTH */ #endif /* MT_MAC */ #endif /* RTMP_MAC_PCI */ #ifdef DBG_TXQ_DEPTH if ((pAd->DiagStruct.diag_cond & DIAG_COND_TXQ_DEPTH) != DIAG_COND_TXQ_DEPTH) { if ((pAd->DiagStruct.wcid > 0) && (pAd->DiagStruct.wcid < MAX_LEN_OF_TR_TABLE)) { STA_TR_ENTRY *tr_entry = &pAd->MacTab.tr_entry[pAd->DiagStruct.wcid]; UCHAR swq_cnt; for (QueIdx = 0; QueIdx < 4; QueIdx++) { if (tr_entry->tx_queue[QueIdx].Number <= 7) swq_cnt = tr_entry->tx_queue[QueIdx].Number; else swq_cnt = 8; diag_info->TxSWQueCnt[QueIdx][swq_cnt]++; } } } #endif /* DBG_TXQ_DEPTH */ } #endif /* DBG_DIAGNOSE */ /*Nobody uses it currently*/ #if 0 static VOID dump_txblk(TX_BLK *pTxBlk) { NDIS_PACKET *pPacket; int i, frameNum; PQUEUE_ENTRY pQEntry; DBGPRINT(RT_DEBUG_TRACE,("Dump TX_BLK Structure:\n")); DBGPRINT(RT_DEBUG_TRACE,("\tTxFrameType=%d!\n", pTxBlk->TxFrameType)); DBGPRINT(RT_DEBUG_TRACE,("\tTotalFrameLen=%d\n", pTxBlk->TotalFrameLen)); DBGPRINT(RT_DEBUG_TRACE,("\tTotalFrameNum=%d!\n", pTxBlk->TxPacketList.Number)); DBGPRINT(RT_DEBUG_TRACE,("\tTotalFragNum=%d!\n", pTxBlk->TotalFragNum)); DBGPRINT(RT_DEBUG_TRACE,("\tpPacketList=\n")); frameNum = pTxBlk->TxPacketList.Number; for(i=0; i < frameNum; i++) { int j; UCHAR *pBuf; pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); if (pPacket) { pBuf = GET_OS_PKT_DATAPTR(pPacket); DBGPRINT(RT_DEBUG_TRACE,("\t\t[%d]:ptr=0x%x, Len=%d!\n", i, (UINT32)(GET_OS_PKT_DATAPTR(pPacket)), GET_OS_PKT_LEN(pPacket))); DBGPRINT(RT_DEBUG_TRACE,("\t\t")); for (j =0 ; j < GET_OS_PKT_LEN(pPacket); j++) { DBGPRINT(RT_DEBUG_TRACE,("%02x ", (pBuf[j] & 0xff))); if (j == 16) break; } InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); } } DBGPRINT(RT_DEBUG_TRACE,("\tWcid=%d!\n", pTxBlk->Wcid)); DBGPRINT(RT_DEBUG_TRACE,("\twdev_idx=%d!\n", pTxBlk->wdev_idx)); DBGPRINT(RT_DEBUG_TRACE,("----EndOfDump\n")); } #endif VOID dump_rxblk(RTMP_ADAPTER *pAd, RX_BLK *pRxBlk) { DBGPRINT(RT_DEBUG_TRACE,("Dump RX_BLK Structure:\n")); DBGPRINT(RT_DEBUG_TRACE,("\tHW rx info:\n")); hex_dump("RawData", &pRxBlk->hw_rx_info[0], RXD_SIZE); DBGPRINT(RT_DEBUG_TRACE,("\tData Pointer info:\n")); #if defined(RTMP_MAC) || defined(RLT_MAC) if (pAd->chipCap.hif_type == HIF_RTMP || pAd->chipCap.hif_type == HIF_RLT) { DBGPRINT(RT_DEBUG_TRACE,("\t\tpRxInfo=0x%p\n", pRxBlk->pRxInfo)); dump_rxinfo(pAd, pRxBlk->pRxInfo); #ifdef RLT_MAC if (pAd->chipCap.hif_type == HIF_RLT) { DBGPRINT(RT_DEBUG_TRACE,("\t\tpRxFceInfo=0x%p\n", pRxBlk->pRxFceInfo)); dumpRxFCEInfo(pAd, pRxBlk->pRxFceInfo); } #endif /* RLT_MAC */ DBGPRINT(RT_DEBUG_TRACE,("\t\tpRxWI=0x%p\n", pRxBlk->pRxWI)); dump_rmac_info(pAd, (UCHAR *)pRxBlk->pRxWI); } #endif /* defined(RTMP_MAC) || defined(RLT_MAC) */ #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { DBGPRINT(RT_DEBUG_TRACE,("\t\trmac_info=0x%p\n", pRxBlk->rmac_info)); dump_rmac_info(pAd, pRxBlk->rmac_info); } #endif /* MT_MAC */ DBGPRINT(RT_DEBUG_TRACE,("\t\tpRxPacket=0x%p, MPDUtotalByteCnt=%d\n", pRxBlk->pRxPacket, pRxBlk->MPDUtotalByteCnt)); DBGPRINT(RT_DEBUG_TRACE,("\t\tpHeader=0x%p\n", pRxBlk->pHeader)); DBGPRINT(RT_DEBUG_TRACE,("\t\tpData=0x%p\n", pRxBlk->pData)); DBGPRINT(RT_DEBUG_TRACE,("\t\tDataSize=%d\n", pRxBlk->DataSize)); DBGPRINT(RT_DEBUG_TRACE,("\t\tFlags=0x%x\n", pRxBlk->Flags)); DBGPRINT(RT_DEBUG_TRACE,("\t\tUserPriority=%d\n", pRxBlk->UserPriority)); DBGPRINT(RT_DEBUG_TRACE,("\t\tOpMode=%d\n", pRxBlk->OpMode)); DBGPRINT(RT_DEBUG_TRACE,("\tMirror Info from RMAC Info:\n")); DBGPRINT(RT_DEBUG_TRACE,("\t\tWCID=%d\n", pRxBlk->wcid)); DBGPRINT(RT_DEBUG_TRACE,("\t\tTID=%d\n", pRxBlk->TID)); DBGPRINT(RT_DEBUG_TRACE,("\t\tKey_idx=%d\n", pRxBlk->key_idx)); DBGPRINT(RT_DEBUG_TRACE,("\t\tBSS_IDX=%d\n", pRxBlk->bss_idx)); #if defined(RLT_MAC) || defined(RTMP_MAC) if (pAd->chipCap.hif_type == HIF_RTMP || pAd->chipCap.hif_type == HIF_RLT) { DBGPRINT(RT_DEBUG_TRACE,("\t\tPhyMode=%d(%s)\n", pRxBlk->rx_rate.field.MODE, get_phymode_str(pRxBlk->rx_rate.field.MODE))); DBGPRINT(RT_DEBUG_TRACE,("\t\tMCS=%d\n", pRxBlk->rx_rate.field.MCS)); DBGPRINT(RT_DEBUG_TRACE,("\t\tBW=%d\n", pRxBlk->rx_rate.field.BW)); DBGPRINT(RT_DEBUG_TRACE,("\t\tSGI=%d\n", pRxBlk->rx_rate.field.ShortGI)); DBGPRINT(RT_DEBUG_TRACE,("\t\tSTBC=%d\n", pRxBlk->rx_rate.field.STBC)); #ifdef RLT_MAC if (pAd->chipCap.hif_type == HIF_RLT) DBGPRINT(RT_DEBUG_TRACE,("\t\tLDPC=%d\n", pRxBlk->rx_rate.field.ldpc)); #endif /* RLT_MAC */ DBGPRINT(RT_DEBUG_TRACE,("\t\tRSSI=%d:%d:%d\n", pRxBlk->rx_signal.raw_rssi[0], pRxBlk->rx_signal.raw_rssi[1], pRxBlk->rx_signal.raw_rssi[2])); DBGPRINT(RT_DEBUG_TRACE,("\t\tSNR=%d:%d:%d\n", pRxBlk->rx_signal.raw_snr[0], pRxBlk->rx_signal.raw_snr[1], pRxBlk->rx_signal.raw_snr[2])); DBGPRINT(RT_DEBUG_TRACE,("\t\tFreqOffset=%d\n", pRxBlk->rx_signal.freq_offset)); } #endif /* defined(RLT_MAC) || defined(RTMP_MAC) */ //hex_dump("Dump RxPacket in dump_rxblk", (UCHAR *)pRxBlk->pHeader, pRxBlk->MPDUtotalByteCnt > 512 ? 512 : pRxBlk->MPDUtotalByteCnt); } #ifdef MT_MAC /* 1'b0: the related GROUP is not present 1'b1: the related GROUP is present bit[0]: indicates GROUP1 (DW8~DW11) bit[1]: indicates GROUP2 (DW12~DW13) bit[2]: indicates GROUP3 (DW14~DW19) bit[3]: indicates GROUP4 (DW4~DW7) */ //#define RMAC_INFO_GRP_1_SIZE 16 //#define RMAC_INFO_GRP_2_SIZE 8 //#define RMAC_INFO_GRP_3_SIZE 24 //#define RMAC_INFO_GRP_4_SIZE 16 static INT32 RMACInfoGrpToLen[]={ /* 0: base only */ RMAC_INFO_BASE_SIZE, /* 1: [bit 0] base + group 1 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE, /* 2: [bit 1] base + group 2 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_2_SIZE, /* 3: [bit 0 + bit 1] base + group 1 + group 2 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_2_SIZE, /* 4: [bit 2] base + group 3 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_3_SIZE, /* 5: [bit 0 + bit 2] base + group 1 + group 3 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_3_SIZE, /* 6: [bit 1 + bit 2] base + group 2 + group 3 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_3_SIZE, /* 7: [bit 0 + bit 1 + bit 2] base + group 1 + group 2 + group 3 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_3_SIZE, /* 8: [bit 3 ] base + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_4_SIZE, /* 9: [bit 0 + bit 3 ] base + group 1 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_4_SIZE, /* 10: [bit 1 + bit 3 ] base + group 2 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_4_SIZE, /* 11: [bit 0 + bit 1 + bit 3 ] base + group 1 + group 2 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_4_SIZE, /* 12: [bit 2 + bit 3 ] base + group 3 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_3_SIZE + RMAC_INFO_GRP_4_SIZE, /* 13: [bit 0 + bit 2 + bit 3 ] base + group 1 + group 3 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_3_SIZE + RMAC_INFO_GRP_4_SIZE, /* 14: [bit 1 + bit 2 + bit 3 ] base + group 2 + group 3 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_3_SIZE + RMAC_INFO_GRP_4_SIZE, /* 15: [bit 0 + bit 1 + bit 2 + bit 3 ] base + group 1 + group 2 + group 3 + group 4 */ RMAC_INFO_BASE_SIZE + RMAC_INFO_GRP_1_SIZE + RMAC_INFO_GRP_2_SIZE + RMAC_INFO_GRP_3_SIZE + RMAC_INFO_GRP_4_SIZE, }; #ifdef MT_MAC VOID ParseRxVPacket(RTMP_ADAPTER *pAd, UINT32 Type, RX_BLK *RxBlk, UCHAR *Data) { //RXV_DWORD0 *DW0 = NULL; RXV_DWORD1 *DW1 = NULL; RX_VECTOR1_1ST_CYCLE *RXV1_1ST_CYCLE = NULL; //RX_VECTOR1_2ND_CYCLE *RXV1_2ND_CYCLE = NULL; #ifdef CONFIG_QA RX_VECTOR1_3TH_CYCLE *RXV1_3TH_CYCLE = NULL; #endif /* CONFIG_QA */ RX_VECTOR1_4TH_CYCLE *RXV1_4TH_CYCLE = NULL; RX_VECTOR1_5TH_CYCLE *RXV1_5TH_CYCLE = NULL; RX_VECTOR1_6TH_CYCLE *RXV1_6TH_CYCLE = NULL; RX_VECTOR2_1ST_CYCLE *RXV2_1ST_CYCLE = NULL; RX_VECTOR2_2ND_CYCLE *RXV2_2ND_CYCLE = NULL; RX_VECTOR2_3TH_CYCLE *RXV2_3TH_CYCLE = NULL; if (Type == RMAC_RX_PKT_TYPE_RX_NORMAL) { RXV1_1ST_CYCLE = (RX_VECTOR1_1ST_CYCLE *)Data; //RXV1_2ND_CYCLE = (RX_VECTOR1_2ND_CYCLE *)(Data + 4); #ifdef CONFIG_QA RXV1_3TH_CYCLE = (RX_VECTOR1_3TH_CYCLE *)(Data + 8); #endif /* CONFIG_QA */ RXV1_4TH_CYCLE = (RX_VECTOR1_4TH_CYCLE *)(Data + 12); RXV1_5TH_CYCLE = (RX_VECTOR1_5TH_CYCLE *)(Data + 16); RXV1_6TH_CYCLE = (RX_VECTOR1_6TH_CYCLE *)(Data + 20); RXV2_2ND_CYCLE = (RX_VECTOR2_2ND_CYCLE *)(Data + 28); } else if (Type == RMAC_RX_PKT_TYPE_RX_TXRXV) { //DW0 = (RXV_DWORD0 *)Data; DW1 = (RXV_DWORD1 *)(Data + 4); RXV1_1ST_CYCLE = (RX_VECTOR1_1ST_CYCLE *)(Data + 8); //RXV1_2ND_CYCLE = (RX_VECTOR1_2ND_CYCLE *)(Data + 12); #ifdef CONFIG_QA RXV1_3TH_CYCLE = (RX_VECTOR1_3TH_CYCLE *)(Data + 16); #endif /* CONFIG_QA */ RXV1_4TH_CYCLE = (RX_VECTOR1_4TH_CYCLE *)(Data + 20); RXV1_5TH_CYCLE = (RX_VECTOR1_5TH_CYCLE *)(Data + 24); RXV1_6TH_CYCLE = (RX_VECTOR1_6TH_CYCLE *)(Data + 28); RXV2_1ST_CYCLE = (RX_VECTOR2_1ST_CYCLE *)(Data + 32); RXV2_2ND_CYCLE = (RX_VECTOR2_2ND_CYCLE *)(Data + 36); RXV2_3TH_CYCLE = (RX_VECTOR2_3TH_CYCLE *)(Data + 40); RxBlk->rxv2_cyc1 = *(UINT32 *)RXV2_1ST_CYCLE; RxBlk->rxv2_cyc2 = *(UINT32 *)RXV2_2ND_CYCLE; RxBlk->rxv2_cyc3 = *(UINT32 *)RXV2_3TH_CYCLE; pAd->rxv2_cyc3[(DW1->RxvSn % 10)] = RxBlk->rxv2_cyc3; #ifdef CONFIG_QA pAd->ATECtrl.RCPI0 = RXV1_3TH_CYCLE->Rcpi0; pAd->ATECtrl.RCPI1 = RXV1_3TH_CYCLE->Rcpi1; if (RXV1_5TH_CYCLE) { pAd->ATECtrl.FreqOffsetFromRx = RXV1_5TH_CYCLE->FoE; pAd->ATECtrl.SNR0 = RXV1_5TH_CYCLE->LTF_SNR0; } if (RXV2_2ND_CYCLE) pAd->ATECtrl.SNR1 = RXV2_2ND_CYCLE->OfdmLtfSNR1; pAd->ATECtrl.RSSI0 = RXV1_3TH_CYCLE->Rcpi0/2 - 110; pAd->ATECtrl.RSSI1 = RXV1_3TH_CYCLE->Rcpi1/2 - 110; #endif /* CONFIG_QA */ } else { DBGPRINT(RT_DEBUG_ERROR,("%s(): invalid Type %u\n",__FUNCTION__,Type)); return; /* return here to avoid dereferencing NULL pointer below */ } #ifdef RELEASE_EXCLUDE /* MT7603, MT7628, MT7636 E1 has hardware bug. BBP not report BW20 CCK RCPI. so,driver must use inband RSSI. */ #endif /* RELEASE_EXCLUDE */ //RxBlk->rx_signal.raw_rssi[0] = (RXV1_3TH_CYCLE->Rcpi0 - 220) / 2; //RxBlk->rx_signal.raw_rssi[1] = (RXV1_3TH_CYCLE->Rcpi1 - 220) / 2; RxBlk->rx_signal.raw_rssi[0] = (CHAR)RXV1_4TH_CYCLE->IBRssi0; RxBlk->rx_signal.raw_rssi[1] = (CHAR)RXV1_4TH_CYCLE->IBRssi1; if (RXV1_5TH_CYCLE) RxBlk->rx_signal.raw_snr[0] = RXV1_5TH_CYCLE->LTF_SNR0; if (RXV2_2ND_CYCLE) RxBlk->rx_signal.raw_snr[1] = RXV2_2ND_CYCLE->OfdmLtfSNR1; if (RXV1_6TH_CYCLE) { #ifdef CONFIG_AP_SUPPORT pAd->ApCfg.RssiSample.LastNoiseLevel[0] = ((RXV1_6TH_CYCLE->Nf0 - 254)/2); pAd->ApCfg.RssiSample.LastNoiseLevel[1] = ((RXV1_6TH_CYCLE->Nf1 - 254)/2); #endif #ifdef CONFIG_STA_SUPPORT pAd->StaCfg.RssiSample.LastNoiseLevel[0] = ((RXV1_6TH_CYCLE->Nf0 - 254)/2); pAd->StaCfg.RssiSample.LastNoiseLevel[1] = ((RXV1_6TH_CYCLE->Nf1 - 254)/2); #endif } //RxBlk->rx_signal.raw_snr[0] = rxwi_n->bbp_rxinfo[0]; //RxBlk->rx_signal.raw_snr[1] = rxwi_n->bbp_rxinfo[1]; //RxBlk->rx_signal.freq_offset = rxwi_n->bbp_rxinfo[4]; RxBlk->rx_rate.field.MODE = (USHORT)RXV1_1ST_CYCLE->TxMode; RxBlk->rx_rate.field.MCS = (USHORT)RXV1_1ST_CYCLE->TxRate; RxBlk->rx_rate.field.ldpc = (USHORT)RXV1_1ST_CYCLE->HtAdCode; RxBlk->rx_rate.field.BW = (USHORT)RXV1_1ST_CYCLE->FrMode; RxBlk->rx_rate.field.STBC = (USHORT)RXV1_1ST_CYCLE->HtStbc; RxBlk->rx_rate.field.ShortGI = (USHORT)RXV1_1ST_CYCLE->HtShortGi; } static inline INT32 mt_rx_info_2_blk( RTMP_ADAPTER *pAd, RX_BLK *pRxBlk, PNDIS_PACKET pRxPacket, INT32 pkt_type) { UCHAR *RMACInfo, *Pos; INT32 RMACInfoLen; struct rxd_base_struc *rx_base; //RXD_GRP4_STRUCT *RxdGrp4 = NULL; RXD_GRP1_STRUCT * RxdGrp1 = NULL; RXD_GRP2_STRUCT *RxdGrp2 = NULL; RXD_GRP3_STRUCT *RxdGrp3 = NULL; pRxBlk->pRxInfo = (RXINFO_STRUC *)(&pRxBlk->hw_rx_info[RXINFO_OFFSET]); RMACInfo = (UCHAR *)(GET_OS_PKT_DATAPTR(pRxPacket)); Pos = RMACInfo; pRxBlk->rmac_info = RMACInfo; rx_base = (struct rxd_base_struc *)RMACInfo; Pos += RMAC_INFO_BASE_SIZE; if (rx_base->rxd_0.grp_vld & RXS_GROUP4) { //RxdGrp4 = (RXD_GRP4_STRUCT *)Pos; Pos += RMAC_INFO_GRP_4_SIZE; } if (rx_base->rxd_0.grp_vld & RXS_GROUP1) { RxdGrp1 = (RXD_GRP1_STRUCT *)Pos; Pos += RMAC_INFO_GRP_1_SIZE; } if (rx_base->rxd_0.grp_vld & RXS_GROUP2) { RxdGrp2 = (RXD_GRP2_STRUCT *)Pos; Pos += RMAC_INFO_GRP_2_SIZE; } if (rx_base->rxd_0.grp_vld & RXS_GROUP3) { RxdGrp3 = (RXD_GRP3_STRUCT *)Pos; Pos += RMAC_INFO_GRP_3_SIZE; } if(NULL == RxdGrp2) { DBGPRINT(RT_DEBUG_ERROR, ("%s: Error RxdGrp2 is null pointer!!!!\n", __FUNCTION__)); return INVALID_RX_PACKET_LEN; } RMACInfoLen = RMACInfoGrpToLen[rx_base->rxd_0.grp_vld]; #ifdef RT_BIG_ENDIAN if ((RMACInfoLen - 4) > 0) { MTMacInfoEndianChange(pAd, RMACInfo, TYPE_RMACINFO, RMACInfoLen); } #endif /* RT_BIG_ENDIAN */ //dump_rmac_info(pAd, RMACInfo); pRxBlk->sec_mode = rx_base->rxd_2.sec_mode; if (RxdGrp1 != NULL) { UINT64 pn1 = RxdGrp1->sec_pn_48; UINT64 pnTotal = 0; if (pn1 != 0) pnTotal = RxdGrp1->sec_pn_32 + (pn1 << 32); else pnTotal = RxdGrp1->sec_pn_32; pRxBlk->ccmp_pn = pnTotal; } pRxBlk->MPDUtotalByteCnt = (USHORT)(rx_base->rxd_0.rx_byte_cnt - RMACInfoLen); if (rx_base->rxd_1.hdr_offset == 1) { pRxBlk->MPDUtotalByteCnt -= 2; RMACInfoLen += 2; } pRxBlk->DataSize = pRxBlk->MPDUtotalByteCnt; pRxBlk->wcid = (UCHAR)rx_base->rxd_2.wlan_idx; pRxBlk->bss_idx = (UCHAR)rx_base->rxd_1.bssid; pRxBlk->key_idx = (UCHAR)rx_base->rxd_1.key_id; pRxBlk->TID = (UCHAR)rx_base->rxd_2.tid; pRxBlk->TimeStamp = RxdGrp2->timestamp; pRxBlk->pRxInfo->U2M = rx_base->rxd_1.u2m; pRxBlk->pRxInfo->Mcast = rx_base->rxd_1.mcast; pRxBlk->pRxInfo->Bcast = rx_base->rxd_1.bcast; pRxBlk->pRxInfo->FRAG = rx_base->rxd_2.frag; pRxBlk->pRxInfo->NULLDATA = rx_base->rxd_2.null_frm; pRxBlk->pRxInfo->DATA = !(rx_base->rxd_2.ndata); pRxBlk->pRxInfo->HTC = rx_base->rxd_1.htc_vld; pRxBlk->pRxInfo->AMPDU = !(rx_base->rxd_2.non_ampdu); pRxBlk->pRxInfo->L2PAD = 0; pRxBlk->pRxInfo->AMSDU = 0; // TODO: pRxBlk->pRxInfo->CipherErr = rx_base->rxd_2.icv_err | (rx_base->rxd_2.tkip_mic_err << 1);/* 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid */ pRxBlk->pRxInfo->Crc = rx_base->rxd_2.fcs_err; pRxBlk->pRxInfo->MyBss = ((rx_base->rxd_1.bssid == 0xf) ? 0 : 1); pRxBlk->pRxInfo->BA = !(rx_base->rxd_2.non_ampdu); pRxBlk->pRxInfo->Decrypted = 0; // TODO: if (rx_base->rxd_0.grp_vld & RXS_GROUP3) ParseRxVPacket(pAd, RMAC_RX_PKT_TYPE_RX_NORMAL, pRxBlk, (UCHAR *)RxdGrp3); SET_OS_PKT_DATAPTR(pRxPacket, GET_OS_PKT_DATAPTR(pRxPacket) + RMACInfoLen); SET_OS_PKT_LEN(pRxPacket, pRxBlk->MPDUtotalByteCnt); //+++Add by shiang for work-around #if 0 // TODO: shiang-MT7603, remove me after hw issue fixed! pRxBlk->MPDUtotalByteCnt -= 4; pRxBlk->DataSize = pRxBlk->MPDUtotalByteCnt; SET_OS_PKT_DATAPTR(pRxPacket, GET_OS_PKT_DATAPTR(pRxPacket) + 4); SET_OS_PKT_LEN(pRxPacket, pRxBlk->MPDUtotalByteCnt); DBGPRINT(RT_DEBUG_OFF, ("%s(): After work-around, DataPtr=%p, DataLen=%d\n", __FUNCTION__, GET_OS_PKT_DATAPTR(pRxPacket), GET_OS_PKT_LEN(pRxPacket))); #endif //---Add by shiang for work-around return RMACInfoLen; } #endif /* MT_MAC */ #define NUM_TYPE_STRING 8 UCHAR *rx_pkt_type_string [NUM_TYPE_STRING] = { "RMAC_RX_PKT_TYPE_RX_TXS", "RMAC_RX_PKT_TYPE_RX_TXRXV", "RMAC_RX_PKT_TYPE_RX_NORMAL", "RMAC_RX_PKT_TYPE_RX_DUP_RFB", "RMAC_RX_PKT_TYPE_RX_TMR", "Undefine Type 0x5", "Undefine Type 0x6", "RMAC_RX_PKT_TYPE_RX_EVENT" }; UINT32 parse_rx_packet_type(RTMP_ADAPTER *ad, RX_BLK *rx_blk, VOID *rx_packet) { UINT32 rx_hw_hdr_len = 0; UINT32 rx_pkt_type; union rmac_rxd_0 *rxd_0; rxd_0 = (union rmac_rxd_0 *)(GET_OS_PKT_DATAPTR(rx_packet)); #ifdef RT_BIG_ENDIAN mt_rmac_d0_endian_change(&rxd_0->word); #endif /* RT_BIG_ENDIAN */ #ifdef RTMP_PCI_SUPPORT if (RMAC_RX_PKT_RX_BYTE_COUNT(rxd_0->word) > RX_BUFFER_AGGRESIZE) { DBGPRINT(RT_DEBUG_ERROR, ("drop rx length = 0x%x packet\n", RMAC_RX_PKT_RX_BYTE_COUNT(rxd_0->word))); return 0; } #endif rx_pkt_type = RMAC_RX_PKT_TYPE(rxd_0->word); switch (rx_pkt_type) { case RMAC_RX_PKT_TYPE_RX_NORMAL: case RMAC_RX_PKT_TYPE_RX_DUP_RFB: #ifdef MT_MAC rx_hw_hdr_len = mt_rx_info_2_blk(ad, rx_blk, rx_packet, rx_pkt_type); #endif /* MT_MAC */ break; case RMAC_RX_PKT_TYPE_RX_TXRXV: { RMAC_RXD_0_TXRXV *rxv = (RMAC_RXD_0_TXRXV *)(GET_OS_PKT_DATAPTR(rx_packet)); UCHAR *ptr; INT idx; DBGPRINT(RT_DEBUG_LOUD, ("RxV Report: Number=%d, ByteCnt=%d\n", rxv->rxv_cnt, rxv->rx_byte_cnt)); if (rxv->rx_byte_cnt != (rxv->rxv_cnt * 44 + 4)) { DBGPRINT(RT_DEBUG_ERROR, ("ReceivedByteCnt not equal rxv_entry required!\n")); } else { ptr = (UCHAR *)(GET_OS_PKT_DATAPTR(rx_packet) + 4); #ifdef RT_BIG_ENDIAN if ((rxv->rx_byte_cnt - 4) > 0) { MTMacInfoEndianChange(ad, ptr, TYPE_RMACINFO, rxv->rx_byte_cnt); } #endif /* RT_BIG_ENDIAN */ for (idx = 0; idx < rxv->rxv_cnt; idx++) { ParseRxVPacket(ad, RMAC_RX_PKT_TYPE_RX_TXRXV, rx_blk, ptr); ptr += 44; } } } break; case RMAC_RX_PKT_TYPE_RX_TXS: { RMAC_RXD_0_TXS *txs = (RMAC_RXD_0_TXS *)(GET_OS_PKT_DATAPTR(rx_packet)); UCHAR *ptr; INT idx; DBGPRINT(RT_DEBUG_INFO, ("TxS Report: Number=%d, ByteCnt=%d\n", txs->txs_cnt, txs->rx_byte_cnt)); if (txs->rx_byte_cnt != (txs->txs_cnt * 20 + 4)) { DBGPRINT(RT_DEBUG_ERROR, ("ReceivedByteCnt not equal txs_entry required!\n")); } else { ptr = (UCHAR *)(GET_OS_PKT_DATAPTR(rx_packet) + 4); for (idx = 0; idx < txs->txs_cnt; idx++) { TXS_STRUC *txs_entry = (TXS_STRUC *)ptr; TXS_D_0 *txs_d0 = &txs_entry->txs_d0; #ifdef RT_BIG_ENDIAN TXS_D_1 *txs_d1 = &txs_entry->txs_d1; TXS_D_2 *txs_d2 = &txs_entry->txs_d2; TXS_D_3 *txs_d3 = &txs_entry->txs_d3; #endif TXS_D_4 *txs_d4 = &txs_entry->txs_d4; #ifdef RT_BIG_ENDIAN *(((UINT32 *)txs_d0)) = SWAP32(*(((UINT32 *)txs_d0))); *(((UINT32 *)txs_d1)) = SWAP32(*(((UINT32 *)txs_d1))); *(((UINT32 *)txs_d2)) = SWAP32(*(((UINT32 *)txs_d2))); *(((UINT32 *)txs_d3)) = SWAP32(*(((UINT32 *)txs_d3))); *(((UINT32 *)txs_d4)) = SWAP32(*(((UINT32 *)txs_d4))); #endif ParseTxSPacket(ad, txs_d4->pid, (UINT8)txs_d0->txsfm, ptr); ptr += 20; } } } break; case RMAC_RX_PKT_TYPE_RX_EVENT: { if (ad->chipOps.rx_event_handler != NULL) ad->chipOps.rx_event_handler(ad, GET_OS_PKT_DATAPTR(rx_packet)); if (rx_blk) RX_BLK_SET_FLAG(rx_blk, fRX_CMD_RSP); } break; #ifdef MT_PS case RMAC_RX_PKT_TYPE_RETRIEVE: { struct rxd_base_struc *rx_base; TMAC_TXD_L *txd_l = (TMAC_TXD_L *)(GET_OS_PKT_DATAPTR(rx_packet)); TMAC_TXD_1 *txd_1 = &txd_l->txd_1; #ifdef RT_BIG_ENDIAN *(((UINT32 *)txd_1)) = SWAP32(*(((UINT32 *)txd_1))); #endif /* RT_BIG_ENDIAN */ UCHAR padding = txd_1->hdr_pad & 0x03; UCHAR hdr_info = txd_1->hdr_info*2; UCHAR *da, *sa; STA_TR_ENTRY *tr_entry; MAC_TABLE_ENTRY *pEntry; unsigned long IrqFlags; UINT32 q_idx = QID_AC_BE; HEADER_802_11 *pWifi_hdr; UCHAR *qos_p; #ifdef UAPSD_SUPPORT UCHAR ac_idx = 0; #endif /* UAPSD_SUPPORT */ tr_entry = &ad->MacTab.tr_entry[txd_1->wlan_idx]; pEntry = &ad->MacTab.Content[txd_1->wlan_idx]; rx_base = (struct rxd_base_struc *)rxd_0; pWifi_hdr = (HEADER_802_11 *)(GET_OS_PKT_DATAPTR(rx_packet) + sizeof(TMAC_TXD_L)); #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(ad, (PUCHAR)pWifi_hdr, DIR_READ, FALSE); #endif DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("parse_rx_packet_type wlan_idx=%d,%d,%d,0x%x\n", txd_1->wlan_idx,hdr_info,padding,tr_entry->EntryType)); if ((pWifi_hdr->FC.Type == FC_TYPE_CNTL) || (pWifi_hdr->FC.Type == FC_TYPE_MGMT)) { return 0; } da = pWifi_hdr->Addr1; sa = pWifi_hdr->Addr2; qos_p = ((UCHAR *)pWifi_hdr) + sizeof(HEADER_802_11); #ifdef UAPSD_SUPPORT /* Sanity Check for UAPSD condition for correct QoS index. */ if (qos_p[0] >= 8) qos_p[0] = 1; /* shout not be here */ /* get the AC ID of incoming packet */ ac_idx = WMM_UP2AC_MAP[qos_p[0]]; #endif /* UAPSD_SUPPORT */ RX_BLK_SET_FLAG(rx_blk, fRX_RETRIEVE); if ((tr_entry->ps_state == APPS_RETRIEVE_GOING) || (tr_entry->ps_state == APPS_RETRIEVE_START_PS)) { if (qos_p[1] == PS_RETRIEVE_TOKEN) //retrive_token : 0x76 { rx_blk->DataSize = 0; rx_blk->MPDUtotalByteCnt = rx_base->rxd_0.rx_byte_cnt; tr_entry->ps_qbitmap &= (~(1 << qos_p[0])) ; //DBGPRINT(RT_DEBUG_ERROR, ("txd_1->wlan_idx=%d, got token:%d, tr_entry->ps_qbitmap=%x\n", txd_1->wlan_idx, qos_p[0], tr_entry->ps_qbitmap)); if (tr_entry->ps_qbitmap == 0x0) { //QUEUE_ENTRY *pQEntry; UINT32 wlan_idx = 0; int for_qid; if (tr_entry->ps_queue.Number) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("(wcid=%d) put ps_queue packets(Number=%d) to tx_queue.\n", txd_1->wlan_idx, tr_entry->ps_queue.Number)); MtEnqTxSwqFromPsQueue(ad, q_idx, tr_entry); } for (for_qid = 0; for_qid < WMM_QUE_NUM; for_qid++) { tr_entry->TokenCount[for_qid] = tr_entry->tx_queue[for_qid].Number; } tr_entry->ps_state = APPS_RETRIEVE_WAIT_EVENT; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("(ps_state = %d)Receives all RMAC_RX_PKT_TYPE_RETRIEVE packets and send CMDTHREAD_PS_CLEAR cmd.\n", tr_entry->ps_state)); wlan_idx = pEntry->wcid; RTEnqueueInternalCmd(ad, CMDTHREAD_PS_CLEAR, (VOID *)&wlan_idx, sizeof(UINT32)); } } else { INT packet_length = 0; if ((pWifi_hdr->FC.SubType == SUBTYPE_DATA_NULL) || (pWifi_hdr->FC.SubType == SUBTYPE_QOS_NULL)) return 0; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("da=(%02x:%02x:%02x:%02x:%02x:%02x), sa=(%02x:%02x:%02x:%02x:%02x:%02x), qos_p->ac%d, qos_p->value=%d, Sequence=%d txd_1->wlan_idx=%d\n" , PRINT_MAC(da), PRINT_MAC(sa), qos_p[0], qos_p[1], pWifi_hdr->Sequence,txd_1->wlan_idx)); packet_length = rx_base->rxd_0.rx_byte_cnt-sizeof(TMAC_TXD_L) - padding - hdr_info - sizeof(SNAP_802_1H); if (packet_length <= 0) return 0; rx_hw_hdr_len = sizeof(TMAC_TXD_L); SET_OS_PKT_DATAPTR(rx_packet, GET_OS_PKT_DATAPTR(rx_packet) + sizeof(TMAC_TXD_L) + padding + hdr_info + sizeof(SNAP_802_1H)); SET_OS_PKT_LEN(rx_packet, packet_length); OS_PKT_HEAD_BUF_EXTEND(rx_packet, MAC_ADDR_LEN + MAC_ADDR_LEN); NdisCopyMemory(GET_OS_PKT_DATAPTR(rx_packet) + MAC_ADDR_LEN, sa, MAC_ADDR_LEN); NdisCopyMemory(GET_OS_PKT_DATAPTR(rx_packet), da, MAC_ADDR_LEN); RTMP_SET_PACKET_WCID(rx_packet, txd_1->wlan_idx); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("parse_rx_packet_type not token txd_1->wlan_idx: %x, rx_packet addr: %x rx_wcid: %x\n",txd_1->wlan_idx,(u32)rx_packet,RTMP_GET_PACKET_WCID(rx_packet))); RTMP_SET_PACKET_WDEV(rx_packet, tr_entry->wdev->wdev_idx); RTMP_IRQ_LOCK(&ad->irq_lock, IrqFlags); if (tr_entry->ps_queue.Number >= MAX_PACKETS_IN_PS_QUEUE) { // drop the ps retrive pks due to limit ps queue max length RELEASE_NDIS_PACKET(ad, rx_packet, NDIS_STATUS_FAILURE); } else { InsertTailQueue(&tr_entry->ps_queue, PACKET_TO_QUEUE_ENTRY(rx_packet)); } RTMP_IRQ_UNLOCK(&ad->irq_lock, IrqFlags); #ifdef UAPSD_SUPPORT if (UAPSD_MR_IS_NOT_TIM_BIT_NEEDED_HANDLED(&ad->MacTab.Content[tr_entry->wcid], ac_idx)) { /* 1. the station is UAPSD station; 2. one of AC is non-UAPSD (legacy) AC; 3. the destinated AC of the packet is UAPSD AC. */ /* So we can not set TIM bit due to one of AC is legacy AC */ } else #endif /* UAPSD_SUPPORT */ { WLAN_MR_TIM_BIT_SET(ad, tr_entry->func_tb_idx, tr_entry->wcid); } } } else { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_PS, ("da=(%02x:%02x:%02x:%02x:%02x:%02x), sa=(%02x:%02x:%02x:%02x:%02x:%02x), qos_p->ac%d, qos_p->value=%d, Sequence=%d txd_1->wlan_idx=%d, ps_state = %d\n" , PRINT_MAC(da), PRINT_MAC(sa), qos_p[0], qos_p[1], pWifi_hdr->Sequence,txd_1->wlan_idx, tr_entry->ps_state)); } break; } #endif /* MT_PS */ case RMAC_RX_PKT_TYPE_RX_TMR: { TMR_FRM_STRUC *tmr = (TMR_FRM_STRUC *)(GET_OS_PKT_DATAPTR(rx_packet)); struct rmac_rxd_0_tmr *ptmr_d0 = &tmr->tmr_d0; //TMR_D_1 *ptmr_d1 = &tmr->tmr_d1; UINT32 *ptod_0 = &tmr->tod_0; UINT32 *ptoa_0 = &tmr->toa_0; TMR_D_6 *tmr_d6 = &tmr->tmr_d6; UNUSED(ptmr_d0); UNUSED(ptod_0); UNUSED(ptoa_0); UNUSED(tmr_d6); hex_dump("TMR", (UCHAR *)tmr, 20); return 0; #if 0 hex_dump("TMR", (UCHAR *)tmr, ptmr_d0->rx_byte_cnt); DBGPRINT(RT_DEBUG_OFF, ("TMR Report: ir = %d\n", ptmr_d0->ir)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_0: ByteCnt=%d, NC=%d, TMF=%d, " "toa_vld=%d, tod_vld=%d\n", ptmr_d0->rx_byte_cnt, ptmr_d0->nc, ptmr_d0->tmf, ptmr_d0->toa_vld, ptmr_d0->tod_vld)); if (ptmr_d0->ir == 1) //responder case! { TMR_D_2 *ptmr_d2 = &tmr->tmr_d2; UINT32 *pta_16 = &tmr->ta_16; DBGPRINT(RT_DEBUG_OFF, ("TYPE=%x,SUB_TYPE=%x\n", ptmr_d0->type, ptmr_d0->sub_type)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_2: TA[0:15]=%x, SN=%x\n", ptmr_d2->field.ta_0, ptmr_d2->field.sn)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_3: TA[16:47]=%x\n", *pta_16)); } DBGPRINT(RT_DEBUG_OFF, ("DWORD_4: TOD[0:31]=0x%x\n", *ptod_0)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_6: TOD[32:47]=0x%x\n", tmr_d6->field.tod_32)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_5: TOA[0:31]=0x%x\n", *ptoa_0)); DBGPRINT(RT_DEBUG_OFF, ("DWORD_6: TOA[32:47]=0x%x\n", tmr_d6->field.toa_32)); #endif } break; default: DBGPRINT(RT_DEBUG_OFF, ("%s():Invalid PktType:%d\n", __FUNCTION__, rx_pkt_type)); //rx_hw_hdr_len = pRxD->SDL0; //rx_blk->MPDUtotalByteCnt = 0; //rx_blk->DataSize = 0; break; } return rx_hw_hdr_len; } #endif /* MT_MAC */ #ifdef DOT11_N_SUPPORT #ifdef RELEASE_EXCLUDE /* For IOT compatibility, BA session can be build only when 1. It is Ralink chip or 2. It is OPEN or AES mode */ #endif /* RELEASE_EXCLUDE */ VOID RTMP_BASetup(RTMP_ADAPTER *pAd, STA_TR_ENTRY *tr_entry, UINT8 UPriority) { MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[tr_entry->wcid]; if (pAd->CommonCfg.BACapability.field.AutoBA == FALSE) return; // TODO: shiang-usw, fix me for pEntry, we should replace this paramter as tr_entry! if ((tr_entry && tr_entry->EntryType != ENTRY_CAT_MCAST && tr_entry->wcid < MAX_LEN_OF_MAC_TABLE) && (pEntry->NoBADataCountDown == 0) && IS_HT_STA(pEntry)) { BOOLEAN isRalink = CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET); if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1 << UPriority)) == 0) */ && (tr_entry->PortSecured == WPA_802_1X_PORT_SECURED) && (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))) #ifdef RT3290 && (!(IS_RT3290(pAd) && pAd->WlanBTCoexInfo.ampduOff == TRUE)) #endif /* RT3290 */ && ((isRalink || IS_ENTRY_MESH(pEntry) || IS_ENTRY_WDS(pEntry)) || (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11AESEnable #ifdef WAPI_SUPPORT || pEntry->WepStatus == Ndis802_11EncryptionSMS4Enabled #endif /* WAPI_SUPPORT */ )) ) { BAOriSessionSetUp(pAd, pEntry, UPriority, 0, 10, FALSE); } } } #endif /* DOT11_N_SUPPORT */ /* ======================================================================== Routine Description: API for MLME to transmit management frame to AP (BSS Mode) or station (IBSS Mode) Arguments: pAd Pointer to our adapter pData Pointer to the outgoing 802.11 frame Length Size of outgoing management frame Return Value: NDIS_STATUS_FAILURE NDIS_STATUS_PENDING NDIS_STATUS_SUCCESS IRQL = PASSIVE_LEVEL IRQL = DISPATCH_LEVEL Note: ======================================================================== */ #define MAX_DATAMM_RETRY 3 NDIS_STATUS MiniportMMRequest(RTMP_ADAPTER *pAd, UCHAR QueIdx, UCHAR *pData, UINT Length) { PNDIS_PACKET pPacket; NDIS_STATUS Status = NDIS_STATUS_FAILURE; ULONG FreeNum; #ifdef RTMP_MAC_PCI unsigned long IrqFlags = 0; BOOLEAN bUseDataQ = FALSE; #endif /* RTMP_MAC_PCI */ BOOLEAN FlgDataQForce = FALSE, FlgIsLocked = FALSE; int retryCnt = 0; BOOLEAN FlgIsCheckPS = FALSE; ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); if ((QueIdx & MGMT_USE_QUEUE_FLAG) == MGMT_USE_QUEUE_FLAG) { #ifdef RTMP_MAC_PCI bUseDataQ = TRUE; #endif /* RTMP_MAC_PCI */ QueIdx &= (~MGMT_USE_QUEUE_FLAG); } #ifndef MT_PS #ifdef CONFIG_FPGA_MODE if (pAd->fpga_ctl.fpga_on & 0x1) { if (pAd->fpga_ctl.tx_kick_cnt > 0) { if (pAd->fpga_ctl.tx_kick_cnt < 0xffff) pAd->fpga_ctl.tx_kick_cnt--; } else return NDIS_STATUS_FAILURE; QueIdx = 0; //bUseDataQ = TRUE; } #endif /* CONFIG_FPGA_MODE */ #endif /* MT_PS */ if ((QueIdx & MGMT_USE_PS_FLAG) == MGMT_USE_PS_FLAG) { FlgIsCheckPS = TRUE; QueIdx &= (~MGMT_USE_PS_FLAG); } #ifdef RTMP_MAC_PCI if (pAd->MACVersion == 0x28600100) { /* do not care about the version */ QueIdx = (bUseDataQ ==TRUE ? QueIdx : 3); bUseDataQ = TRUE; } #if 0 //defined(MT7603) || defined(MT7628) // TODO: shiang-7603, now only verifiy the AC0 when DMA scheduler is not ready! if (IS_MT7603(pAd) || IS_MT7628(pAd)) { bUseDataQ = TRUE; } #endif /* MT7603 */ if (bUseDataQ) { RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); FlgIsLocked = TRUE; retryCnt = MAX_DATAMM_RETRY; } #endif /* RTMP_MAC_PCI */ do { /* Reset is in progress, stop immediately*/ if (RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_RADIO_OFF)) || !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) #ifdef P2P_SUPPORT || IS_P2P_ABSENCE(pAd) #endif /* P2P_SUPPORT */ ) { Status = NDIS_STATUS_FAILURE; break; } #ifdef CONFIG_STA_SUPPORT #ifdef RTMP_MAC_USB if(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)) { #ifdef RLT_MAC if (pAd->chipCap.hif_type == HIF_RLT) { #ifdef MT7601 if ( IS_MT7601(pAd) ) ASIC_RADIO_ON(pAd, DOT11_RADIO_ON); else #endif /* MT7601 */ ASIC_RADIO_ON(pAd, MLME_RADIO_ON); } #endif /* RLT_MAC */ #ifdef RTMP_MAC if (pAd->chipCap.hif_type == HIF_RTMP) { RT28xxUsbAsicRadioOn(pAd); } #endif /* RTMP_MAC */ } #endif /* RTMP_MAC_USB */ #endif /* CONFIG_STA_SUPPORT */ /* Check Free priority queue*/ /* Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing.*/ #ifdef RTMP_MAC_PCI if (bUseDataQ) { #ifndef __ECOS /* Eddy temporary remove on ECOS */ /* free Tx(QueIdx) resources*/ RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); #endif /* __ECOS */ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); } else #endif /* RTMP_MAC_PCI */ { FreeNum = GET_MGMTRING_FREENO(pAd); #ifdef __ECOS /* keep the management ring has more space */ if (FreeNum < (MGMT_RING_SIZE/2)) { RTMPHandleMgmtRingDmaDoneInterrupt(pAd); FreeNum = GET_MGMTRING_FREENO(pAd); } #endif /* __ECOS */ } if ((FreeNum > 0)) { INT hw_len; UCHAR rtmpHwHdr[40]; // TODO: shiang-7603 hw_len = pAd->chipCap.tx_hw_hdr_len; ASSERT((sizeof(rtmpHwHdr) > hw_len)); /* We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870*/ NdisZeroMemory(&rtmpHwHdr, hw_len); Status = RTMPAllocateNdisPacket(pAd, &pPacket, (UCHAR *)&rtmpHwHdr[0], hw_len, pData, Length); if (Status != NDIS_STATUS_SUCCESS) { DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); break; } #ifdef DOT11W_PMF_SUPPORT #ifdef CONFIG_STA_SUPPORT if (INFRA_ON(pAd)) #endif /* CONFIG_STA_SUPPORT */ if (pAd->chipCap.hif_type != HIF_MT) PMF_PerformTxFrameAction(pAd, pPacket); #endif /* DOT11W_PMF_SUPPORT */ #if defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) #ifdef UAPSD_SUPPORT UAPSD_MR_QOS_NULL_HANDLE(pAd, pData, pPacket); #endif /* UAPSD_SUPPORT */ #else #ifdef CONFIG_AP_SUPPORT #ifdef UAPSD_SUPPORT #ifdef P2P_SUPPORT if (P2P_GO_ON(pAd)) #else #ifdef RT_CFG80211_P2P_SUPPORT if (RTMP_CFG80211_VIF_P2P_GO_ON(pAd)) #else IF_DEV_CONFIG_OPMODE_ON_AP(pAd) #endif /* RT_CFG80211_P2P_SUPPORT */ #endif /* P2P_SUPPORT */ { UAPSD_MR_QOS_NULL_HANDLE(pAd, pData, pPacket); } #endif /* UAPSD_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ #endif /* defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) */ #ifdef RTMP_MAC_PCI if (bUseDataQ) { FlgDataQForce = TRUE; retryCnt--; } #endif /* RTMP_MAC_PCI */ Status = MlmeHardTransmit(pAd, QueIdx, pPacket, FlgDataQForce, FlgIsLocked, FlgIsCheckPS); if (Status == NDIS_STATUS_SUCCESS) retryCnt = 0; else RELEASE_NDIS_PACKET(pAd, pPacket, Status); } else { pAd->RalinkCounters.MgmtRingFullCount++; #ifdef RTMP_MAC_PCI if (bUseDataQ) { retryCnt--; DBGPRINT(RT_DEBUG_TRACE, ("retryCnt %d\n", retryCnt)); if (retryCnt == 0) { DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n", QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); } } else #endif /* RTMP_MAC_PCI */ { DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); } #ifdef RELEASE_EXCLUDE #ifdef RTMP_MAC_USB /* TODO: need to remove it when do formal release, it's used for debug.*/ Show_TxBulk_Proc(pAd, NULL); #endif /* RTMP_MAC_USB */ #endif /* RELEASE_EXCLUDE */ } } while (retryCnt > 0); #ifdef RTMP_MAC_PCI if (bUseDataQ) RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); #endif /* RTMP_MAC_PCI */ return Status; } #ifdef CONFIG_AP_SUPPORT /* ======================================================================== Routine Description: Copy frame from waiting queue into relative ring buffer and set appropriate ASIC register to kick hardware transmit function Arguments: pAd Pointer to our adapter pBuffer Pointer to memory of outgoing frame Length Size of outgoing management frame FlgIsDeltsFrame 1: the frame is a DELTS frame Return Value: NDIS_STATUS_FAILURE NDIS_STATUS_PENDING NDIS_STATUS_SUCCESS IRQL = PASSIVE_LEVEL IRQL = DISPATCH_LEVEL Note: ======================================================================== */ void AP_QueuePsActionPacket( IN RTMP_ADAPTER *pAd, IN MAC_TABLE_ENTRY *pMacEntry, IN PNDIS_PACKET pPacket, IN BOOLEAN FlgIsDeltsFrame, IN BOOLEAN FlgIsLocked, IN UCHAR MgmtQid) { #ifdef UAPSD_SUPPORT #ifdef UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY PNDIS_PACKET DuplicatePkt = NULL; #endif /* UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY */ #endif /* UAPSD_SUPPORT */ STA_TR_ENTRY *tr_entry = &pAd->MacTab.tr_entry[pMacEntry->wcid]; /* Note: for original mode of 4 AC are UAPSD, if station want to change the mode of a AC to legacy PS, we dont know where to put the response; 1. send the response; 2. but the station is in ps mode, so queue the response; 3. we should queue the reponse to UAPSD queue because the station is not yet change its mode to legacy ps AC; 4. so AP should change its mode to legacy ps AC only when the station sends a trigger frame and we send out the reponse; 5. the mechanism is too complicate; */ #ifdef UAPSD_SUPPORT /* If the frame is action frame and the VO is UAPSD, we can not send the frame to VO queue, we need to send to legacy PS queue; or the frame maybe not got from QSTA. */ /* if ((pMacEntry->bAPSDDeliverEnabledPerAC[MgmtQid]) &&*/ /* (FlgIsDeltsFrame == 0))*/ if (pMacEntry->bAPSDDeliverEnabledPerAC[MgmtQid]) { /* queue the management frame to VO queue if VO is deliver-enabled */ DBGPRINT(RT_DEBUG_TRACE, ("ps> mgmt to UAPSD queue %d ... (IsDelts: %d)\n", MgmtQid, FlgIsDeltsFrame)); #ifdef UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY if (!pMacEntry->bAPSDAllAC) { /* duplicate one packet to legacy PS queue */ RTMP_SET_PACKET_UAPSD(pPacket, 0, MgmtQid); DuplicatePkt = DuplicatePacket(wdev->if_dev, pPacket); } else #endif /* UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY */ { RTMP_SET_PACKET_UAPSD(pPacket, 1, MgmtQid); } #if 1 UAPSD_PacketEnqueue(pAd, pMacEntry, pPacket, MgmtQid, FALSE); #else rtmp_enq_req(pAd, pPacket, MgmtQid, tr_entry, FlgIsLocked,NULL); #endif if (pMacEntry->bAPSDAllAC) { /* mark corresponding TIM bit in outgoing BEACON frame*/ WLAN_MR_TIM_BIT_SET(pAd, pMacEntry->func_tb_idx, pMacEntry->Aid); } else { #ifdef UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY /* duplicate one packet to legacy PS queue */ /* Sometimes AP will send DELTS frame to STA but STA will not send any trigger frame to get the DELTS frame. We must force to send it so put another one in legacy PS queue. */ if (DuplicatePkt != NULL) { pPacket = DuplicatePkt; goto Label_Legacy_PS; } #endif /* UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY */ } } else #endif /* UAPSD_SUPPORT */ { #ifdef UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY Label_Legacy_PS: #endif /* UAPSD_CC_FUNC_PS_MGMT_TO_LEGACY */ DBGPRINT(RT_DEBUG_TRACE, ("ps> mgmt to legacy ps queue... (%d)\n", FlgIsDeltsFrame)); if (tr_entry->ps_queue.Number >= MAX_PACKETS_IN_PS_QUEUE || rtmp_enq_req(pAd, pPacket, MgmtQid, tr_entry, FlgIsLocked, NULL) == FALSE) { DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): WLAN_TX_DROP, pPacket=%p, QueIdx=%d, ps_queue_num=%d, wcid=%d\n", __FUNCTION__, __LINE__, pPacket, MgmtQid, tr_entry->ps_queue.Number, tr_entry->wcid)); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); return; } else { DBGPRINT(RT_DEBUG_TRACE, ("ps> mgmt to legacy ps queue... (%d)\n", FlgIsDeltsFrame)); /* mark corresponding TIM bit in outgoing BEACON frame*/ WLAN_MR_TIM_BIT_SET(pAd, pMacEntry->func_tb_idx, pMacEntry->Aid); } } } #endif /* CONFIG_AP_SUPPORT */ /* ======================================================================== Routine Description: Copy frame from waiting queue into relative ring buffer and set appropriate ASIC register to kick hardware transmit function Arguments: pAd Pointer to our adapter pBuffer Pointer to memory of outgoing frame Length Size of outgoing management frame Return Value: NDIS_STATUS_FAILURE NDIS_STATUS_PENDING NDIS_STATUS_SUCCESS IRQL = PASSIVE_LEVEL IRQL = DISPATCH_LEVEL Note: ======================================================================== */ NDIS_STATUS MlmeHardTransmit( IN RTMP_ADAPTER *pAd, IN UCHAR QueIdx, IN PNDIS_PACKET pPacket, IN BOOLEAN FlgDataQForce, IN BOOLEAN FlgIsLocked, IN BOOLEAN FlgIsCheckPS) { #ifdef CONFIG_AP_SUPPORT MAC_TABLE_ENTRY *pEntry = NULL; HEADER_802_11 *pHeader_802_11; //UINT8 TXWISize = pAd->chipCap.TXWISize; UINT8 tx_hw_hdr_len = pAd->chipCap.tx_hw_hdr_len; #endif /* CONFIG_AP_SUPPORT */ PACKET_INFO PacketInfo; UCHAR *pSrcBufVA; UINT SrcBufLen; if ((pAd->Dot11_H.RDMode != RD_NORMAL_MODE) #ifdef CARRIER_DETECTION_SUPPORT #ifdef CONFIG_AP_SUPPORT ||(isCarrierDetectExist(pAd) == TRUE) #endif /* CONFIG_AP_SUPPORT */ #endif /* CARRIER_DETECTION_SUPPORT */ ) { return NDIS_STATUS_FAILURE; } RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); if (pSrcBufVA == NULL) return NDIS_STATUS_FAILURE; #ifdef CONFIG_AP_SUPPORT // TODO: shiang-7603 pHeader_802_11 = (HEADER_802_11 *) (pSrcBufVA + tx_hw_hdr_len); /* Section 11.2.1.1 STA Power Management modes of IEEE802.11-2007: The Power Managment bit shall not be set in any management frame, except an Action frame. So in the 'baseline' test plan (Wi-Fi 802.11 WPA2, WPA, WEP Interoperability Test Plan), Section 2.2.6, the following Requirement: APs shall ignore the power save bit in any received Authenticate and (Re) Associate, and shall assume that the station is awake for the response. */ /* IEEE802.11, 11.2.1.4 AP operation during the contention period f) A single buffered MSDU or management frame for a STA in the PS mode shall be forwarded to the STA after a PS-Poll has been received from that STA. The More Data field shall be set to indicate the presence of further buffered MSDUs or "management frames" for the polling STA. */ /* IEEE802.11e, 11.2.1.4 Power management with APSD, An unscheduled SP ends after the QAP has attempted to transmit at least one MSDU or MMPDU associated with a delivery-enabled AC and destined for the non-AP QSTA, but no more than the number indicated in the Max SP Length field if the field has a nonzero value. */ if ((pHeader_802_11->FC.Type == FC_TYPE_DATA) || (pHeader_802_11->FC.Type == FC_TYPE_MGMT)) { if ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) || (pHeader_802_11->FC.SubType != SUBTYPE_QOS_NULL)) pEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); } #ifdef DOT11K_RRM_SUPPORT #ifdef QUIET_SUPPORT if ((pEntry != NULL) && (pEntry->func_tb_idx < pAd->ApCfg.BssidNum) && IS_RRM_QUIET(pAd, pEntry->func_tb_idx)) { return NDIS_STATUS_FAILURE; } #endif /* QUIET_SUPPORT */ #endif /* DOT11K_RRM_SUPPORT */ #ifdef WMM_ACM_SUPPORT if (ACMR_IS_AP_MODE(pAd)) { ACMR_PKT_QOS_TYPE_SET(pPacket, 0); /* check if the action frame is ADDTS Response */ if ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) { UINT8 FlgIsRspFrame; FlgIsRspFrame = ACMP_IsResponseFrame(\ ((UCHAR *)pHeader_802_11)+sizeof(HEADER_802_11)); if (FlgIsRspFrame == TRUE) { ACMR_PKT_QOS_TYPE_SET(pPacket, ACM_QOS_TYPE_ADDTS_RSP); } } } #endif /* WMM_ACM_SUPPORT */ #ifdef CONFIG_FPGA_MODE if (pAd->fpga_ctl.fpga_on & 0x1) { if (pAd->fpga_ctl.tx_kick_cnt > 0) { if (pAd->fpga_ctl.tx_kick_cnt < 0xffff) { pAd->fpga_ctl.tx_kick_cnt--; } } else { return NDIS_STATUS_FAILURE; } } #endif /* CONFIG_FPGA_MODE */ if ((pEntry != NULL) && (pEntry->PsMode == PWR_SAVE) && (((pHeader_802_11->FC.Type == FC_TYPE_DATA) && (pHeader_802_11->FC.SubType != SUBTYPE_DATA_NULL) && (pHeader_802_11->FC.SubType != SUBTYPE_QOS_NULL)) || ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) || ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_ACTION_NO_ACK)) || (FlgIsCheckPS == 1))) { /* the peer is in PS mode, we need to queue the management frame */ UINT8 FlgIsDeltsFrame = 0, MgmtQid = QID_AC_VO; /* 1. Data & Not QoS Null, or 2. Management & Action, or 3. Management & Action No ACK; */ DBGPRINT(RT_DEBUG_TRACE, ("STA in ps mode, queue the mgmt frame\n")); RTMP_SET_PACKET_WCID(pPacket, pEntry->wcid); RTMP_SET_PACKET_MGMT_PKT(pPacket, 1); /* is management frame */ RTMP_SET_PACKET_MGMT_PKT_DATA_QUE(pPacket, 0); /* default to management queue */ #ifdef P2P_SUPPORT if (IS_P2P_GO_ENTRY(pEntry)) { RTMP_SET_PACKET_NET_DEVICE_P2P(pPacket,MAIN_MBSSID); RTMP_SET_PACKET_OPMODE(pPacket, OPMODE_AP); } #endif /* P2P_SUPPORT */ #ifdef RT_CFG80211_P2P_SUPPORT if(pEntry->wdev->wdev_type == WDEV_TYPE_AP) { //RTMP_SET_PACKET_NET_DEVICE_MBSSID(pPacket, MAIN_MBSSID); RTMP_SET_PACKET_OPMODE(pPacket, OPMODE_AP); } #endif /* RT_CFG80211_P2P_SUPPORT */ if (FlgDataQForce == TRUE) RTMP_SET_PACKET_MGMT_PKT_DATA_QUE(pPacket, 1); /* force to data queue */ if ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) { FRAME_ADDBA_REQ *pFrameBa = (FRAME_ADDBA_REQ *)pHeader_802_11; if (pFrameBa->Category == CATEGORY_BA) MgmtQid = QueIdx; } #ifdef WMM_ACM_SUPPORT if (ACMR_IS_AP_MODE(pAd)) { /* check if the packet is the DELTS frame */ FlgIsDeltsFrame = ACMP_IsDeltsFrame(\ ((UCHAR *)pHeader_802_11)+sizeof(HEADER_802_11)); if (FlgIsDeltsFrame == TRUE) { ACMR_PKT_QOS_TYPE_SET(pPacket, ACM_QOS_TYPE_DELTS); } } #endif /* WMM_ACM_SUPPORT */ #ifdef CONFIG_HOTSPOT_R2 if (((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_DISASSOC)) || ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_DEAUTH))) { RTMP_SET_PACKET_DISASSOC(pPacket, 1); pEntry->IsKeep = 1; } #endif /* CONFIG_HOTSPOT_R2 */ AP_QueuePsActionPacket(pAd, pEntry, pPacket, FlgIsDeltsFrame, FlgIsLocked, MgmtQid); return NDIS_STATUS_SUCCESS; } else #endif /* CONFIG_AP_SUPPORT */ { #ifdef RTMP_MAC_PCI if (FlgDataQForce == TRUE) return MlmeHardTransmitTxRing(pAd,QueIdx,pPacket); else #endif /* RTMP_MAC_PCI */ return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); } } NDIS_STATUS MlmeHardTransmitMgmtRing(RTMP_ADAPTER *pAd, UCHAR QueIdx, PNDIS_PACKET pPacket) { PACKET_INFO PacketInfo; UCHAR *pSrcBufVA, *tmac_info; UINT SrcBufLen; HEADER_802_11 *pHeader_802_11; BOOLEAN bAckRequired, bInsertTimestamp; PFRAME_BAR pBar = NULL; UCHAR MlmeRate; MAC_TABLE_ENTRY *pMacEntry = NULL; UCHAR PID, wcid, tx_rate; HTTRANSMIT_SETTING *transmit = NULL, TransmitSetting; //UINT8 TXWISize = pAd->chipCap.TXWISize; UINT8 tx_hw_hdr_len = pAd->chipCap.tx_hw_hdr_len; MAC_TX_INFO mac_info; #ifdef CONFIG_AP_SUPPORT #ifdef SPECIFIC_TX_POWER_SUPPORT UCHAR TxPwrAdj = 0; #endif /* SPECIFIC_TX_POWER_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ #ifdef RT_CFG80211_P2P_SUPPORT struct ieee80211_mgmt *mgmt; BOOLEAN is_P2P_action_frame = FALSE; #endif /* RT_CFG80211_P2P_SUPPORT */ UCHAR prot = 0; UCHAR apidx = 0; ULONG Flags = 0; PCFG80211_CTRL pCfg80211_ctrl = &pAd->cfg80211_ctrl; UNUSED(prot); UNUSED(apidx); RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); /* Make sure MGMT ring resource won't be used by other threads*/ RTMP_IRQ_LOCK(&pAd->MgmtRingLock, Flags); NdisZeroMemory((UCHAR *)&mac_info, sizeof(mac_info)); if (pSrcBufVA == NULL) { /* The buffer shouldn't be NULL*/ RTMP_IRQ_UNLOCK(&pAd->MgmtRingLock, Flags); return NDIS_STATUS_FAILURE; } #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { /* outgoing frame always wakeup PHY to prevent frame lost */ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s::Wake up H/W\n", __FUNCTION__)); AsicForceWakeup(pAd, TRUE); } } #endif /* CONFIG_STA_SUPPORT */ #if defined(MT7603) || defined(MT7628) // TODO: shiang-7603 tmac_info = pSrcBufVA; #else tmac_info = pSrcBufVA + TXINFO_SIZE; #endif /* MT7603 */ pHeader_802_11 = (HEADER_802_11 *) (pSrcBufVA + tx_hw_hdr_len); //DBGPRINT(RT_DEBUG_OFF, ("%s(): pSrcBufVA=0x%p, pHeader_802_11=0x%p, tmac_info=%p, tx_hw_hdr_len=%d\n", // __FUNCTION__, pSrcBufVA, pHeader_802_11, tmac_info, tx_hw_hdr_len)); if (pHeader_802_11->Addr1[0] & 0x01) MlmeRate = pAd->CommonCfg.BasicMlmeRate; else MlmeRate = pAd->CommonCfg.MlmeRate; /* Verify Mlme rate for a / g bands.*/ if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) /* 11A band*/ MlmeRate = RATE_6; if (((pHeader_802_11->FC.Type == FC_TYPE_DATA) && (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) || ((pHeader_802_11->FC.Type == FC_TYPE_CNTL) && (pHeader_802_11->FC.SubType == SUBTYPE_BLOCK_ACK_REQ))) { pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); } #ifdef DOT11W_PMF_SUPPORT if (pAd->chipCap.hif_type == HIF_MT) { UINT32 ret = 0; MAC_TABLE_ENTRY *pEntry = NULL; pEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); ret = PMF_RobustFrameClassify( (PHEADER_802_11)pHeader_802_11, (PUCHAR)(((PUCHAR)pHeader_802_11)+LENGTH_802_11), (SrcBufLen - LENGTH_802_11 - tx_hw_hdr_len), (PUCHAR) pEntry, FALSE); if (pEntry) apidx = pEntry->func_tb_idx; if (ret == UNICAST_ROBUST_FRAME) { prot = 1; pHeader_802_11->FC.Wep = 1; } else if (ret == GROUP_ROBUST_FRAME) { ret = PMF_EncapBIPAction(pAd, (PUCHAR)pHeader_802_11, (SrcBufLen - tx_hw_hdr_len)); if (ret == PMF_STATUS_SUCCESS) prot = 2; else DBGPRINT(RT_DEBUG_OFF, ("%s, PMF GROUP ROBUST Encap fail, ret=%d\n", __FUNCTION__, ret)); } } #endif #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { /* Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode.*/ // TODO: shiang-6590, why we need this condition check here? if (WMODE_EQUAL(pAd->CommonCfg.PhyMode, WMODE_A | WMODE_B | WMODE_G) #ifdef DOT11_N_SUPPORT || WMODE_EQUAL(pAd->CommonCfg.PhyMode, WMODE_A | WMODE_B | WMODE_G | WMODE_AN | WMODE_GN) #endif /* DOT11_N_SUPPORT */ #ifdef DOT11_VHT_AC || WMODE_CAP(pAd->CommonCfg.PhyMode, WMODE_AC) #endif /* DOT11_VHT_AC*/ ) { if (pAd->LatchRfRegs.Channel > 14) { pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; } else { pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_0; } } } #endif /* CONFIG_STA_SUPPORT */ #ifdef P2P_SUPPORT if (P2P_INF_ON(pAd)) { if (MAC_ADDR_EQUAL(pHeader_802_11->Addr2, pAd->P2pCfg.CurrentAddress) || (pAd->LatchRfRegs.Channel > 14)) { pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; } else { pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_0; } } #endif /* P2P_SUPPORT */ #ifdef RT_CFG80211_P2P_SUPPORT /* make sure that p2p does not use cck rate */ mgmt = (struct ieee80211_mgmt *)pHeader_802_11; if (ieee80211_is_action(mgmt->frame_control)) { PP2P_PUBLIC_FRAME pP2PFrame = (PP2P_PUBLIC_FRAME) pHeader_802_11; if ((pP2PFrame->p80211Header.FC.SubType == SUBTYPE_ACTION) && (pP2PFrame->Category == CATEGORY_PUBLIC) && (pP2PFrame->Action == ACTION_WIFI_DIRECT)) is_P2P_action_frame = TRUE; } if ((pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_CCK) && (pAd->ScanCtrl.ScanType == SCAN_P2P || (is_P2P_action_frame))) { pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; } #endif /* RT_CFG80211_SUPPORT */ /* Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) Snice it's been set to 0 while on MgtMacHeaderInit By the way this will cause frame to be send on PWR_SAVE failed. */ #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) { /* We are in scan progress, just let the PwrMgmt bit keep as it orginally should be.*/ } else #endif /* CONFIG_STA_SUPPORT */ pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; #ifdef CONFIG_STA_SUPPORT } #endif /* CONFIG_STA_SUPPORT */ #ifdef CONFIG_STA_SUPPORT /* In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame, Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if ((pHeader_802_11->FC.SubType == SUBTYPE_ACTION) || (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL) || ((pHeader_802_11->FC.Type == FC_TYPE_DATA) && ((pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL) || (pHeader_802_11->FC.SubType == SUBTYPE_DATA_NULL)))) { if (RtmpPktPmBitCheck(pAd) == TRUE) pHeader_802_11->FC.PwrMgmt = PWR_SAVE; else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && INFRA_ON(pAd) && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) { /* We are in scan progress, just let the PwrMgmt bit keep as it orginally should be */ } else { pHeader_802_11->FC.PwrMgmt = pAd->CommonCfg.bAPSDForcePowerSave; } #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { #if defined(CONFIG_STA_SUPPORT) && defined(CONFIG_PM_BIT_HW_MODE) /* For MT STA LP control, use H/W control mode for PM bit */ mac_info.PsmBySw = 0; #else mac_info.PsmBySw = 1; #endif /* CONFIG_STA_SUPPORT && CONFIG_PM_BIT_HW_MODE */ } #endif /* MT_MAC */ } } #endif /* CONFIG_STA_SUPPORT */ #ifdef CONFIG_AP_SUPPORT pHeader_802_11->FC.MoreData = RTMP_GET_PACKET_MOREDATA(pPacket); #endif /* CONFIG_AP_SUPPORT */ bInsertTimestamp = FALSE; if (pHeader_802_11->FC.Type == FC_TYPE_CNTL) /* must be PS-POLL*/ { #ifdef CONFIG_STA_SUPPORT /*Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue.*/ if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) { pHeader_802_11->FC.PwrMgmt = PWR_SAVE; } #endif /* CONFIG_STA_SUPPORT */ bAckRequired = FALSE; if (pHeader_802_11->FC.SubType == SUBTYPE_BLOCK_ACK_REQ) { pBar = (PFRAME_BAR)(pSrcBufVA + tx_hw_hdr_len); bAckRequired = TRUE; } #ifdef VHT_TXBF_SUPPORT if (pHeader_802_11->FC.SubType == SUBTYPE_VHT_NDPA) { #if 0 // HsuChu's suggestion pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, SrcBufLen); #else pHeader_802_11->Duration = 100; #endif //DBGPRINT(RT_DEBUG_OFF, ("%s(): VHT_NDPA frame, rate=%d, len=%d, duration=%d\n", // __FUNCTION__, MlmeRate, SrcBufLen, pHeader_802_11->Duration)); //hex_dump("VHT_NDPA after update Duration", (UCHAR *)pHeader_802_11, SrcBufLen); } #endif /* VHT_TXBF_SUPPORT */ } else /* FC_TYPE_MGMT or FC_TYPE_DATA(must be NULL frame)*/ { if (pHeader_802_11->Addr1[0] & 0x01) /* MULTICAST, BROADCAST*/ { bAckRequired = FALSE; pHeader_802_11->Duration = 0; } else { #ifdef SOFT_SOUNDING if (((pHeader_802_11->FC.Type == FC_TYPE_DATA) && (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) && pMacEntry && (pMacEntry->snd_reqired == TRUE)) { bAckRequired = FALSE; pHeader_802_11->Duration = 0; } else #endif /* SOFT_SOUNDING */ { bAckRequired = TRUE; pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) && (pHeader_802_11->FC.Type == FC_TYPE_MGMT)) { bInsertTimestamp = TRUE; bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Response*/ #ifdef CONFIG_AP_SUPPORT #ifdef SPECIFIC_TX_POWER_SUPPORT /* Find which MBSSID to be send this probeRsp */ UINT32 apidx = get_apidx_by_addr(pAd, pHeader_802_11->Addr2); if ( !(apidx >= pAd->ApCfg.BssidNum) && (pAd->ApCfg.MBSSID[apidx].TxPwrAdj != -1) && (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_CCK) && (pAd->CommonCfg.MlmeTransmit.field.MCS == RATE_1)) { TxPwrAdj = pAd->ApCfg.MBSSID[apidx].TxPwrAdj; } #endif /* SPECIFIC_TX_POWER_SUPPORT */ #endif /* CONFIG_AP_SUPPORT */ } else if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) && (pHeader_802_11->FC.Type == FC_TYPE_MGMT)) { bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Request*/ } else if ((pHeader_802_11->FC.SubType == SUBTYPE_DEAUTH) && (MacTableLookup(pAd, pHeader_802_11->Addr1) == NULL)) { bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Deauth */ } } } } pHeader_802_11->Sequence = pAd->Sequence++; if (pAd->Sequence >0xfff) pAd->Sequence = 0; /* Before radar detection done, mgmt frame can not be sent but probe req Because we need to use probe req to trigger driver to send probe req in passive scan */ if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) && (pAd->CommonCfg.bIEEE80211H == 1) && (pAd->Dot11_H.RDMode != RD_NORMAL_MODE)) { RTMP_IRQ_UNLOCK(&pAd->MgmtRingLock, Flags); return NDIS_STATUS_FAILURE; } /* fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET should always has only one physical buffer, and the whole frame size equals to the first scatter buffer size Initialize TX Descriptor For inter-frame gap, the number is for this frame and next frame For MLME rate, we will fix as 2Mb to match other vendor's implement management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not */ PID = PID_MGMT; #ifdef WMM_ACM_SUPPORT if (ACMR_PKT_QOS_TYPE_GET(pPacket) == ACM_QOS_TYPE_ADDTS_RSP) { /* no any empty field can be used in TxWI, nothing to do */ } #endif /* WMM_ACM_SUPPORT */ if (pMacEntry == NULL) { wcid = RESERVED_WCID; // TODO: shiang-7603 if (IS_MT7603(pAd) || IS_MT7628(pAd)) { wcid = 0; #if 1 if(prot) { MAC_TABLE_ENTRY *pEntry = NULL; pEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); if (pEntry) wcid = (UCHAR)pEntry->Aid; } #endif } tx_rate = (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS; transmit = &pAd->CommonCfg.MlmeTransmit; #ifdef VHT_TXBF_SUPPORT if (pAd->NDPA_Request) { transmit->field.MODE = MODE_VHT; transmit->field.MCS = MCS_RATE_6; } #endif } else { #if defined(P2P_SUPPORT) || defined(RT_CFG80211_P2P_SUPPORT) /* P2P Test Case 6.1.12, only OFDM rate can be captured by sniffer */ if( #ifdef P2P_SUPPORT (pAd->P2pCfg.bLowRateQoSNULL == TRUE) && #endif /* P2P_SUPPORT */ #ifdef RT_CFG80211_P2P_SUPPORT (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_APSD_CAPABLE)) && #endif /* RT_CFG80211_P2P_SUPPORT */ ((pHeader_802_11->FC.Type == FC_TYPE_DATA) && (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL))) { DBGPRINT(RT_DEBUG_TRACE, ("%s:: Using Low Rate to send QOS NULL!!\n", __FUNCTION__)); pMacEntry->MaxHTPhyMode.field.MODE = 1; pMacEntry->MaxHTPhyMode.field.MCS = MCS_RATE_6; } #endif /* P2P_SUPPORT || RT_CFG80211_SUPPORT */ wcid = pMacEntry->wcid; tx_rate = (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS; transmit = &pMacEntry->MaxHTPhyMode; /* dont use low rate to send QoS Null data frame */ } if(prot) mac_info.prot = prot; if (prot == 2) mac_info.bss_idx = apidx; mac_info.FRAG = FALSE; mac_info.CFACK = FALSE; mac_info.InsTimestamp = bInsertTimestamp; mac_info.AMPDU = FALSE; mac_info.Ack = bAckRequired; mac_info.BM = IS_BM_MAC_ADDR(pHeader_802_11->Addr1); mac_info.NSeq = FALSE; mac_info.BASize = 0; mac_info.WCID = wcid; mac_info.TID = 0; #if defined(MT7603) || defined(MT7628) // TODO: shiang-MT7603 mac_info.Length = (SrcBufLen - tx_hw_hdr_len); if (pHeader_802_11->FC.Type == FC_TYPE_MGMT) { mac_info.hdr_len = 24; if (pHeader_802_11->FC.Order == 1) mac_info.hdr_len += 4; } else if (pHeader_802_11->FC.Type == FC_TYPE_DATA) { switch (pHeader_802_11->FC.SubType) { case SUBTYPE_DATA_NULL: mac_info.hdr_len = 24; #ifdef RELEASE_EXCLUDE /* * HEC# WHQA_0017099 * When ERP protection enable, it will use CCK to protect and send out 20Mhz pkt. * if the pkt is use 40Mhz and Fixed BW, it will stuck in PSE and cannot be sendout. * the below patch will be removed after MT7603E2 */ #endif /* RELEASE_EXCLUDE */ tx_rate = (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS; transmit = &pAd->CommonCfg.MlmeTransmit; break; case SUBTYPE_QOS_NULL: mac_info.hdr_len = 26; #ifdef RELEASE_EXCLUDE /* * HEC# WHQA_0017099 * When ERP protection enable, it will use CCK to protect and send out 20Mhz pkt. * if the pkt is use 40Mhz and Fixed BW, it will stuck in PSE and cannot be sendout. * the below patch will be removed after MT7603E2 */ #endif /* RELEASE_EXCLUDE */ tx_rate = (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS; transmit = &pAd->CommonCfg.MlmeTransmit; break; default: { DBGPRINT(RT_DEBUG_ERROR, ("%s(): FIXME!!!Unexpected frame(Type=%d, SubType=%d) send to MgmtRing, need to assign the length!\n", __FUNCTION__, pHeader_802_11->FC.Type, pHeader_802_11->FC.SubType)); hex_dump("DataFrame", (char *)pHeader_802_11, 24); } break; } if (pMacEntry && pAd->MacTab.tr_entry[wcid].PsDeQWaitCnt) PID = PID_PS_DATA; mac_info.WCID = wcid; } else if (pHeader_802_11->FC.Type == FC_TYPE_CNTL) { switch (pHeader_802_11->FC.SubType) { case SUBTYPE_BLOCK_ACK_REQ: PID = PID_CTL_BAR; mac_info.hdr_len = 16; mac_info.SpeEn = 0; mac_info.TID = (UCHAR)pBar->BarControl.TID; if (pAd->CommonCfg.Channel > 14) { /* 2.4G */ TransmitSetting.field.MODE = MODE_OFDM; } else { /* 5G */ TransmitSetting.field.MODE = MODE_CCK; } TransmitSetting.field.BW = BW_20; TransmitSetting.field.STBC = 0; TransmitSetting.field.ShortGI = 0; TransmitSetting.field.MCS = 0; TransmitSetting.field.ldpc = 0; transmit = &TransmitSetting; break; case SUBTYPE_PS_POLL: mac_info.hdr_len = sizeof (PSPOLL_FRAME); #ifdef RELEASE_EXCLUDE /* * HEC# WHQA_0017099 * When ERP protection enable, it will use CCK to protect and send out 20Mhz pkt. * if the pkt is use 40Mhz and Fixed BW, it will stuck in PSE and cannot be sendout. * the below patch will be removed after MT7603E2 */ #endif /* RELEASE_EXCLUDE */ tx_rate = (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS; transmit = &pAd->CommonCfg.MlmeTransmit; break; default: DBGPRINT(RT_DEBUG_ERROR, ("%s(): FIXME!!!Unexpected frame(Type=%d, SubType=%d) send to MgmtRing, need to assign the length!\n", __FUNCTION__, pHeader_802_11->FC.Type, pHeader_802_11->FC.SubType)); break; } } else { DBGPRINT(RT_DEBUG_ERROR, ("%s(): FIXME!!!Unexpected frame send to MgmtRing, need to assign the length!\n", __FUNCTION__)); } #else mac_info.Length = (SrcBufLen - TXINFO_SIZE - pAd->chipCap.TXWISize - TSO_SIZE); #endif /* MT7603 */ mac_info.PID = PID; mac_info.TxRate = tx_rate; mac_info.SpeEn = 1; mac_info.Preamble = LONG_PREAMBLE; #ifdef MT_MAC // TODO: shiang-MT7603 mac_info.q_idx = Q_IDX_AC4; #endif /* MT_MAC */ /* PCI use Miniport to send NULL frame and need to add NULL frame TxS control here to enter PSM */ #ifdef CONFIG_STA_SUPPORT #if defined(MT_MAC) && (defined(STA_LP_PHASE_1_SUPPORT) || defined(STA_LP_PHASE_2_SUPPORT)) if ((pHeader_802_11->FC.SubType == SUBTYPE_DATA_NULL) || (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) { /* PCI use Miniport to send NULL frame and need to add NULL frame TxS control here to enter PSM */ mac_info.PID = (pHeader_802_11->FC.PwrMgmt == PWR_ACTIVE) ? PID_NULL_FRAME_PWR_ACTIVE : PID_NULL_FRAME_PWR_SAVE; if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && RTMPEnterPsmNullBitStatus(&pAd->StaCfg.PwrMgmt)) { DBGPRINT(RT_DEBUG_TRACE, ("%s(line=%d)\n", __FUNCTION__, __LINE__)); RTMPClearEnterPsmNullBit(&pAd->StaCfg.PwrMgmt); TxSTypeCtlPerPkt(pAd, mac_info.PID, TXS_FORMAT0, FALSE, TRUE, FALSE, TXS_DUMP_REPEAT); } else { DBGPRINT(RT_DEBUG_TRACE, ("%s(line=%d)\n", __FUNCTION__, __LINE__)); TxSTypeCtlPerPkt(pAd, mac_info.PID, TXS_FORMAT0, FALSE, FALSE, FALSE, TXS_DUMP_REPEAT); } } #endif /* MT_MAC */ #endif /* CONFIG_STA_SUPPORT */ DBGPRINT(RT_DEBUG_TRACE, ("%s(line=%d), mac_info.PsmBySw(%d)\n", __FUNCTION__, __LINE__, mac_info.PsmBySw)); if(pCfg80211_ctrl->TxStatusInUsed && pCfg80211_ctrl->IsNeedTxStatus) { DBGPRINT(RT_DEBUG_TRACE, ("%s %d, PID (%d)\n", __FUNCTION__, __LINE__, mac_info.PID)); TxSTypeCtlPerPkt(pAd, mac_info.PID, TXS_FORMAT0, FALSE, TRUE, FALSE, TXS_DUMP_REPEAT); } else TxSTypeCtlPerPkt(pAd, mac_info.PID, TXS_FORMAT0, FALSE, FALSE, FALSE, TXS_DUMP_REPEAT); #ifdef SOFT_SOUNDING if (((pHeader_802_11->FC.Type == FC_TYPE_DATA) && (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) && pMacEntry && (pMacEntry->snd_reqired == TRUE)) { wcid = RESERVED_WCID; tx_rate = (UCHAR)pMacEntry->snd_rate.field.MCS; transmit = &pMacEntry->snd_rate; mac_info.Txopmode = IFS_PIFS; write_tmac_info(pAd, tmac_info, &mac_info, transmit); pMacEntry->snd_reqired = FALSE; DBGPRINT(RT_DEBUG_OFF, ("%s():Kick Sounding to %02x:%02x:%02x:%02x:%02x:%02x, dataRate(PhyMode:%s, BW:%sHz, %dSS, MCS%d)\n", __FUNCTION__, PRINT_MAC(pMacEntry->Addr), get_phymode_str(transmit->field.MODE), get_bw_str(transmit->field.BW), (transmit->field.MCS>>4) + 1, (transmit->field.MCS & 0xf))); } else #endif /* SOFT_SOUNDING */ { mac_info.Txopmode = IFS_BACKOFF; write_tmac_info(pAd, tmac_info, &mac_info, transmit); #ifdef SPECIFIC_TX_POWER_SUPPORT #if defined(RTMP_MAC) || defined(RLT_MAC) if (pMacEntry == NULL) { TXWI_STRUC *pFirstTxWI = (TXWI_STRUC *)tmac_info; #ifdef RTMP_MAC if (pAd->chipCap.hif_type == HIF_RTMP) pFirstTxWI->TXWI_O.TxPwrAdj = TxPwrAdj; #endif /* RTMP_MAC */ #ifdef RLT_MAC if (pAd->chipCap.hif_type == HIF_RLT) pFirstTxWI->TXWI_N.TxPwrAdj = TxPwrAdj; #endif /* RLT_MAC */ } #endif /* defined(RTMP_MAC) || defined(RLT_MAC) */ #endif /* SPECIFIC_TX_POWER_SUPPORT */ } //+++Add by shiang for debug #if 0 //defined(MT7603) || defined(MT7628) // TODO: shiang-7603 hex_dump("MgmtFrame", pSrcBufVA, SrcBufLen); hex_dump("TMAC_Info", tmac_info, sizeof(TMAC_TXD_L)); #endif /* MT7603 */ //---Add by shiang for debug //+++Add by shiang for debug if ((pHeader_802_11->FC.Type == FC_TYPE_CNTL) && (pHeader_802_11->FC.SubType == SUBTYPE_VHT_NDPA)) { DBGPRINT(RT_DEBUG_TRACE, ("%s(): Send VhtNDPA to peer(wcid=%d, pMacEntry=%p) with Mode=%d, txRate=%d, BW=%d\n", __FUNCTION__, wcid, pMacEntry, transmit->field.MODE, tx_rate, transmit->field.BW)); hex_dump("VHT_NDPA raw data", pSrcBufVA, SrcBufLen); dump_tmac_info(pAd, tmac_info); } //---Add by shiang for debug #ifdef RT_BIG_ENDIAN RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); #ifdef MT_MAC if (pAd->chipCap.hif_type == HIF_MT) { MTMacInfoEndianChange(pAd, tmac_info, TYPE_TMACINFO, sizeof(TMAC_TXD_L)); } #endif #if defined(RTMP_MAC) || defined(RLT_MAC) if (pAd->chipCap.hif_type == HIF_RTMP || pAd->chipCap.hif_type == HIF_RLT) { RTMPWIEndianChange(pAd, tmac_info, TYPE_TXWI); } #endif #endif #ifdef CONFIG_TSO_SUPPORT // TODO: shiang-6590, for mgmt frame, we don't need to fill any fields of TSO_INFO //rlt_tso_info_write(pAd, tinfo, TX_BLK * pTxBlk); #endif /* CONFIG_TSO_SUPPORT */ /* Now do hardware-depened kick out.*/ HAL_KickOutMgmtTx(pAd, mac_info.q_idx, pPacket, pSrcBufVA, SrcBufLen); #ifdef CONFIG_HOTSPOT_R2 if (RTMP_GET_PACKET_DISASSOC(pPacket)) { if (((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_DISASSOC)) || ((pHeader_802_11->FC.Type == FC_TYPE_MGMT) && (pHeader_802_11->FC.SubType == SUBTYPE_DEAUTH))) { pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); } if ((pMacEntry) && (pMacEntry->IsKeep == 1)) MacTableDeleteEntry(pAd, pMacEntry->Aid, pMacEntry->Addr); } #endif /* CONFIG_HOTSPOT_R2 */ /* Make sure to release MGMT ring resource*/ /* if (!IrqState)*/ RTMP_IRQ_UNLOCK(&pAd->MgmtRingLock, Flags); return NDIS_STATUS_SUCCESS; } /******************************************************************************** New DeQueue Procedures. ********************************************************************************/ #define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ do{ \ if (bIntContext == FALSE) \ RTMP_IRQ_LOCK((lock), IrqFlags); \ }while(0) #define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ do{ \ if (bIntContext == FALSE) \ RTMP_IRQ_UNLOCK((lock), IrqFlags); \ }while(0) /* ======================================================================== Tx Path design algorithm: Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), Specific Packet Type. Following show the classification rule and policy for each kinds of packets. Classification Rule=> Multicast: (*addr1 & 0x01) == 0x01 Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. 11N Rate : If peer support HT (1).AMPDU -- If TXBA is negotiated. (2).AMSDU -- If AMSDU is capable for both peer and ourself. *). AMSDU can embedded in a AMPDU, but now we didn't support it. (3).Normal -- Other packets which send as 11n rate. B/G Rate : If peer is b/g only. (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 (2).Normal -- Other packets which send as b/g rate. Fragment: The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. Classified Packet Handle Rule=> Multicast: No ACK, pTxBlk->bAckRequired = FALSE; No WMM, pTxBlk->bWMM = FALSE; No piggyback, pTxBlk->bPiggyBack = FALSE; Force LowRate, pTxBlk->bForceLowRate = TRUE; Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use the same policy to handle it. Force LowRate, pTxBlk->bForceLowRate = TRUE; 11N Rate : No piggyback, pTxBlk->bPiggyBack = FALSE; (1).AMSDU pTxBlk->bWMM = TRUE; (2).AMPDU pTxBlk->bWMM = TRUE; (3).Normal B/G Rate : (1).ARALINK (2).Normal ======================================================================== */ static UCHAR TxPktClassification(RTMP_ADAPTER *pAd, PNDIS_PACKET pPacket, TX_BLK *pTxBlk) { UCHAR TxFrameType = TX_LEGACY_FRAME; UCHAR Wcid; MAC_TABLE_ENTRY *pMacEntry = NULL; STA_TR_ENTRY *tr_entry = NULL; if (RTMP_GET_PACKET_TXTYPE(pPacket) == TX_MCAST_FRAME) return TX_MCAST_FRAME; /* Handle for unicast packets */ Wcid = RTMP_GET_PACKET_WCID(pPacket); tr_entry = &pAd->MacTab.tr_entry[Wcid]; if (Wcid < MAX_LEN_OF_MAC_TABLE) pMacEntry = &pAd->MacTab.Content[Wcid]; else pMacEntry = &pAd->MacTab.Content[MCAST_WCID]; pTxBlk->wdev = tr_entry->wdev; /* It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame*/ if ((RTMP_GET_PACKET_TXTYPE(pPacket) == TX_LEGACY_FRAME) || (pMacEntry->PsMode == PWR_SAVE)) TxFrameType = TX_LEGACY_FRAME; #ifdef DOT11_N_SUPPORT else if (IS_HT_RATE(pMacEntry)) { #ifdef VHT_TXBF_SUPPORT // TODO: shiang-usw, we should use cb here instead of mark the data type! if (pMacEntry->TxSndgType == SNDG_TYPE_NDP && IS_VHT_RATE(pMacEntry)) { #error TxFrameType = TX_NDPA_FRAME; DBGPRINT(RT_DEBUG_OFF, ("%s():Err!! fix me for this!!\n", __FUNCTION__)); } #endif if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) TxFrameType = TX_LEGACY_FRAME; else #ifdef UAPSD_SUPPORT if (RTMP_GET_PACKET_EOSP(pPacket)) TxFrameType = TX_LEGACY_FRAME; else #endif /* UAPSD_SUPPORT */ #ifdef WFA_VHT_PF if (pAd->force_amsdu == TRUE) return TX_AMSDU_FRAME; else #endif /* WFA_VHT_PF */ if ((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) return TX_AMPDU_FRAME; else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED) #ifdef CONFIG_TSO_SUPPORT && (!(RTMP_GET_PKT_CSO(pPacket) || RTMP_GET_PKT_TSO(pPacket))) #endif /* CONFIG_TSO_SUPPORT */ ) return TX_AMSDU_FRAME; } #endif /* DOT11_N_SUPPORT */ else { /* it's a legacy b/g packet.*/ if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE))) #ifdef CONFIG_TSO_SUPPORT && (!(RTMP_GET_PKT_CSO(pPacket) || RTMP_GET_PKT_TSO(pPacket))) #endif /* CONFIG_TSO_SUPPORT */ ) { TxFrameType = TX_RALINK_FRAME; } } #ifdef RELEASE_EXCLUDE /* IOT issue with Intel WiFi-Link 5100/5300 (v.12.2.0.11 - 2008/11/17) : When AP set fragment threshold as 256 in HT-mode, the intel STA can't complete EAP-certification with RADIUS server. [solution] : After the TX BA is built, the frame shall not be fragmented even if none-AMPDU frame. Add new condition to fix this issue ((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) == 0) Currently, our fragment only support when a unicast packet send as: NOT-ARALINK, NOT-AMSDU and NOT-AMPDU */ #endif /* RELEASE_EXCLUDE */ if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME) #ifdef DOT11_N_SUPPORT && ((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) == 0) #endif /* DOT11_N_SUPPORT */ ) TxFrameType = TX_FRAG_FRAME; return TxFrameType; } BOOLEAN RTMP_FillTxBlkInfo(RTMP_ADAPTER *pAd, TX_BLK *pTxBlk) { PACKET_INFO PacketInfo; PNDIS_PACKET pPacket; MAC_TABLE_ENTRY *pMacEntry = NULL; pPacket = pTxBlk->pPacket; RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); #ifdef TX_PKT_SG NdisMoveMemory( &pTxBlk->pkt_info, &PacketInfo, sizeof(PacketInfo)); #endif /* TX_PKT_SG */ pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); pTxBlk->wdev_idx = RTMP_GET_PACKET_WDEV(pPacket); pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); pTxBlk->FrameGap = IFS_HTTXOP; #ifdef CONFIG_AP_SUPPORT pTxBlk->pMbss = NULL; #endif /* CONFIG_AP_SUPPORT */ if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); else TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); #ifdef WAPI_SUPPORT /* Check if this is an WPI data frame*/ if ((RTMPIsWapiCipher(pAd, pTxBlk->wdev_idx) == TRUE) && (RTMP_GET_PACKET_WAI(pTxBlk->pPacket) == FALSE)) TX_BLK_SET_FLAG(pTxBlk, fTX_bWPIDataFrame); else TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWPIDataFrame); #endif /* WAPI_SUPPORT */ if (pTxBlk->tr_entry->EntryType == ENTRY_CAT_MCAST) { pTxBlk->pMacEntry = NULL; TX_BLK_SET_FLAG(pTxBlk, fTX_ForceRate); { #ifdef MCAST_RATE_SPECIFIC PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; else #endif /* MCAST_RATE_SPECIFIC */ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; } /* AckRequired = FALSE, when broadcast packet in Adhoc mode.*/ TX_BLK_CLEAR_FLAG(pTxBlk, (fTX_bAckRequired | fTX_bAllowFrag | fTX_bWMM)); if (RTMP_GET_PACKET_MOREDATA(pPacket)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); } #ifdef ETH_CONVERT_SUPPORT if (ADHOC_ON(pAd)) { /* If we are running as Ethernet Converter, update MAT DataBase and duplicant the packet if necessary.*/ if (pAd->EthConvert.ECMode & ETH_CONVERT_MODE_DONGLE) { PNDIS_PACKET donglePkt; if(!NdisEqualMemory(pAd->CurrentAddress, (GET_OS_PKT_DATAPTR(pPacket) + 6), MAC_ADDR_LEN)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bDonglePkt); #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_INFO, ("@@ %s: Dongle Packet)\n", __FUNCTION__)); #endif /* RELEASE_EXCLUDE */ } /* For each tx packet, update our MAT convert engine databases.*/ donglePkt = (PNDIS_PACKET)MATEngineTxHandle(pAd, pPacket, 0, pTxBlk->OpMode); if(donglePkt) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); pPacket = donglePkt; RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); pTxBlk->pPacket = donglePkt; } } } #endif /* ETH_CONVERT_SUPPORT */ } else { pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; pMacEntry = pTxBlk->pMacEntry; #ifdef CONFIG_AP_SUPPORT pTxBlk->pMbss = pMacEntry->pMbss; #endif /* CONFIG_AP_SUPPORT */ //YF MCC #ifdef MULTI_WMM_SUPPORT if (IS_ENTRY_APCLI(pMacEntry)) { pTxBlk->QueIdx = EDCA_WMM1_AC0_PIPE; printk("%s(): QIdx %d\n", __FUNCTION__, pTxBlk->QueIdx); } #endif /* MULTI_WMM_SUPPORT */ /* For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK.*/ #ifdef MULTI_WMM_SUPPORT if (pTxBlk->QueIdx >= EDCA_WMM1_AC0_PIPE) { if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx - EDCA_WMM1_AC0_PIPE] != NORMAL_ACK) TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); else TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); } else #endif /* MULTI_WMM_SUPPORT */ { if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); else TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); } #ifdef CONFIG_STA_SUPPORT #ifdef XLINK_SUPPORT if ((pAd->OpMode == OPMODE_STA) && (ADHOC_ON(pAd)) /*&& (RX_FILTER_TEST_FLAG(pAd, fRX_FILTER_ACCEPT_PROMISCUOUS))*/) { if (pAd->StaCfg.PSPXlink) TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); } #endif /* XLINK_SUPPORT */ #endif /* CONFIG_STA_SUPPORT */ #ifdef MESH_SUPPORT if (IS_ENTRY_MESH(pMacEntry)) { PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); TX_BLK_SET_FLAG(pTxBlk, fTX_bMeshEntry); if (RTMP_GET_MESH_SOURCE(pPacket) == MESH_PROXY) { UINT8 MeshRouteId = RTMP_GET_MESH_ROUTE_ID(pPacket); /* B/Mcast packet.*/ if ((MeshRouteId == BMCAST_ROUTE_ID) && (*pSrcBufVA & 0x01)) pTxBlk->pMeshDA = pSrcBufVA; /* Mesh DA*/ else { PUCHAR pMeshDA = PathRouteAddrSearch(pAd, MeshRouteId); if (pMeshDA) pTxBlk->pMeshDA = pMeshDA; /* Mesh DA*/ else return FALSE; } } else /* MESH_ORIGIN, MESH_FORWARD packet.*/ pTxBlk->pMeshDA = pSrcBufVA; /* Mesh DA*/ /* If both of peer and us support WMM, enable it.*/ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); } else #endif /* MESH_SUPPORT */ { #ifdef CONFIG_AP_SUPPORT #if defined(P2P_SUPPORT) || defined(RT_CFG80211_P2P_SUPPORT) || defined(CFG80211_MULTI_STA) if (pTxBlk->OpMode == OPMODE_AP) #else IF_DEV_CONFIG_OPMODE_ON_AP(pAd) #endif /* P2P_SUPPORT || RT_CFG80211_P2P_SUPPORT || CFG80211_MULTI_STA */ { #ifdef WDS_SUPPORT if(IS_ENTRY_WDS(pMacEntry)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bWDSEntry); } else #endif /* WDS_SUPPORT */ #ifdef APCLI_SUPPORT if(IS_ENTRY_APCLI(pMacEntry)) { #ifdef MAT_SUPPORT PNDIS_PACKET apCliPkt = NULL; #ifdef MAC_REPEATER_SUPPORT if ((pMacEntry->bReptCli) && (pAd->ApCfg.bMACRepeaterEn)) { UCHAR tmpIdx; pAd->MatCfg.bMACRepeaterEn = pAd->ApCfg.bMACRepeaterEn; if(pAd->ApCfg.MACRepeaterOuiMode != 1) { tmpIdx = (64 + (MAX_EXT_MAC_ADDR_SIZE * pMacEntry->func_tb_idx) + pMacEntry->MatchReptCliIdx); // TODO: shiang-lock, fix ME! apCliPkt = (PNDIS_PACKET)MATEngineTxHandle(pAd, pPacket, tmpIdx, pTxBlk->OpMode); } } else #endif /* MAC_REPEATER_SUPPORT */ { /* For each tx packet, update our MAT convert engine databases.*/ /* CFG_TODO */ apCliPkt = (PNDIS_PACKET)MATEngineTxHandle(pAd, pPacket, pMacEntry->func_tb_idx, pTxBlk->OpMode); } if(apCliPkt) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); pPacket = apCliPkt; RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); pTxBlk->pPacket = apCliPkt; } #endif /* MAT_SUPPORT */ pTxBlk->pApCliEntry = &pAd->ApCfg.ApCliTab[pMacEntry->func_tb_idx]; TX_BLK_SET_FLAG(pTxBlk, fTX_bApCliPacket); #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_INFO, ("RTMP_FillTxBlkInfo: ApClient - Rxwcid(%d), wdev_idx(%d))\n",pTxBlk->Wcid, pTxBlk->wdev_idx)); #endif /* RELEASE_EXCLUDE */ } else #endif /* APCLI_SUPPORT */ #ifdef CLIENT_WDS if (IS_ENTRY_CLIWDS(pMacEntry)) { PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); PUCHAR pSA = GET_OS_PKT_DATAPTR(pPacket) + MAC_ADDR_LEN; if (((pMacEntry->func_tb_idx < MAX_MBSSID_NUM(pAd)) && !MAC_ADDR_EQUAL(pSA, pAd->ApCfg.MBSSID[pMacEntry->func_tb_idx].Bssid)) || !MAC_ADDR_EQUAL(pDA, pMacEntry->Addr) ) { TX_BLK_SET_FLAG(pTxBlk, fTX_bClientWDSFrame); } } else #endif /* CLIENT_WDS */ if (IS_ENTRY_CLIENT(pMacEntry)) { } else return FALSE; /* If both of peer and us support WMM, enable it.*/ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); } #endif /* CONFIG_AP_SUPPORT */ #ifdef CONFIG_STA_SUPPORT #if defined(P2P_SUPPORT) || defined(RT_CFG80211_P2P_SUPPORT) || defined(CFG80211_MULTI_STA) if (pTxBlk->OpMode == OPMODE_STA) #else IF_DEV_CONFIG_OPMODE_ON_STA(pAd) #endif /* P2P_SUPPORT || RT_CFG80211_P2P_SUPPORT || CFG80211_MULTI_STA */ { #if defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) if(IS_ENTRY_TDLS(pMacEntry)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bTdlsEntry); } #endif /* DOT11Z_TDLS_SUPPORT */ #ifdef ETH_CONVERT_SUPPORT /* If we are running as Ethernet Converter, update MAT DataBase and duplicant the packet if necessary.*/ if (pAd->EthConvert.ECMode & ETH_CONVERT_MODE_DONGLE) { PNDIS_PACKET donglePkt; if(!NdisEqualMemory(pAd->CurrentAddress, (GET_OS_PKT_DATAPTR(pPacket) + 6), MAC_ADDR_LEN)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bDonglePkt); #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_INFO, ("%s(): Dongle Packet)\n", __FUNCTION__)); #endif /* RELEASE_EXCLUDE */ } /* For each tx packet, update our MAT convert engine databases.*/ donglePkt = (PNDIS_PACKET)MATEngineTxHandle(pAd, pPacket, 0, pTxBlk->OpMode); if(donglePkt) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); pPacket = donglePkt; RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); pTxBlk->pPacket = donglePkt; } } #endif /* ETH_CONVERT_SUPPORT */ /* If support WMM, enable it.*/ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); } #endif /* CONFIG_STA_SUPPORT */ } if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) { if ( ((RTMP_GET_PACKET_LOWRATE(pPacket)) #ifdef UAPSD_SUPPORT && (!(pMacEntry && (pMacEntry->bAPSDFlagSPStart))) #endif /* UAPSD_SUPPORT */ ) || ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1)) ) { /* Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. */ pTxBlk->pTransmit->field.MODE = MODE_CCK; pTxBlk->pTransmit->field.iTxBF = 0; pTxBlk->pTransmit->field.eTxBF = 0; pTxBlk->pTransmit->field.STBC = 0; pTxBlk->pTransmit->field.ShortGI = 0; pTxBlk->pTransmit->field.BW = 0; pTxBlk->pTransmit->field.MCS = 0; TX_BLK_SET_FLAG(pTxBlk, fTX_ForceRate); #ifdef WAPI_SUPPORT /* According to WAPIA certification description, WAI packets can not include QoS header */ if (RTMP_GET_PACKET_WAI(pTxBlk->pPacket)) { TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); } #endif /* WAPI_SUPPORT */ #ifdef DOT11_N_SUPPORT /* Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it? */ if (IS_HT_STA(pTxBlk->pMacEntry) && (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) { TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); } #endif /* DOT11_N_SUPPORT */ } #ifdef DOT11_N_SUPPORT if ( (IS_HT_RATE(pMacEntry) == FALSE) && (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) { /* Currently piggy-back only support when peer is operate in b/g mode.*/ TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); } #endif /* DOT11_N_SUPPORT */ if (RTMP_GET_PACKET_MOREDATA(pPacket)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); } #ifdef UAPSD_SUPPORT if (RTMP_GET_PACKET_EOSP(pPacket)) { TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); } #endif /* UAPSD_SUPPORT */ } else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) { TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); } pMacEntry->DebugTxCount++; } #ifdef CONFIG_TSO_SUPPORT if (RTMP_GET_PKT_CSO(pPacket) || RTMP_GET_PKT_TSO(pPacket)) { TSO_INFO *info = &pTxBlk->tso_info; if (RTMP_GET_PKT_TSO(pPacket)) { DBGPRINT(RT_DEBUG_TRACE, ("%s(): Transmit a TSO/CSO frame:\n", __FUNCTION__)); DBGPRINT(RT_DEBUG_TRACE, ("\tcso/tso=%d:%d, is_tcp=%d, ips=%d, tups=%d, mss=%d!\n", RTMP_GET_PKT_CSO(pPacket), RTMP_GET_PKT_TSO(pPacket), RTMP_GET_PKT_TCP(pPacket), RTMP_GET_PKT_IPS(pPacket), RTMP_GET_PKT_TUPS(pPacket), RTMP_GET_PKT_MSS(pPacket))); } pTxBlk->naf_type = RTMP_GET_PKT_NAF_TYPE(pPacket); info->ips = RTMP_GET_PKT_IPS(pPacket); info->tups = RTMP_GET_PKT_TUPS(pPacket); info->mss = RTMP_GET_PKT_MSS(pPacket); if (RTMP_GET_PKT_TCP(pPacket)) info->tcp = 1; } #endif /* CONFIG_TSO_SUPPORT */ pAd->LastTxRate = (USHORT)pTxBlk->pTransmit->word; return TRUE; } BOOLEAN CanDoAggregateTransmit(RTMP_ADAPTER *pAd, NDIS_PACKET *pPacket, TX_BLK *pTxBlk) { int minLen = LENGTH_802_3; /*DBGPRINT(RT_DEBUG_TRACE, ("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType));*/ if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) return FALSE; if (RTMP_GET_PACKET_DHCP(pPacket) || RTMP_GET_PACKET_EAPOL(pPacket) || RTMP_GET_PACKET_WAI(pPacket) #ifdef CONFIG_TSO_SUPPORT || (RTMP_GET_PKT_CSO(pPacket) || RTMP_GET_PKT_TSO(pPacket)) #endif /* CONFIG_TSO_SUPPORT */ ) return FALSE; /* Make sure the first packet has non-zero-length data payload */ if (RTMP_GET_PACKET_VLAN(pPacket)) minLen += LENGTH_802_1Q; /* VLAN tag */ else if (RTMP_GET_PACKET_LLCSNAP(pPacket)) minLen += 8; /* SNAP hdr Len*/ if (minLen >= GET_OS_PKT_LEN(pPacket)) return FALSE; if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) { /* For AMSDU, allow the packets with total length < max-amsdu size*/ return FALSE; } if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && (pTxBlk->TxPacketList.Number == 2)) { /* For RALINK-Aggregation, allow two frames in one batch.*/ return FALSE; } #ifdef CONFIG_STA_SUPPORT if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) /* must be unicast to AP*/ return TRUE; else #endif /* CONFIG_STA_SUPPORT */ #ifdef CONFIG_AP_SUPPORT /* CFG_TODO */ if ((MAC_ADDR_EQUAL(GET_OS_PKT_DATAPTR(pTxBlk->pPacket), GET_OS_PKT_DATAPTR(pPacket))) && (pAd->OpMode == OPMODE_AP)) /* unicast to same STA*/ return TRUE; else #endif /* CONFIG_AP_SUPPORT */ return FALSE; } VOID rtmp_sta_txq_dump(RTMP_ADAPTER *pAd, STA_TR_ENTRY *tr_entry, INT qidx) { ULONG IrqFlags = 0; QUEUE_ENTRY *entry; RTMP_IRQ_LOCK(&pAd->irq_lock /*&tr_entry->txq_lock[qidx]*/, IrqFlags); entry = tr_entry->tx_queue[qidx].Head; DBGPRINT(RT_DEBUG_OFF, ("\nDump TxQ[%d] of TR_ENTRY(ID:%d, MAC:%02x:%02x:%02x:%02x:%02x:%02x): %s, enq_cap=%d\n", qidx, tr_entry->wcid, PRINT_MAC(tr_entry->Addr), entry == NULL ? "Empty" : "HasEntry", tr_entry->enq_cap)); while(entry != NULL) { DBGPRINT(RT_DEBUG_OFF, (" 0x%p ", entry)); entry = entry->Next; if (entry == NULL) { DBGPRINT(RT_DEBUG_OFF, ("\n")); } }; RTMP_IRQ_UNLOCK(&pAd->irq_lock /* &tr_entry->txq_lock[qidx]*/, IrqFlags); } VOID rtmp_tx_swq_dump(RTMP_ADAPTER *pAd, INT qidx) { ULONG IrqFlags = 0; INT deq_id, enq_id; RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); deq_id = pAd->tx_swq[qidx].deqIdx; enq_id = pAd->tx_swq[qidx].enqIdx; DBGPRINT(RT_DEBUG_OFF, ("\nDump TxSwQ[%d]: DeqIdx=%d, EnqIdx=%d, %s\n", qidx, deq_id, enq_id, (pAd->tx_swq[qidx].swq[deq_id] == 0 ? "Empty" : "HasEntry"))); for (; deq_id != enq_id; (deq_id = (deq_id == 511 ? 0 : deq_id+1))) { DBGPRINT(RT_DEBUG_OFF, (" %d ", pAd->tx_swq[qidx].swq[deq_id])); } RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); DBGPRINT(RT_DEBUG_OFF, ("\n")); } VOID rtmp_ps_init(RTMP_ADAPTER *pAd) { UCHAR i = 0; /*initial PS Token Queue*/ DlListInit(&pAd->psTokenQueue); for(i=0;ipsTokenQueue,struct WCID_TABLE,list) { DBGPRINT(RT_DEBUG_LOUD,("%d\t",pEntry->wcid)); } DBGPRINT(RT_DEBUG_LOUD,("\n")); } INT rtmp_ps_enq(RTMP_ADAPTER *pAd, STA_TR_ENTRY *tr_entry) { struct WCID_TABLE *pEntry; if(tr_entry->wcid >= MAX_LEN_OF_TR_TABLE ) { return TRUE; } pEntry = &wcid_table[tr_entry->wcid]; if( tr_entry->PsTokenFlag != PS_TOKEN_STAT_WCID_PKT) { tr_entry->PsTokenFlag = PS_TOKEN_STAT_WCID_PKT; DlListAdd(&pAd->psTokenQueue,&pEntry->list); DBGPRINT(RT_DEBUG_LOUD, ("enqueue PS fifo token to Token Queue, WCID: %d,%d.\n", tr_entry->wcid,pEntry->wcid)); }else { DBGPRINT(RT_DEBUG_LOUD, ("not need enqueue WCID: %d.\n", tr_entry->wcid)); } /*rtmp_ps_listforAll(pAd);*/ return TRUE; } INT rtmp_psDeq_req(RTMP_ADAPTER *pAd) { STA_TR_ENTRY *tr_entry = NULL; struct WCID_TABLE *psEntry = NULL; struct tx_swq_fifo *fifo_swq; INT32 cnt = 0, i = 0; INT32 capCount=0; /*remove first psToken now, should check WCID requeue when report*/ do { psEntry = DlListFirst(&pAd->psTokenQueue,struct WCID_TABLE,list); if(psEntry==NULL) { break; } DlListDel(&psEntry->list); if( psEntry->wcid >= MAX_LEN_OF_TR_TABLE) { DBGPRINT(RT_DEBUG_ERROR,("%s(): wcid >MAX_LEN_OF_TR_TABLE \n",__FUNCTION__)); continue; } tr_entry = &pAd->MacTab.tr_entry[psEntry->wcid]; if(!tr_entry) { DBGPRINT(RT_DEBUG_ERROR,("%s(): tr_entry is NULL \n",__FUNCTION__)); continue; } if(tr_entry->enqCount <=0) { tr_entry->PsTokenFlag = PS_TOKEN_STAT_IDLE; DBGPRINT(RT_DEBUG_LOUD,("%s(): ps token flag =%d,wcid =%d\n",__FUNCTION__,tr_entry->PsTokenFlag,psEntry->wcid)); continue; } tr_entry->PsTokenFlag = PS_TOKEN_STAT_PKT; /*enqueue wcid to sw fifo queue*/ fifo_swq = &pAd->tx_swq[QID_AC_BE]; cnt = tr_entry->tx_queue[QID_AC_BE].Number ; capCount = (fifo_swq->enqIdx >=fifo_swq->deqIdx) ? (TX_SWQ_FIFO_LEN-fifo_swq->enqIdx+fifo_swq->deqIdx) : (fifo_swq->deqIdx-fifo_swq->enqIdx); cnt = cnt > capCount ? capCount : cnt; for(i=0;iswq[fifo_swq->enqIdx] != 0) || !(tr_entry->enq_cap)) { rtmp_ps_enq(pAd,tr_entry); DBGPRINT(RT_DEBUG_LOUD,("%s(): fifo is full,flag:%d,enqId:%d,deqId:%d, cap: %d \n",__FUNCTION__,tr_entry->PsTokenFlag,fifo_swq->enqIdx,fifo_swq->deqIdx,tr_entry->enq_cap)); break; } fifo_swq->swq[fifo_swq->enqIdx] = tr_entry->wcid; INC_RING_INDEX(fifo_swq->enqIdx, TX_SWQ_FIFO_LEN); } DBGPRINT(RT_DEBUG_LOUD,("%s(): deq for PS retrieve and PSM change. WCID: %d,stat: %d\n",__FUNCTION__,tr_entry->wcid,tr_entry->PsTokenFlag)); return TRUE; }while(TRUE); return TRUE; } INT rtmp_psDeq_report(RTMP_ADAPTER *pAd,struct dequeue_info *info) { STA_TR_ENTRY *tr_entry = NULL; tr_entry = &pAd->MacTab.tr_entry[info->target_wcid]; if(tr_entry->enqCount > 0 && tr_entry->PsTokenFlag == PS_TOKEN_STAT_PKT) { rtmp_ps_enq(pAd,tr_entry); DBGPRINT(RT_DEBUG_LOUD,("%s(): After DeqReport, re-enq PsToken, WCID: %d,STAT: %d\n",__FUNCTION__,info->target_wcid,tr_entry->PsTokenFlag)); }else if(tr_entry->enqCount <= 0 && tr_entry->PsTokenFlag != PS_TOKEN_STAT_IDLE) { tr_entry->PsTokenFlag = PS_TOKEN_STAT_IDLE; DBGPRINT(RT_DEBUG_LOUD,("%s(): After DeqReport, Abort PsToken, WCID: %d,STAT: %d\n",__FUNCTION__,info->target_wcid,tr_entry->PsTokenFlag)); } return TRUE; } INT rtmp_tx_swq_init(RTMP_ADAPTER *pAd) { ULONG IrqFlags = 0; RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); NdisZeroMemory(pAd->tx_swq, sizeof(pAd->tx_swq)); rtmp_ps_init(pAd); RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); return TRUE; } INT rtmp_tx_swq_exit(RTMP_ADAPTER *pAd, UCHAR wcid) { UCHAR ring_idx, wcid_start, wcid_end; STA_TR_ENTRY *tr_entry; ULONG IrqFlags = 0; PNDIS_PACKET pPacket; QUEUE_ENTRY *pEntry; QUEUE_HEADER *pQueue; if (wcid == WCID_ALL) { wcid_start = 0; wcid_end = MAX_LEN_OF_TR_TABLE; } else { if (wcid < MAX_LEN_OF_TR_TABLE) wcid_start = wcid_end = wcid; else { DBGPRINT(RT_DEBUG_OFF, ("%s():Invalid WCID[%d]\n", __FUNCTION__, wcid)); return FALSE; } } for (wcid = wcid_start; wcid <= wcid_end; wcid++) { tr_entry = &pAd->MacTab.tr_entry[wcid]; if (IS_ENTRY_NONE(tr_entry)) continue; // TODO: shiang-usw, protect "tr_entry->enq_cap" here !! for (ring_idx = 0; ring_idx < WMM_QUE_NUM; ring_idx++) { RTMP_IRQ_LOCK(&pAd->irq_lock /* &tr_entry->txq_lock[ring_idx] */, IrqFlags); pQueue = &tr_entry->tx_queue[ring_idx]; while (pQueue->Head) { pEntry = RemoveHeadQueue(pQueue); TR_ENQ_COUNT_DEC(tr_entry); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); if (pPacket) RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } #if 0 //def MT_PS pQueue = &tr_entry->mt_ps_queue[ring_idx]; while (pQueue->Head) { pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); if (pPacket) RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } #endif /* MT_PS */ RTMP_IRQ_UNLOCK(&pAd->irq_lock /* &tr_entry->txq_lock[ring_idx] */, IrqFlags); } RTMP_IRQ_LOCK(&pAd->irq_lock /* &tr_entry->ps_queue_lock */, IrqFlags); pQueue = &tr_entry->ps_queue; while (pQueue->Head) { pEntry = RemoveHeadQueue(pQueue); pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); if (pPacket) RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); } RTMP_IRQ_UNLOCK(&pAd->irq_lock /*&tr_entry->ps_queue_lock*/, IrqFlags); } return TRUE; } INT rtmp_enq_req(RTMP_ADAPTER *pAd, PNDIS_PACKET pkt, UCHAR qidx, STA_TR_ENTRY *tr_entry, BOOLEAN FlgIsLocked,QUEUE_HEADER *pPktQueue) { ULONG IrqFlags = 0; BOOLEAN enq_done = FALSE; INT enq_idx = 0; struct tx_swq_fifo *fifo_swq; UCHAR occupied_wcid = 0; QUEUE_ENTRY *pEntry; UINT capCount = 0; PNDIS_PACKET tmpPkt; ASSERT(qidx < WMM_QUE_NUM); ASSERT((tr_entry->wcid != 0)); fifo_swq = &pAd->tx_swq[qidx]; if (FlgIsLocked == FALSE) RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); if ((tr_entry->enqCount > SQ_ENQ_NORMAL_MAX) &&(tr_entry->tx_queue[qidx].Number > SQ_ENQ_RESERVE_PERAC)) { occupied_wcid = fifo_swq->swq[enq_idx]; enq_done = FALSE; goto enq_end; } if(pkt) { enq_idx = fifo_swq->enqIdx; if ((fifo_swq->swq[enq_idx] == 0) && (tr_entry->enq_cap)) { InsertTailQueueAc(pAd, tr_entry, &tr_entry->tx_queue[qidx], PACKET_TO_QUEUE_ENTRY(pkt)); fifo_swq->swq[enq_idx] = tr_entry->wcid; INC_RING_INDEX(fifo_swq->enqIdx, TX_SWQ_FIFO_LEN); TR_ENQ_COUNT_INC(tr_entry); enq_done = TRUE; } else { occupied_wcid = fifo_swq->swq[enq_idx]; enq_done = FALSE; goto enq_end; } } /*check soft queue is enough*/ capCount = (fifo_swq->enqIdx >=fifo_swq->deqIdx) ? (TX_SWQ_FIFO_LEN-fifo_swq->enqIdx+fifo_swq->deqIdx) : (fifo_swq->deqIdx-fifo_swq->enqIdx); /*insert full queue to soft queue*/ if(pPktQueue && pPktQueue->Number <= capCount) { while(pPktQueue->Head) { pEntry = RemoveHeadQueue(pPktQueue); tmpPkt = QUEUE_ENTRY_TO_PACKET(pEntry); enq_idx = fifo_swq->enqIdx; if ((fifo_swq->swq[enq_idx] == 0) && (tr_entry->enq_cap)) { InsertTailQueueAc(pAd, tr_entry, &tr_entry->tx_queue[qidx],tmpPkt); fifo_swq->swq[enq_idx] = tr_entry->wcid; INC_RING_INDEX(fifo_swq->enqIdx, TX_SWQ_FIFO_LEN); TR_ENQ_COUNT_INC(tr_entry); enq_done = TRUE; } else { occupied_wcid = fifo_swq->swq[enq_idx]; enq_done = FALSE; goto enq_end; } } } enq_end: if (FlgIsLocked == FALSE) RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s():EnqPkt(%p) for WCID(%d) to tx_swq[%d].swq[%d] %s\n", __FUNCTION__, pkt, tr_entry->wcid, qidx, enq_idx, (enq_done ? "success" : "fail"))); if (enq_done == FALSE) { #ifdef DBG_DIAGNOSE if ((pAd->DiagStruct.inited) && (pAd->DiagStruct.wcid == tr_entry->wcid)) pAd->DiagStruct.diag_info[pAd->DiagStruct.ArrayCurIdx].enq_fall_cnt[qidx]++; #endif /* DBG_DIAGNOSE */ DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("\t FailedCause =>OccupiedWCID:%d,EnqCap:%d\n", occupied_wcid, tr_entry->enq_cap)); } if (0 /*(RTDebugFunc & DBG_FUNC_TXQ) == DBG_FUNC_TXQ*/) { DBGPRINT(RT_DEBUG_OFF, ("%s():EnqSuccess!\n", __FUNCTION__)); rtmp_tx_swq_dump(pAd, qidx); rtmp_sta_txq_dump(pAd, tr_entry, qidx); } /*add hook point for enqueue progress*/ RTMP_OS_TXRXHOOK_CALL(WLAN_TX_ENQUEUE_PROGRESS,NULL,qidx,fifo_swq); return enq_done; } INT rtmp_deq_req(RTMP_ADAPTER *pAd, INT cnt, struct dequeue_info *info) { CHAR deq_qid = 0, start_q, end_q; UCHAR deq_wcid; struct tx_swq_fifo *fifo_swq; STA_TR_ENTRY *tr_entry = NULL; if (!info->inited) { if (info->target_que < WMM_QUE_NUM) { info->start_q = info->target_que; info->end_q = info->target_que; } else { info->start_q = (WMM_QUE_NUM - 1); info->end_q = 0; } info->cur_q = info->start_q; if (info->target_wcid < MAX_LEN_OF_TR_TABLE) { info->pkt_cnt = cnt; info->full_qid[0] = FALSE; info->full_qid[1] = FALSE; info->full_qid[2] = FALSE; info->full_qid[3] = FALSE; } else { info->q_max_cnt[0] = (UCHAR)cnt; info->q_max_cnt[1] = (UCHAR)cnt; info->q_max_cnt[2] = (UCHAR)cnt; info->q_max_cnt[3] = (UCHAR)cnt; } info->inited = 1; } start_q = info->cur_q; end_q = info->end_q; /* wcid first */ if (info->target_wcid < MAX_LEN_OF_TR_TABLE) { if (info->pkt_cnt <= 0) { info->status = NDIS_STATUS_FAILURE; goto done; } deq_wcid = info->target_wcid; if (info->target_que >= WMM_QUE_NUM) { tr_entry = &pAd->MacTab.tr_entry[deq_wcid]; for (deq_qid = start_q; deq_qid >= end_q; deq_qid--) { if (info->full_qid[deq_qid] == FALSE && tr_entry->tx_queue[deq_qid].Number) break; } } else if (info->full_qid[info->target_que] == FALSE) { deq_qid = info->target_que; } else { info->status = NDIS_STATUS_FAILURE; goto done; } if (deq_qid >= 0) { info->cur_q = deq_qid; info->cur_wcid = deq_wcid; } else { info->status = NDIS_STATUS_FAILURE; } goto done; } /* Start from high queue, Don't need get "pAd->irq_lock" here becuse already get it by caller */ for (deq_qid = start_q; deq_qid >= end_q; deq_qid--) { fifo_swq = &pAd->tx_swq[deq_qid]; deq_wcid = fifo_swq->swq[fifo_swq->deqIdx]; if (deq_wcid == 0) { DBGPRINT(RT_DEBUG_LOUD | DBG_FUNC_TXQ, ("%s():tx_swq[%d] emtpy!\n", __FUNCTION__, deq_qid)); info->q_max_cnt[deq_qid] = 0; continue; } tr_entry = &pAd->MacTab.tr_entry[deq_wcid]; /* If any stations are in Psm, AP will skip this swq and increase deqIdx */ if (tr_entry->EntryType == ENTRY_CAT_MCAST) { /* Broadcast/Multicast */ if (pAd->MacTab.fAnyStationInPsm) { DBGPRINT(RT_DEBUG_LOUD | DBG_FUNC_TXQ, ("!!!B/MCast entry and AP in PSM\n")); fifo_swq->swq[fifo_swq->deqIdx] = 0; INC_RING_INDEX(fifo_swq->deqIdx, TX_SWQ_FIFO_LEN); continue; } } else { /* unicast */ if ((tr_entry->PsMode == PWR_SAVE) #ifdef MT_PS ||((tr_entry->ps_state != APPS_RETRIEVE_IDLE) && (tr_entry->ps_state != APPS_RETRIEVE_DONE)) #endif /* MT_PS */ ) { DBGPRINT(RT_DEBUG_LOUD | DBG_FUNC_TXQ, ("!!!STA in PSM\n")); fifo_swq->swq[fifo_swq->deqIdx] = 0; INC_RING_INDEX(fifo_swq->deqIdx, TX_SWQ_FIFO_LEN); if (tr_entry->tx_queue[deq_qid].Number > 0) TR_TOKEN_COUNT_INC(tr_entry, deq_qid); continue; } } if (info->q_max_cnt[deq_qid] > 0) { info->cur_q = deq_qid; info->cur_wcid = deq_wcid; info->pkt_cnt = info->q_max_cnt[deq_qid]; break; } else { /* Queue Quota full, go next! */ } } if (deq_qid < end_q) { info->cur_q = deq_qid; info->status = NDIS_STATUS_FAILURE; } done: rtmp_psDeq_req(pAd); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): DeqReq %s, Start/End/Cur Queue=%d/%d/%d\n", __FUNCTION__, (info->status == NDIS_STATUS_SUCCESS ? "success" : "fail"), info->start_q, info->end_q, info->cur_q)); if (info->status == NDIS_STATUS_SUCCESS) { tr_entry = &pAd->MacTab.tr_entry[info->cur_wcid]; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("\tdeq_info=>wcid:%d, qidx:%d, pkt_cnt:%d, q_max_cnt=%d, QueuedNum=%d\n", info->cur_wcid, info->cur_q, info->pkt_cnt, info->q_max_cnt[deq_qid], tr_entry->tx_queue[info->cur_q].Number)); } else { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("\tdeq_info=>wcid:%d, qidx:%d, pkt_cnt:%d\n", info->cur_wcid, info->cur_q, info->pkt_cnt)); } #ifdef DBG if (0){ // RTDebugFunc & DBG_FUNC_TXQ) { if (deq_qid >= 0) { // cannot call this here because we already get lock but this function will try lock again! rtmp_tx_swq_dump(pAd, deq_qid); if (deq_wcid < MAX_LEN_OF_TR_TABLE) rtmp_sta_txq_dump(pAd, &pAd->MacTab.tr_entry[deq_wcid], deq_qid); } } #endif /* DBG */ return TRUE; } INT rtmp_deq_report(RTMP_ADAPTER *pAd, struct dequeue_info *info) { UINT tx_cnt = info->deq_pkt_cnt, qidx = info->cur_q; struct tx_swq_fifo *fifo_swq; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s():Success DeQ(QId=%d) for WCID(%d), PktCnt=%d, TxSWQDeQ/EnQ ID=%d/%d\n", __FUNCTION__, info->cur_q, info->cur_wcid, info->deq_pkt_cnt, pAd->tx_swq[qidx].deqIdx, pAd->tx_swq[qidx].enqIdx)); if ((qidx < 4) && (tx_cnt > 0)) { fifo_swq = &pAd->tx_swq[qidx]; do { if (fifo_swq->swq[fifo_swq->deqIdx] == info->cur_wcid) { fifo_swq->swq[fifo_swq->deqIdx] = 0; INC_RING_INDEX(fifo_swq->deqIdx, TX_SWQ_FIFO_LEN); tx_cnt--; } else break; }while (tx_cnt != 0); if (info->q_max_cnt[qidx] > 0) info->q_max_cnt[qidx] -= info->deq_pkt_cnt; if (info->target_wcid < MAX_LEN_OF_TR_TABLE) info->pkt_cnt -= info->deq_pkt_cnt; //rtmp_tx_swq_dump(pAd, qidx); //rtmp_sta_txq_dump(pAd, &pAd->MacTab.tr_entry[info->wcid], qidx); } rtmp_psDeq_report(pAd,info); if (qidx < 4) DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("After DeqReport, tx_swq D/EQIdx=%d/%d, deq_info.q_max_cnt/pkt_cnt=%d/%d\n", pAd->tx_swq[qidx].deqIdx, pAd->tx_swq[qidx].enqIdx, info->q_max_cnt[qidx] , info->pkt_cnt)); return TRUE; } #ifdef CONFIG_AP_SUPPORT INT deq_mgmt_frame(RTMP_ADAPTER *pAd, PNDIS_PACKET pkt, UCHAR qIdx, BOOLEAN bLocked) { NDIS_STATUS Status; //unsigned long IrqFlags; #ifdef RTMP_MAC_PCI if (RTMP_GET_PACKET_MGMT_PKT_DATA_QUE(pkt) == 1) { //DEQUEUE_LOCK(&pAd->irq_lock, bLocked, IrqFlags); Status = MlmeHardTransmitTxRing(pAd,qIdx,pkt); //DEQUEUE_UNLOCK(&pAd->irq_lock, bLocked, IrqFlags); } else #endif /* RTMP_MAC_PCI */ Status = MlmeHardTransmitMgmtRing(pAd,qIdx,pkt); if (Status != NDIS_STATUS_SUCCESS) { DBGPRINT(RT_DEBUG_ERROR, ("tx queued mgmt frame error!\n")); RELEASE_NDIS_PACKET(pAd, pkt, NDIS_STATUS_FAILURE); } return TRUE; } #endif /* CONFIG_AP_SUPPORT */ #define TX_FLAG_STOP_DEQUEUE (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS |\ fRTMP_ADAPTER_RADIO_OFF |\ fRTMP_ADAPTER_RESET_IN_PROGRESS |\ fRTMP_ADAPTER_HALT_IN_PROGRESS |\ fRTMP_ADAPTER_NIC_NOT_EXIST |\ fRTMP_ADAPTER_DISABLE_DEQUEUEPACKET) #ifdef RELEASE_EXCLUDE /* Traffic Jam checking: WDS: WDS need to check the peer's absent by tx few (2 ~3) pkts to peer. When WDS Jam happen by peer's absent, drop pkts to hw for 1 min. non-WDS interface: Sample Lin, 20100412 we also need to tx pkt to detect the link periodically; Or when pMacEntry->ContinueTxFailCnt >= pAd->ApCfg.EntryLifeCheck, no any chance to clear pMacEntry->ContinueTxFailCnt. EX: When pMacEntry->ContinueTxFailCnt >= pAd->ApCfg.EntryLifeCheck, the condition will not be removed and we will drop all packets for the pEntry. But maybe the signal becomes better. So we try to send a packet periodically and we will get the tx status in tx done interrupt. If the tx status is success, pMacEntry->ContinueTxFailCnt will be cleared to 0. */ #endif /* RELEASE_EXCLUDE */ #define ENTRY_RETRY_INTERVAL (100 * OS_HZ / 1000) static inline BOOLEAN traffic_jam_chk(RTMP_ADAPTER *pAd, STA_TR_ENTRY *tr_entry) { BOOLEAN drop_it = FALSE; if (!IS_ENTRY_NONE(tr_entry)) { ULONG Now32; NdisGetSystemUpTime(&Now32); #ifdef CONFIG_AP_SUPPORT #ifdef WDS_SUPPORT if (IS_ENTRY_WDS(tr_entry)) { if (tr_entry->LockEntryTx && RTMP_TIME_BEFORE(Now32, tr_entry->TimeStamp_toTxRing + WDS_ENTRY_RETRY_INTERVAL)) drop_it = TRUE; } else #endif /* WDS_SUPPORT */ if (tr_entry->ContinueTxFailCnt >= pAd->ApCfg.EntryLifeCheck) { if(RTMP_TIME_BEFORE(Now32, tr_entry->TimeStamp_toTxRing + ENTRY_RETRY_INTERVAL)) drop_it = TRUE; } else #endif /* CONFIG_AP_SUPPORT */ { tr_entry->TimeStamp_toTxRing = Now32; } } return drop_it; } INT deq_packet_gatter(RTMP_ADAPTER *pAd, struct dequeue_info *deq_info, TX_BLK *pTxBlk, BOOLEAN in_hwIRQ) { STA_TR_ENTRY *tr_entry; MAC_TABLE_ENTRY *pMacEntry = NULL; #ifdef WMM_ACM_SUPPORT BOOLEAN hasTxDesc = FALSE; #endif /* WMM_ACM_SUPPORT */ ULONG hwd_cnt = 0; PQUEUE_ENTRY qEntry = NULL; PNDIS_PACKET pPacket; PQUEUE_HEADER pQueue; //unsigned long IrqFlags; UCHAR QueIdx = deq_info->cur_q; UCHAR wcid = deq_info->cur_wcid; tr_entry = &pAd->MacTab.tr_entry[wcid]; if (wcid < MAX_LEN_OF_MAC_TABLE) pMacEntry = &pAd->MacTab.Content[wcid]; else pMacEntry = &pAd->MacTab.Content[MCAST_WCID]; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("-->%s(): deq_info->wcid=%d, qidx=%d! hwd_cnt=%lu!\n", __FUNCTION__, wcid, QueIdx, hwd_cnt)); deq_info->deq_pkt_cnt = 0; do { hwd_cnt = GET_TXRING_FREENO(pAd, QueIdx); pQueue = &tr_entry->tx_queue[QueIdx]; dequeue: if ((qEntry = pQueue->Head) != NULL) { qEntry = RemoveHeadQueue(pQueue); TR_ENQ_COUNT_DEC(tr_entry); pPacket = QUEUE_ENTRY_TO_PACKET(qEntry); ASSERT(RTMP_GET_PACKET_WCID(pPacket) == wcid); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("-->%s(): GetPacket, wcid=%d, deq_pkt_cnt=%d, TotalFrameNum=%d\n", __FUNCTION__, wcid, deq_info->deq_pkt_cnt, pTxBlk->TotalFrameNum)); #ifdef CONFIG_AP_SUPPORT // TODO: shiang-usw, for mgmt frame enqueue to a dataQ but still go through mgmtRing here, is that good?? if (RTMP_GET_PACKET_MGMT_PKT(pPacket)) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): Call deq_mgmt_frame()!\n", __FUNCTION__)); deq_mgmt_frame(pAd, pPacket, QueIdx, in_hwIRQ); deq_info->deq_pkt_cnt++; goto dequeue; } #endif /* CONFIG_AP_SUPPORT */ // TODO: shiang-usw, remove this check to other place!! if (traffic_jam_chk(pAd, tr_entry) == TRUE) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): traffic jam detected! free pkt!\n", __FUNCTION__)); RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); deq_info->deq_pkt_cnt++; goto dequeue; } pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket, pTxBlk); if (pTxBlk->TxFrameType & (TX_RALINK_FRAME | TX_AMSDU_FRAME)) { if (pTxBlk->TotalFrameNum == 0) { struct tx_swq_fifo *tx_swq = &pAd->tx_swq[QueIdx]; BOOLEAN tx_swq_empty = FALSE; UINT diff = 0; if (tx_swq->enqIdx > tx_swq->deqIdx) diff = tx_swq->enqIdx - tx_swq->deqIdx; else if (tx_swq->enqIdx < tx_swq->deqIdx) diff = TX_SWQ_FIFO_LEN - tx_swq->deqIdx + tx_swq->enqIdx; if (diff == 1) tx_swq_empty = TRUE; if ((tx_swq_empty == TRUE) && (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, hwd_cnt, pTxBlk->TxFrameType))) { InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); TR_ENQ_COUNT_INC(tr_entry); deq_info->q_max_cnt[QueIdx] = 0; break; } } else { if (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE) { InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); TR_ENQ_COUNT_INC(tr_entry); goto start_kick; } } } #ifdef WMM_ACM_SUPPORT #ifdef ACM_CC_FUNC_QUE_TX_CTRL /* init ACM related parameters for the packet */ if (RTMP_GET_PACKET_TX_TIME(pPacket)) { UINT32 QueTypeTx; /* when any ACM of one AC is enabled, check if the packet can be transmitted Null frame is tx in management queue, not here but QoS null belongs to data frame so the method violates spec. */ ACMR_PKT_QOS_TYPE_SET(pPacket, 0); QueTypeTx = ACMP_MsduClassify(pAd, pMacEntry, pPacket, QueIdx, 0, pTxBlk->TxFrameType, pTxBlk->TxPacketList.Number + 1); if (pTxBlk->TotalFrameNum == 0) { if ((QueTypeTx == QID_AC_BE) || (QueTypeTx == QID_AC_BK) || (QueTypeTx == QID_AC_VI) ||(QueTypeTx == QID_AC_VO)) { QueIdx = QueTypeTx; } else { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); deq_info->deq_pkt_cnt++; continue; } } else { if (QueTypeTx != QueIdx) hasTxDesc = FALSE; /* Can not do AMSDU for the packet */ } } #endif /* ACM_CC_FUNC_QUE_TX_CTRL */ #endif /* WMM_ACM_SUPPORT */ /*Need located here, since RTMP_HAS_ENOUGH_FREE_DESC will use it when USB mode*/ pTxBlk->QueIdx = QueIdx; #ifdef MT_MAC #ifdef USE_BMC if ((pAd->chipCap.hif_type == HIF_MT) && (pAd->MacTab.fAnyStationInPsm == 1) && (tr_entry->EntryType == ENTRY_CAT_MCAST)) pTxBlk->QueIdx = QID_BMC; #endif /* USE_BMC */ #endif /* Early check to make sure we have enoguh Tx Resource. */ if (!RTMP_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, hwd_cnt, pPacket)) { pAd->PrivateInfo.TxRingFullCnt++; InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); TR_ENQ_COUNT_INC(tr_entry); if (deq_info->target_wcid < MAX_LEN_OF_TR_TABLE) { deq_info->full_qid[QueIdx] = TRUE; } else { deq_info->q_max_cnt[QueIdx] = 0; } #ifdef DBG_DIAGNOSE if (pAd->DiagStruct.inited && pAd->DiagStruct.wcid == pTxBlk->Wcid) { struct dbg_diag_info *diag_info; diag_info = &pAd->DiagStruct.diag_info[pAd->DiagStruct.ArrayCurIdx]; diag_info->deq_fail_no_resource_cnt[QueIdx]++; } #endif /* DBG_DIAGNOSE */ #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_LOUD, ("TxRing(%d) full, PktFragCnt=%d\n", QueIdx, RTMP_GET_PACKET_FRAGMENTS(pPacket))); #ifdef RTMP_MAC_PCI DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("Deq:NoFreeTxD[%d](CIDX=%d,TxSwFreeIdx=%d)\n", QueIdx, pAd->TxRing[QueIdx].TxCpuIdx, pAd->TxRing[QueIdx].TxSwFreeIdx)); #endif /* RTMP_MAC_PCI */ #endif /* RELEASE_EXCLUDE */ #ifdef RTMP_MAC_PCI DBGPRINT(RT_DEBUG_INFO, ("%s(): No free TxD(hwd_cnt=%ld, SWIDx=%d, CIDX=%d)\n", __FUNCTION__, hwd_cnt, pAd->TxRing[QueIdx].TxSwFreeIdx, pAd->TxRing[QueIdx].TxCpuIdx)); #else DBGPRINT(RT_DEBUG_INFO, ("%s(): deque break beacuse no free txResource\n", __FUNCTION__)); #endif /* RTMP_MAC_PCI */ break; } pTxBlk->TotalFrameNum++; /* The real fragment number maybe vary*/ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); if (pTxBlk->TotalFrameNum == 1) { pTxBlk->pPacket = pPacket; pTxBlk->wdev = tr_entry->wdev; pTxBlk->tr_entry = tr_entry; pTxBlk->pMacEntry = pMacEntry; #ifdef VENDOR_FEATURE1_SUPPORT pTxBlk->HeaderBuf = (UCHAR *)pTxBlk->HeaderBuffer; #endif /* VENDOR_FEATURE1_SUPPORT */ #if defined(P2P_SUPPORT) || defined(RT_CFG80211_P2P_SUPPORT) || defined(CFG80211_MULTI_STA) pTxBlk->OpMode = RTMP_GET_PACKET_OPMODE(pPacket); #endif /* P2P_SUPPORT || RT_CFG80211_P2P_SUPPORT */ } InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); } else { if (pTxBlk->TxPacketList.Number == 0) { deq_info->deq_pkt_cnt++; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("<--%s():Try deQ a empty Q. pTxBlk.TxPktList.Num=%d, deq_info.pkt_cnt=%d\n", __FUNCTION__, pTxBlk->TxPacketList.Number, deq_info->pkt_cnt)); break; } } if ((pTxBlk->TxFrameType & (TX_RALINK_FRAME | TX_AMSDU_FRAME)) && (pTxBlk->TotalFrameNum == 1) && (pQueue->Head != NULL)) { DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): ForAMSDU/ARalink, try dequeue more pkt!\n", __FUNCTION__)); goto dequeue; } start_kick: if (pTxBlk->TxFrameType & (TX_RALINK_FRAME | TX_AMSDU_FRAME)) { if (pTxBlk->TxPacketList.Number == 1) pTxBlk->TxFrameType = TX_LEGACY_FRAME; } DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("<--%s():pTxBlk.TxPktList.Num=%d, deq_info.pkt_cnt=%d\n", __FUNCTION__, pTxBlk->TxPacketList.Number, deq_info->pkt_cnt)); break; } while(pTxBlk->TxPacketList.Number < deq_info->pkt_cnt); if (pTxBlk->TxPacketList.Number > 0) { deq_info->deq_pkt_cnt += pTxBlk->TxPacketList.Number; return TRUE; } else return FALSE; } /* ======================================================================== Routine Description: To do the enqueue operation and extract the first item of waiting list. If a number of available shared memory segments could meet the request of extracted item, the extracted item will be fragmented into shared memory segments. Arguments: pAd Pointer to our adapter pQueue Pointer to Waiting Queue Return Value: None IRQL = DISPATCH_LEVEL Note: ======================================================================== */ VOID RTMPDeQueuePacket( IN RTMP_ADAPTER *pAd, IN BOOLEAN in_hwIRQ, IN UCHAR QIdx, IN INT wcid, IN INT max_cnt) { //NDIS_STATUS Status = NDIS_STATUS_SUCCESS; INT Count = 0, round = 0; TX_BLK *pTxBlk = NULL; UCHAR QueIdx = 0; unsigned long IrqFlags = 0; struct dequeue_info *deq_info = NULL; #ifdef RELEASE_EXCLUDE DBGPRINT(RT_DEBUG_INFO,("RTMPDeQueuePacket (Tx:%d)--> \n", max_cnt)); #endif /* RELEASE_EXCLUDE */ os_alloc_mem(pAd, (UCHAR **)&pTxBlk, sizeof(TX_BLK)); if (pTxBlk == NULL) { CFG80211DBG(RT_DEBUG_ERROR, ("ERROR !!! %s:malloc TxBlk failed!\n", __FUNCTION__)); goto LabelErr; } os_alloc_mem(pAd, (UCHAR **)&deq_info, sizeof(struct dequeue_info)); if (deq_info == NULL) { CFG80211DBG(RT_DEBUG_ERROR, ("ERROR !!! %s:malloc deq_info failed!\n", __FUNCTION__)); goto LabelErr; } NdisZeroMemory(deq_info,sizeof(struct dequeue_info)); #ifdef DBG_DIAGNOSE if (pAd->DiagStruct.inited) dbg_diag_deque_log(pAd); #endif /* DBG_DIAGNOSE */ //NdisZeroMemory((UCHAR *)&deq_info, sizeof(deq_info)); deq_info->target_wcid = (UCHAR)((wcid == WCID_ALL) ? MAX_LEN_OF_TR_TABLE : wcid); deq_info->target_que = QIdx; do { // TODO: shiang-usw, for another two options "IS_P2P_ABSENCE(pAd)" and RTMP_TEST_MORE_FLAG(pAd, fRTMP_ADAPTER_DISABLE_DEQUEUE) // TODO: we need to take care that for per-entry based control "tr_entry->deq_cap" if (RTMP_TEST_FLAG(pAd, TX_FLAG_STOP_DEQUEUE)) { DBGPRINT(RT_DEBUG_TRACE,("%s:: SW Tx Dequeue was stoped, pAd->Flags=0x%lx\n", __FUNCTION__, pAd->Flags)); break; } round++; DEQUEUE_LOCK(&pAd->irq_lock, in_hwIRQ, IrqFlags); rtmp_deq_req(pAd, max_cnt, deq_info); if (deq_info->status == NDIS_STATUS_FAILURE) { DEQUEUE_UNLOCK(&pAd->irq_lock, in_hwIRQ, IrqFlags); break; } QueIdx = deq_info->cur_q; DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): deq_info:cur_wcid=%d, cur_qidx=%d, pkt_cnt=%d, pkt_bytes=%d\n", __FUNCTION__, deq_info->cur_wcid, QueIdx, deq_info->pkt_cnt, deq_info->pkt_bytes)); NdisZeroMemory((UCHAR *)pTxBlk, sizeof(TX_BLK)); RTMP_START_DEQUEUE(pAd, QueIdx, IrqFlags); deq_packet_gatter(pAd, deq_info, pTxBlk, in_hwIRQ); if (pTxBlk->TotalFrameNum) { ASSERT(pTxBlk->wdev); if (pTxBlk->wdev) ASSERT(pTxBlk->wdev->wdev_hard_tx); if (pTxBlk->wdev && pTxBlk->wdev->wdev_hard_tx) { pTxBlk->wdev->wdev_hard_tx(pAd, pTxBlk); } else { DBGPRINT(RT_DEBUG_ERROR, ("%s():ERR! pTxBlk->wdev=%p, wdev_hard_tx=%p\n", __FUNCTION__, pTxBlk->wdev, pTxBlk->wdev ? pTxBlk->wdev->wdev_hard_tx : NULL)); #ifdef CONFIG_AP_SUPPORT IF_DEV_CONFIG_OPMODE_ON_AP(pAd) /*Status =*/ APHardTransmit(pAd, pTxBlk); #endif /* CONFIG_AP_SUPPORT */ #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) /*Status =*/ STAHardTransmit(pAd, pTxBlk); #endif /* CONFIG_STA_SUPPORT */ } Count += pTxBlk->TotalFrameNum; } RTMP_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); rtmp_deq_report(pAd, deq_info); DEQUEUE_UNLOCK(&pAd->irq_lock, in_hwIRQ, IrqFlags); DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("%s(): deq_packet_gatter %s, TotalFrmNum=%d\n", __FUNCTION__, (pTxBlk->TotalFrameNum > 0 ? "success" : "fail"), pTxBlk->TotalFrameNum)); #ifdef RTMP_MAC_PCI if (++pAd->FifoUpdateDone >= FIFO_STAT_READ_PERIOD) { // TODO: shiang-usw, check this because of REG access here!! NICUpdateFifoStaCounters(pAd); pAd->FifoUpdateDone = 0; } #endif /* RTMP_MAC_PCI */ #ifdef DBG if (round >= 1024) { DBGPRINT(RT_DEBUG_OFF, ("%s():ForceToBreak!!Buggy here?\n", __FUNCTION__)); break; } #endif /* DBG */ }while(1); #ifdef DBG_DEQUE DBGPRINT(RT_DEBUG_INFO | DBG_FUNC_TXQ, ("--->%s():DeQueueRule:WCID[%d], Que[%d]\n", __FUNCTION__, deq_info->target_wcid, deq_info->target_que)); #endif /* DBG_DEQUE */ #ifdef DBG_DIAGNOSE if (pAd->DiagStruct.inited) { struct dbg_diag_info *diag_info; diag_info = &pAd->DiagStruct.diag_info[pAd->DiagStruct.ArrayCurIdx]; diag_info->deq_called++; diag_info->deq_round += round; if (Count < 8) diag_info->deq_cnt[Count]++; else diag_info->deq_cnt[8]++; } #endif /* DBG_DIAGNOSE */ #ifdef WMM_ACM_SUPPORT #ifdef RTMP_MAC_USB if (!hasTxDesc) RTUSBKickBulkOut(pAd); #endif /* RTMP_MAC_USB */ #endif /* WMM_ACM_SUPPORT */ #ifdef BLOCK_NET_IF ASSERT((QueIdx < NUM_OF_TX_RING)); if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) && /* (pAd->TxSwQueue[QueIdx].Number < 1)*/ (pAd->tx_swq[QueIdx].enqIdx == pAd->tx_swq[QueIdx].deqIdx) ) { releaseNetIf(&pAd->blockQueueTab[QueIdx]); } #endif /* BLOCK_NET_IF */ LabelErr: if (deq_info != NULL) os_free_mem(NULL, deq_info); if (pTxBlk != NULL) os_free_mem(NULL, pTxBlk); return; } /* ======================================================================== Routine Description: Calculates the duration which is required to transmit out frames with given size and specified rate. Arguments: pAd Pointer to our adapter Rate Transmit rate Size Frame size in units of byte Return Value: Duration number in units of usec IRQL = PASSIVE_LEVEL IRQL = DISPATCH_LEVEL Note: ======================================================================== */ USHORT RTMPCalcDuration(RTMP_ADAPTER *pAd, UCHAR Rate, ULONG Size) { ULONG Duration = 0; if (Rate < RATE_FIRST_OFDM_RATE) /* CCK*/ { if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) Duration = 96; /* 72+24 preamble+plcp*/ else Duration = 192; /* 144+48 preamble+plcp*/ Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); if ((Size << 4) % RateIdTo500Kbps[Rate]) Duration ++; } else if (Rate <= RATE_LAST_OFDM_RATE)/* OFDM rates*/ { Duration = 20 + 6; /* 16+4 preamble+plcp + Signal Extension*/ Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) Duration += 4; } else /*mimo rate*/ { Duration = 20 + 6; /* 16+4 preamble+plcp + Signal Extension*/ } return (USHORT)Duration; } /* NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same scatter gather buffer */ static inline VOID Sniff2BytesFromNdisBuffer( IN PNDIS_BUFFER buf, IN UCHAR offset, OUT UCHAR *p0, OUT UCHAR *p1) { UCHAR *ptr = (UCHAR *)(buf + offset); *p0 = *ptr; *p1 = *(ptr + 1); } #define ETH_TYPE_VLAN 0x8100 #define ETH_TYPE_IPv4 0x0800 #define ETH_TYPE_IPv6 0x86dd #define ETH_TYPE_ARP 0x0806 #define ETH_TYPE_EAPOL 0x888e #define ETH_TYPE_WAI 0x88b4 #define IP_VER_CODE_V4 0x40 #define IP_VER_CODE_V6 0x60 #define IP_PROTO_UDP 0x11 #define IP_HDR_LEN 20 #define ETH_HDR_LEN 14 #if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) VOID CheckQosMapUP(PMAC_TABLE_ENTRY pEntry, UCHAR DSCP, PUCHAR pUserPriority) { UCHAR i = 0, find_up = 0, dscpL = 0, dscpH = 0; for (i=0;i<(pEntry->DscpExceptionCount/2);i++) { if ((pEntry->DscpException[i] & 0xff) == DSCP) { *pUserPriority = (pEntry->DscpException[i]>>8) & 0xff; find_up = 1; break; } } if (!find_up) { for (i=0;i<8;i++) { dscpL = pEntry->DscpRange[i] & 0xff; dscpH = (pEntry->DscpRange[i]>>8) & 0xff; if ((DSCP <= dscpH) && (DSCP >= dscpL)) { *pUserPriority = i; break; } } } } #endif /* defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) */ /* Check the Ethernet Frame type, and set RTMP_SET_PACKET_SPECIFIC flags Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). */ BOOLEAN RTMPCheckEtherType( IN RTMP_ADAPTER *pAd, IN PNDIS_PACKET pPacket, IN STA_TR_ENTRY *tr_entry, IN struct wifi_dev *wdev, OUT UCHAR *pUserPriority, OUT UCHAR *pQueIdx, OUT UCHAR *pWcid) { UINT16 TypeLen; UCHAR Byte0, Byte1, *pSrcBuf, up = 0; #if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) BSS_STRUCT *pMbss; MAC_TABLE_ENTRY *pMacEntry = &pAd->MacTab.Content[tr_entry->wcid]; if (IS_ENTRY_CLIENT(tr_entry)) { BSS_STRUCT *pMbss = (BSS_STRUCT *) wdev->func_dev; } #endif /* CONFIG_AP_SUPPORT && CONFIG_HOTSPOT_R2 */ pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); ASSERT(pSrcBuf); RTMP_SET_PACKET_SPECIFIC(pPacket, 0); /* get Ethernet protocol field and skip the Ethernet Header */ TypeLen = (pSrcBuf[12] << 8) | pSrcBuf[13]; pSrcBuf += LENGTH_802_3; if (TypeLen <= 1500) { /* 802.3, 802.3 LLC: DestMAC(6) + SrcMAC(6) + Lenght(2) + DSAP(1) + SSAP(1) + Control(1) + if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. => + SNAP (5, OriginationID(3) + etherType(2)) else => It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it */ if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) { Sniff2BytesFromNdisBuffer((PNDIS_BUFFER)pSrcBuf, 6, &Byte0, &Byte1); RTMP_SET_PACKET_LLCSNAP(pPacket, 1); TypeLen = (USHORT)((Byte0 << 8) + Byte1); pSrcBuf += LENGTH_802_1_H; /* Skip this LLC/SNAP header*/ } else { return FALSE; } } /* If it's a VLAN packet, get the real Type/Length field.*/ if (TypeLen == ETH_TYPE_VLAN) { #ifdef CONFIG_AP_SUPPORT /* 802.3 VLAN packets format: DstMAC(6B) + SrcMAC(6B) + 802.1Q Tag Type (2B = 0x8100) + Tag Control Information (2-bytes) + Length/Type(2B) + data payload (42-1500 bytes) + FCS(4B) VLAN tag: 3-bit UP + 1-bit CFI + 12-bit VLAN ID */ /* No matter unicast or multicast, discard it if not my VLAN packet. */ if (wdev->VLAN_VID != 0) { USHORT vlan_id = *(USHORT *)pSrcBuf; vlan_id = cpu2be16(vlan_id); vlan_id = vlan_id & 0x0FFF; /* 12 bit */ if (vlan_id != wdev->VLAN_VID) { DBGPRINT(RT_DEBUG_OFF, ("%s():failed for VLAN_ID(vlan_id=%d, VLAN_VID=%d)\n", __FUNCTION__, vlan_id, wdev->VLAN_VID)); return FALSE; } } #endif /* CONFIG_AP_SUPPORT */ RTMP_SET_PACKET_VLAN(pPacket, 1); Sniff2BytesFromNdisBuffer((PNDIS_BUFFER)pSrcBuf, 2, &Byte0, &Byte1); TypeLen = (USHORT)((Byte0 << 8) + Byte1); /* only use VLAN tag as UserPriority setting */ up = (*pSrcBuf & 0xe0) >> 5; #if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) if (pMacEntry && pMacEntry->QosMapSupport && pMbss->HotSpotCtrl.QosMapEnable) { CheckQosMapUP(pMacEntry, (*pSrcBuf & 0xfc) >> 2, pUserPriority); } #endif /* defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) */ pSrcBuf += LENGTH_802_1Q; /* Skip the VLAN Header.*/ } else if (TypeLen == ETH_TYPE_IPv4) { /* 0 4 8 14 15 31(Bits) +---+----+-----+----+---------------+ |Ver | IHL |DSCP |ECN | TotalLen | +---+----+-----+----+---------------+ Ver - 4bit Internet Protocol version number. IHL - 4bit Internet Header Length DSCP - 6bit Differentiated Services Code Point(TOS) ECN - 2bit Explicit Congestion Notification TotalLen - 16bit IP entire packet length(include IP hdr) */ up = (*(pSrcBuf + 1) & 0xe0) >> 5; #if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) if (pMacEntry && pMacEntry->QosMapSupport && pMbss->HotSpotCtrl.QosMapEnable) { CheckQosMapUP(pMacEntry, (*(pSrcBuf+1) & 0xfc) >> 2, pUserPriority); } #endif } else if (TypeLen == ETH_TYPE_IPv6) { /* 0 4 8 12 16 31(Bits) +---+----+----+----+---------------+ |Ver | TrafficClas | Flow Label | +---+----+----+--------------------+ Ver - 4bit Internet Protocol version number. TrafficClas - 8bit traffic class field, the 6 most-significant bits used for DSCP */ up = ((*pSrcBuf) & 0x0e) >> 1; #if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) if (pMacEntry && pMacEntry->QosMapSupport && pMbss->HotSpotCtrl.QosMapEnable) { CheckQosMapUP(pMacEntry, ((*pSrcBuf & 0x0f) << 2)|((*(pSrcBuf+1)) & 0xc0) >> 6, pUserPriority); } #endif /* defined(CONFIG_AP_SUPPORT) && defined(CONFIG_HOTSPOT_R2) */ } #ifdef RTMP_RBUS_SUPPORT #ifdef VIDEO_TURBINE_SUPPORT if (pAd->VideoTurbine.Enable) { /* RVT Out-band QoS */ struct sk_buff *pSkbPkt = RTPKT_TO_OSPKT(pPacket); if(pSkbPkt->cb[40]==0x0E) up = (pSkbPkt->cb[41] & 0xe0) >> 5; } #endif /* VIDEO_TURBINE_SUPPORT */ #endif /* RTMP_RBUS_SUPPORT */ switch (TypeLen) { case ETH_TYPE_IPv4: { UINT32 pktLen = GET_OS_PKT_LEN(pPacket); ASSERT((pktLen > (ETH_HDR_LEN + IP_HDR_LEN))); /* 14 for ethernet header, 20 for IP header*/ RTMP_SET_PACKET_IPV4(pPacket, 1); if (*(pSrcBuf + 9) == IP_PROTO_UDP) { UINT16 srcPort, dstPort; pSrcBuf += IP_HDR_LEN; srcPort = OS_NTOHS(get_unaligned((PUINT16)(pSrcBuf))); dstPort = OS_NTOHS(get_unaligned((PUINT16)(pSrcBuf+2))); if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) { /*It's a BOOTP/DHCP packet*/ RTMP_SET_PACKET_DHCP(pPacket, 1); RTMP_SET_PACKET_TXTYPE(pPacket, TX_LEGACY_FRAME); } #ifdef CONFIG_AP_SUPPORT #ifdef CONFIG_DOT11V_WNM WNMIPv4ProxyARPCheck(pAd, pPacket, srcPort, dstPort, pSrcBuf); #endif #ifdef CONFIG_HOTSPOT { UCHAR Wcid = RTMP_GET_PACKET_WCID(pPacket); if (!HSIPv4Check(pAd, &Wcid, pPacket, pSrcBuf, srcPort, dstPort)) return FALSE; } #endif #endif } } break; case ETH_TYPE_ARP: { #ifdef CONFIG_AP_SUPPORT #ifdef CONFIG_DOT11V_WNM BSS_STRUCT *pMbss = (BSS_STRUCT *)wdev->func_dev; if (pMbss->WNMCtrl.ProxyARPEnable) { /* Check if IPv4 Proxy ARP Candidate from DS */ if (IsIPv4ProxyARPCandidate(pAd, pSrcBuf - 2)) { BOOLEAN FoundProxyARPEntry; FoundProxyARPEntry = IPv4ProxyARP(pAd, pMbss, pSrcBuf - 2, TRUE); if (!FoundProxyARPEntry) DBGPRINT(RT_DEBUG_TRACE, ("Can not find proxy entry\n")); return FALSE; } } #endif #ifdef CONFIG_HOTSPOT if (pMbss->HotSpotCtrl.HotSpotEnable) { if (!pMbss->HotSpotCtrl.DGAFDisable) { if (IsGratuitousARP(pAd, pSrcBuf - 2, pSrcBuf-14, pMbss)) return FALSE; } } #endif #endif RTMP_SET_PACKET_DHCP(pPacket, 1); RTMP_SET_PACKET_TXTYPE(pPacket, TX_LEGACY_FRAME); } break; case ETH_P_IPV6: { #ifdef CONFIG_AP_SUPPORT #ifdef CONFIG_DOT11V_WNM BSS_STRUCT *pMbss = (BSS_STRUCT *)wdev->func_dev; WNMIPv6ProxyARPCheck(pAd, pPacket, pSrcBuf); if (pMbss->WNMCtrl.ProxyARPEnable) { /* Check if IPv6 Proxy ARP Candidate from DS */ if (IsIPv6ProxyARPCandidate(pAd, pSrcBuf - 2)) { BOOLEAN FoundProxyARPEntry; FoundProxyARPEntry = IPv6ProxyARP(pAd, pMbss, pSrcBuf - 2, TRUE); if (!FoundProxyARPEntry) DBGPRINT(RT_DEBUG_TRACE, ("Can not find IPv6 proxy entry\n")); return FALSE; } } #endif #ifdef CONFIG_HOTSPOT if (pMbss->HotSpotCtrl.HotSpotEnable) { if (!pMbss->HotSpotCtrl.DGAFDisable) { if (IsUnsolicitedNeighborAdver(pAd, pSrcBuf - 2)) return FALSE; } } #endif /* Check if DHCPv6 Packet, and Convert group-address DHCP packets to individually-addressed 802.11 frames */ #endif /* return AC_BE if packet is not IPv6 */ if ((*pSrcBuf & 0xf0) != 0x60) up = 0; } break; case ETH_TYPE_EAPOL: RTMP_SET_PACKET_EAPOL(pPacket, 1); RTMP_SET_PACKET_TXTYPE(pPacket, TX_LEGACY_FRAME); break; #ifdef WAPI_SUPPORT case ETH_TYPE_WAI: RTMP_SET_PACKET_WAI(pPacket, 1); RTMP_SET_PACKET_TXTYPE(pPacket, TX_LEGACY_FRAME); break; #endif /* WAPI_SUPPORT */ #if defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) case 0x890d: { RTMP_SET_PACKET_TDLS_MMPDU(pPacket, 1); RTMP_SET_PACKET_TXTYPE(pPacket, TX_LEGACY_FRAME); up = 5; } break; #endif /* DOT11Z_TDLS_SUPPORT */ default: break; } #ifdef VENDOR_FEATURE1_SUPPORT RTMP_SET_PACKET_PROTOCOL(pPacket, TypeLen); #endif /* VENDOR_FEATURE1_SUPPORT */ /* have to check ACM bit. downgrade UP & QueIdx before passing ACM*/ /* NOTE: AP doesn't have to negotiate TSPEC. ACM is controlled purely via user setup, not protocol handshaking*/ /* Under WMM ACM control, we dont need to check the bit; Or when a TSPEC is built for VO but we will change priority to BE here and when we issue a BA session, the BA session will be BE session, not VO session. */ #ifndef WMM_ACM_SUPPORT if (pAd->CommonCfg.APEdcaParm.bACM[WMM_UP2AC_MAP[up]]) up = 0; #endif /* WMM_ACM_SUPPORT */ #ifdef WAC_SUPPORT #ifdef WAC_QOS_PRIORITY if (tr_entry->bSamsungForcePriority) up = 7; #endif /* WAC_QOS_PRIORITY */ #endif /* WAC_SUPPORT */ /* Set WMM when 1. wdev->bWmmCapable == TRUE 2. Receiver's capability a). bc/mc packets ->Need to get UP for IGMP use b). unicast packets -> CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE) 3. has VLAN tag or DSCP fields in IPv4/IPv6 hdr */ if ((wdev->bWmmCapable == TRUE) && (up <= 7)) { *pUserPriority = up; *pQueIdx = WMM_UP2AC_MAP[up]; } return TRUE; } BOOLEAN CheckICMPPacket(RTMP_ADAPTER *pAd, UCHAR *pSrcBuf, UINT8 Direction) { UINT16 TypeLen; UCHAR Byte0, Byte1; if (Direction == 0) /* TX */ { TypeLen = (pSrcBuf[12] << 8) | pSrcBuf[13]; pSrcBuf += LENGTH_802_3; if (TypeLen <= 1500) { if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) { Sniff2BytesFromNdisBuffer((PNDIS_BUFFER)pSrcBuf, 6, &Byte0, &Byte1); TypeLen = (USHORT)((Byte0 << 8) + Byte1); pSrcBuf += LENGTH_802_1_H; /* Skip this LLC/SNAP header*/ } else { return FALSE; } } if (TypeLen == ETH_TYPE_IPv4) { pSrcBuf += 9; if (*pSrcBuf == 0x01) { pSrcBuf += 11; if (*pSrcBuf == 0x00) { pSrcBuf++; if (*pSrcBuf == 0x00) { DBGPRINT(RT_DEBUG_INFO, ("ping reply packet\n")); return TRUE; } } else if (*pSrcBuf == 0x08) { pSrcBuf++; if (*pSrcBuf == 0x00) { DBGPRINT(RT_DEBUG_INFO, ("ping req packet\n")); return TRUE; } } } } } else if (Direction == 1) /* RX */ { pSrcBuf = NdisEqualMemory(SNAP_802_1H, pSrcBuf, 6) ? (pSrcBuf + 6) : pSrcBuf; TypeLen = (*pSrcBuf << 8) + (*(pSrcBuf + 1)); if (TypeLen == ETH_TYPE_IPv4) { pSrcBuf += 9; if (*pSrcBuf == 0x01) { pSrcBuf += 11; if (*pSrcBuf == 0x00) { pSrcBuf++; if (*pSrcBuf == 0x00) { DBGPRINT(RT_DEBUG_INFO, ("ping reply packet\n")); return TRUE; } } else if (*pSrcBuf == 0x08) { pSrcBuf++; if (*pSrcBuf == 0x00) { DBGPRINT(RT_DEBUG_INFO, ("ping req packet\n")); return TRUE; } } } } } return FALSE; } #ifdef SOFT_ENCRYPT BOOLEAN RTMPExpandPacketForSwEncrypt( IN RTMP_ADAPTER *pAd, IN TX_BLK *pTxBlk) { PACKET_INFO PacketInfo; UINT32 ex_head = 0, ex_tail = 0; UCHAR NumberOfFrag = RTMP_GET_PACKET_FRAGMENTS(pTxBlk->pPacket); #ifdef WAPI_SUPPORT if (pTxBlk->CipherAlg == CIPHER_SMS4) ex_tail = LEN_WPI_MIC; else #endif /* WAPI_SUPPORT */ if (pTxBlk->CipherAlg == CIPHER_AES) ex_tail = LEN_CCMP_MIC; ex_tail = (NumberOfFrag * ex_tail); pTxBlk->pPacket = ExpandPacket(pAd, pTxBlk->pPacket, ex_head, ex_tail); if (pTxBlk->pPacket == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("%s: out of resource.\n", __FUNCTION__)); return FALSE; } RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); return TRUE; } VOID RTMPUpdateSwCacheCipherInfo( IN RTMP_ADAPTER *pAd, IN TX_BLK *pTxBlk, IN UCHAR *pHdr) { HEADER_802_11 *pHeader_802_11; MAC_TABLE_ENTRY *pMacEntry; pHeader_802_11 = (HEADER_802_11 *) pHdr; pMacEntry = pTxBlk->pMacEntry; if (pMacEntry && pHeader_802_11->FC.Wep && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_SOFTWARE_ENCRYPT)) { PCIPHER_KEY pKey = &pMacEntry->PairwiseKey; TX_BLK_SET_FLAG(pTxBlk, fTX_bSwEncrypt); pTxBlk->CipherAlg = pKey->CipherAlg; pTxBlk->pKey = pKey; #ifdef WAPI_SUPPORT pTxBlk->KeyIdx = pMacEntry->usk_id; /* TSC increment pre encryption transmittion */ if (pKey->CipherAlg == CIPHER_SMS4) inc_iv_byte(pKey->TxTsc, LEN_WAPI_TSC, 2); else #endif /* WAPI_SUPPORT */ if ((pKey->CipherAlg == CIPHER_WEP64) || (pKey->CipherAlg == CIPHER_WEP128)) inc_iv_byte(pKey->TxTsc, LEN_WEP_TSC, 1); else if ((pKey->CipherAlg == CIPHER_TKIP) || (pKey->CipherAlg == CIPHER_AES)) inc_iv_byte(pKey->TxTsc, LEN_WPA_TSC, 1); } } INT tx_sw_encrypt(RTMP_ADAPTER *pAd, TX_BLK *pTxBlk, UCHAR *pHeaderBufPtr, HEADER_802_11 *wifi_hdr) { UCHAR iv_offset = 0, ext_offset = 0; #ifdef CONFIG_TSO_SUPPORT if (pTxBlk->naf_type) DBGPRINT(RT_DEBUG_ERROR, ("%s():Error, try to encrypt a pkt marked to use NAF(%d)!\n", __FUNCTION__, pTxBlk->naf_type)); #endif /* CONFIG_TSO_SUPPORT */ /* If original Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required */ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData - 2, pTxBlk->pExtraLlcSnapEncap); /* Insert LLC-SNAP encapsulation (8 octets) to MPDU data buffer */ if (pTxBlk->pExtraLlcSnapEncap) { /* Reserve the front 8 bytes of data for LLC header */ pTxBlk->pSrcBufData -= LENGTH_802_1_H; pTxBlk->SrcBufLen += LENGTH_802_1_H; NdisMoveMemory(pTxBlk->pSrcBufData, pTxBlk->pExtraLlcSnapEncap, 6); } /* Construct and insert specific IV header to MPDU header */ RTMPSoftConstructIVHdr(pTxBlk->CipherAlg, pTxBlk->KeyIdx, pTxBlk->pKey->TxTsc, pHeaderBufPtr, &iv_offset); pHeaderBufPtr += iv_offset; // TODO: shiang-MT7603, for header Len, shall we take care that?? pTxBlk->MpduHeaderLen += iv_offset; /* Encrypt the MPDU data by software */ RTMPSoftEncryptionAction(pAd, pTxBlk->CipherAlg, (UCHAR *)wifi_hdr, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, pTxBlk->KeyIdx, pTxBlk->pKey, &ext_offset); pTxBlk->SrcBufLen += ext_offset; pTxBlk->TotalFrameLen += ext_offset; return TRUE; } #endif /* SOFT_ENCRYPT */ #ifdef IP_ASSEMBLY /*for cache usage to improve throughput*/ static IP_ASSEMBLE_DATA *pCurIpAsmData[NUM_OF_TX_RING]; static INT rtmp_IpAssembleDataCreate(RTMP_ADAPTER *pAd,UCHAR queId,IP_ASSEMBLE_DATA **ppIpAsmbData,UINT id,UINT fragSize) { ULONG now = 0; IP_ASSEMBLE_DATA *pIpAsmbData = NULL; DL_LIST *pAssHead = &pAd->assebQueue[queId]; os_alloc_mem(NULL,(UCHAR**)&pIpAsmbData,sizeof(IP_ASSEMBLE_DATA)); *ppIpAsmbData = pIpAsmbData; if(pIpAsmbData==NULL) { return NDIS_STATUS_FAILURE; } InitializeQueueHeader(&pIpAsmbData->queue); NdisGetSystemUpTime(&now); pIpAsmbData->identify = id; pIpAsmbData->fragSize = fragSize; pIpAsmbData->createTime = now; DlListAdd(pAssHead,&pIpAsmbData->list); return NDIS_STATUS_SUCCESS; } static VOID rtmp_IpAssembleDataDestory(RTMP_ADAPTER *pAd,IP_ASSEMBLE_DATA *pIpAsmbData) { PQUEUE_ENTRY pPktEntry; PNDIS_PACKET pPkt; /*free queue packet*/ while (1) { pPktEntry = RemoveHeadQueue(&pIpAsmbData->queue); if (pPktEntry == NULL) { break; } pPkt = QUEUE_ENTRY_TO_PACKET(pPktEntry); RELEASE_NDIS_PACKET(pAd, pPkt, NDIS_STATUS_FAILURE); } /*remove from list*/ DlListDel(&pIpAsmbData->list); /*free data*/ os_free_mem(NULL,pIpAsmbData); } static IP_ASSEMBLE_DATA* rtmp_IpAssembleDataSearch(RTMP_ADAPTER *pAd, UCHAR queIdx, UINT identify) { DL_LIST *pAssHead = &pAd->assebQueue[queIdx]; IP_ASSEMBLE_DATA *pAssData = NULL; DlListForEach(pAssData,pAssHead,struct ip_assemble_data,list) { if(pAssData->identify == identify) { return pAssData; } } return NULL; } static VOID rtmp_IpAssembleDataUpdate(RTMP_ADAPTER *pAd) { DL_LIST *pAssHead = NULL; IP_ASSEMBLE_DATA *pAssData = NULL,*pNextAssData=NULL; INT i=0; ULONG now = 0; QUEUE_HEADER *pAcQueue = NULL; NdisGetSystemUpTime(&now); for(i=0;iassebQueue[i]; DlListForEachSafe(pAssData,pNextAssData,pAssHead,struct ip_assemble_data,list) { pAcQueue = &pAssData->queue; if ((pAcQueue->Number != 0) && (RTMP_TIME_AFTER(now, (pAssData->createTime) + (1000 * OS_HZ)))) { if(pCurIpAsmData[i] == pAssData) { pCurIpAsmData[i] = NULL; } rtmp_IpAssembleDataDestory(pAd,pAssData); } } } } INT rtmp_IpAssembleHandle(RTMP_ADAPTER *pAd,STA_TR_ENTRY *pTrEntry , PNDIS_PACKET pPacket,UCHAR queIdx,PACKET_INFO packetInfo) { IP_ASSEMBLE_DATA *pIpAsmData = NULL; /*define local variable*/ IP_V4_HDR *pIpv4Hdr, Ipv4Hdr; IP_FLAGS_FRAG_OFFSET *pFlagsFragOffset, flagsFragOffset; UINT fragSize = 0; QUEUE_HEADER *pAcQueue = NULL; UINT32 fragCount = 0; /*check all timer of assemble for ageout */ rtmp_IpAssembleDataUpdate(pAd); /*is not ipv4 packet*/ if (!RTMP_GET_PACKET_IPV4(pPacket)) { /*continue to do normal path*/ return NDIS_STATUS_INVALID_DATA; } pFlagsFragOffset = (IP_FLAGS_FRAG_OFFSET *) (packetInfo.pFirstBuffer + LENGTH_802_3 + 6); flagsFragOffset.word = ntohs(pFlagsFragOffset->word); /*is not fragment packet*/ if(flagsFragOffset.field.flags_more_frag == 0 && flagsFragOffset.field.frag_offset == 0) { /*continue to do normal path*/ return NDIS_STATUS_INVALID_DATA; } /*get ipv4 */ pIpv4Hdr = (IP_V4_HDR *) (packetInfo.pFirstBuffer + LENGTH_802_3); Ipv4Hdr.identifier = ntohs(pIpv4Hdr->identifier); Ipv4Hdr.tot_len = ntohs(pIpv4Hdr->tot_len); Ipv4Hdr.ihl = pIpv4Hdr->ihl; fragSize = Ipv4Hdr.tot_len - (Ipv4Hdr.ihl * 4); /* check if 1st fragment */ if ((flagsFragOffset.field.flags_more_frag == 1) && (flagsFragOffset.field.frag_offset == 0)) { /*check current queue is exist this id packet or not*/ pIpAsmData = rtmp_IpAssembleDataSearch(pAd,queIdx,Ipv4Hdr.identifier); /*if not exist, create it*/ if(!pIpAsmData) { rtmp_IpAssembleDataCreate(pAd,queIdx,&pIpAsmData,Ipv4Hdr.identifier,fragSize); if(!pIpAsmData) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); return NDIS_STATUS_FAILURE; } } /*store to cache */ pCurIpAsmData[queIdx] = pIpAsmData; /*insert packet*/ pAcQueue = &pIpAsmData->queue; InsertTailQueue(pAcQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); } else { /*search assemble data from identify and cache first*/ if(pCurIpAsmData[queIdx] && (pCurIpAsmData[queIdx]->identify == Ipv4Hdr.identifier)) { pIpAsmData = pCurIpAsmData[queIdx]; }else { pIpAsmData = rtmp_IpAssembleDataSearch(pAd,queIdx,Ipv4Hdr.identifier); /*not create assemble, should drop*/ if(!pIpAsmData) { RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); return NDIS_STATUS_FAILURE; } /*update cache*/ pCurIpAsmData[queIdx] = pIpAsmData; } pAcQueue = &pIpAsmData->queue; InsertTailQueue(pAcQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); /* check if last fragment */ if (pIpAsmData && (flagsFragOffset.field.flags_more_frag == 0) && (flagsFragOffset.field.frag_offset != 0)) { /*fragment packets gatter and check*/ fragCount = ((flagsFragOffset.field.frag_offset * 8) / (pIpAsmData->fragSize)) + 1; if (pAcQueue->Number != fragCount) { rtmp_IpAssembleDataDestory(pAd,pIpAsmData); pCurIpAsmData[queIdx] = NULL; return NDIS_STATUS_FAILURE; } /* move backup fragments to software queue */ if (rtmp_enq_req(pAd, NULL, queIdx, pTrEntry,FALSE,pAcQueue) == FALSE) { rtmp_IpAssembleDataDestory(pAd,pIpAsmData); pCurIpAsmData[queIdx] = NULL; return NDIS_STATUS_FAILURE; } rtmp_IpAssembleDataDestory(pAd,pIpAsmData); pCurIpAsmData[queIdx] = NULL; } } return NDIS_STATUS_SUCCESS; } #endif INT rtmp_tx_burst_set(RTMP_ADAPTER *pAd) { #ifdef DOT11_N_SUPPORT #ifdef MT_MAC #ifdef RTMP_SDIO_SUPPORT if(pAd->MCUCtrl.Stage == FW_RUN_TIME){ #endif if (pAd->chipCap.hif_type == HIF_MT) { /* Not RDG, update the TxOP else keep the default RDG's TxOP */ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RDG_ACTIVE) == FALSE) { if ((pAd->MacTab.Size == 1) && (pAd->CommonCfg.bEnableTxBurst)) { /* Only update TxOP for racing */ AsicUpdateTxOP(pAd, WMM_PARAM_AC_1, 0x60); } else { AsicUpdateTxOP(pAd, WMM_PARAM_AC_1, 0x0); } } } #ifdef RTMP_SDIO_SUPPORT } #endif #endif /* MT_MAC */ #endif /* DOT11_N_SUPPORT */ return NDIS_STATUS_SUCCESS; }