| /* |
| ************************************************************************* |
| * Ralink Tech Inc. |
| * 5F., No.36, Taiyuan St., Jhubei City, |
| * Hsinchu County 302, |
| * Taiwan, R.O.C. |
| * |
| * (c) Copyright 2002-2007, Ralink Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 2 of the License, or * |
| * (at your option) any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the * |
| * Free Software Foundation, Inc., * |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
| * * |
| ************************************************************************* |
| */ |
| |
| #include "../rt_config.h" |
| |
| u8 SNAP_802_1H[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
| u8 SNAP_BRIDGE_TUNNEL[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
| |
| /* Add Cisco Aironet SNAP heade for CCX2 support */ |
| u8 SNAP_AIRONET[] = { 0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00 }; |
| u8 CKIP_LLC_SNAP[] = { 0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02 }; |
| u8 EAPOL_LLC_SNAP[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; |
| u8 EAPOL[] = { 0x88, 0x8e }; |
| u8 TPID[] = { 0x81, 0x00 }; /* VLAN related */ |
| |
| u8 IPX[] = { 0x81, 0x37 }; |
| u8 APPLE_TALK[] = { 0x80, 0xf3 }; |
| |
| u8 RateIdToPlcpSignal[12] = { |
| 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 *//* see BBP spec */ |
| 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 *//* see IEEE802.11a-1999 p.14 */ |
| 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ |
| }; /* see IEEE802.11a-1999 p.14 */ |
| |
| u8 OfdmSignalToRateId[16] = { |
| RATE_54, RATE_54, RATE_54, RATE_54, /* OFDM PLCP Signal = 0, 1, 2, 3 respectively */ |
| RATE_54, RATE_54, RATE_54, RATE_54, /* OFDM PLCP Signal = 4, 5, 6, 7 respectively */ |
| RATE_48, RATE_24, RATE_12, RATE_6, /* OFDM PLCP Signal = 8, 9, 10, 11 respectively */ |
| RATE_54, RATE_36, RATE_18, RATE_9, /* OFDM PLCP Signal = 12, 13, 14, 15 respectively */ |
| }; |
| |
| u8 OfdmRateToRxwiMCS[12] = { |
| 0, 0, 0, 0, |
| 0, 1, 2, 3, /* OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 */ |
| 4, 5, 6, 7, /* OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 */ |
| }; |
| |
| u8 RxwiMCSToOfdmRate[12] = { |
| RATE_6, RATE_9, RATE_12, RATE_18, |
| RATE_24, RATE_36, RATE_48, RATE_54, /* OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 */ |
| 4, 5, 6, 7, /* OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 */ |
| }; |
| |
| char *MCSToMbps[] = |
| { "1Mbps", "2Mbps", "5.5Mbps", "11Mbps", "06Mbps", "09Mbps", "12Mbps", |
| "18Mbps", "24Mbps", "36Mbps", "48Mbps", "54Mbps", "MM-0", "MM-1", "MM-2", "MM-3", |
| "MM-4", "MM-5", "MM-6", "MM-7", "MM-8", "MM-9", "MM-10", "MM-11", "MM-12", "MM-13", |
| "MM-14", "MM-15", "MM-32", "ee1", "ee2", "ee3" }; |
| |
| u8 default_cwmin[] = |
| { CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS - 1, CW_MIN_IN_BITS - 2 }; |
| /*u8 default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; */ |
| u8 default_sta_aifsn[] = { 3, 7, 2, 2 }; |
| |
| u8 MapUserPriorityToAccessCategory[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 }; |
| |
| /* |
| ======================================================================== |
| |
| 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: |
| |
| ======================================================================== |
| */ |
| int MiniportMMRequest(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, u8 *pData, u32 Length) |
| { |
| void *pPacket; |
| int Status = NDIS_STATUS_SUCCESS; |
| unsigned long FreeNum; |
| u8 rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; /*RTMP_HW_HDR_LEN]; */ |
| #ifdef RTMP_MAC_PCI |
| unsigned long IrqFlags = 0; |
| u8 IrqState; |
| #endif /* RTMP_MAC_PCI // */ |
| BOOLEAN bUseDataQ = FALSE; |
| int retryCnt = 0; |
| |
| ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); |
| |
| if ((QueIdx & MGMT_USE_QUEUE_FLAG) == MGMT_USE_QUEUE_FLAG) { |
| bUseDataQ = TRUE; |
| QueIdx &= (~MGMT_USE_QUEUE_FLAG); |
| } |
| #ifdef RTMP_MAC_PCI |
| /* 2860C use Tx Ring */ |
| IrqState = pAd->irq_disabled; |
| if (pAd->MACVersion == 0x28600100) { |
| QueIdx = (bUseDataQ == TRUE ? QueIdx : 3); |
| bUseDataQ = TRUE; |
| } |
| if (bUseDataQ && (!IrqState)) |
| RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); |
| #endif /* RTMP_MAC_PCI // */ |
| |
| do { |
| /* Reset is in progress, stop immediately */ |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || |
| RTMP_TEST_FLAG(pAd, |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST) |
| || !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) { |
| Status = NDIS_STATUS_FAILURE; |
| break; |
| } |
| /* 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) { |
| retryCnt = MAX_DATAMM_RETRY; |
| /* free Tx(QueIdx) resources */ |
| RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); |
| FreeNum = GET_TXRING_FREENO(pAd, QueIdx); |
| } else |
| #endif /* RTMP_MAC_PCI // */ |
| { |
| FreeNum = GET_MGMTRING_FREENO(pAd); |
| } |
| |
| if ((FreeNum > 0)) { |
| /* We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 */ |
| NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); |
| Status = |
| RTMPAllocateNdisPacket(pAd, &pPacket, |
| (u8 *)& rtmpHwHdr, |
| (TXINFO_SIZE + TXWI_SIZE), |
| pData, Length); |
| if (Status != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); |
| break; |
| } |
| /*pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; */ |
| /*pAd->CommonCfg.MlmeRate = RATE_2; */ |
| |
| #ifdef RTMP_MAC_PCI |
| if (bUseDataQ) { |
| Status = |
| MlmeDataHardTransmit(pAd, QueIdx, pPacket); |
| retryCnt--; |
| } else |
| #endif /* RTMP_MAC_PCI // */ |
| Status = MlmeHardTransmit(pAd, QueIdx, pPacket); |
| if (Status == NDIS_STATUS_SUCCESS) |
| retryCnt = 0; |
| else |
| RTMPFreeNdisPacket(pAd, pPacket); |
| } 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)); |
| } |
| } |
| #endif /* RTMP_MAC_PCI // */ |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", |
| QueIdx, |
| pAd->RalinkCounters.MgmtRingFullCount)); |
| } |
| } while (retryCnt > 0); |
| |
| #ifdef RTMP_MAC_PCI |
| if (bUseDataQ && (!IrqState)) |
| RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); |
| #endif /* RTMP_MAC_PCI // */ |
| |
| return Status; |
| } |
| |
| /* |
| ======================================================================== |
| |
| 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: |
| |
| ======================================================================== |
| */ |
| int MlmeHardTransmit(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, void *pPacket) |
| { |
| struct rt_packet_info PacketInfo; |
| u8 *pSrcBufVA; |
| u32 SrcBufLen; |
| struct rt_header_802_11 * pHeader_802_11; |
| |
| if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) |
| ) { |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); |
| if (pSrcBufVA == NULL) |
| return NDIS_STATUS_FAILURE; |
| |
| pHeader_802_11 = (struct rt_header_802_11 *) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); |
| |
| #ifdef RTMP_MAC_PCI |
| if (pAd->MACVersion == 0x28600100) |
| return MlmeHardTransmitTxRing(pAd, QueIdx, pPacket); |
| else |
| #endif /* RTMP_MAC_PCI // */ |
| return MlmeHardTransmitMgmtRing(pAd, QueIdx, pPacket); |
| |
| } |
| |
| int MlmeHardTransmitMgmtRing(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, void *pPacket) |
| { |
| struct rt_packet_info PacketInfo; |
| u8 *pSrcBufVA; |
| u32 SrcBufLen; |
| struct rt_header_802_11 * pHeader_802_11; |
| BOOLEAN bAckRequired, bInsertTimestamp; |
| u8 MlmeRate; |
| struct rt_txwi * pFirstTxWI; |
| struct rt_mac_table_entry *pMacEntry = NULL; |
| u8 PID; |
| |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); |
| |
| /* Make sure MGMT ring resource won't be used by other threads */ |
| RTMP_SEM_LOCK(&pAd->MgmtRingLock); |
| if (pSrcBufVA == NULL) { |
| /* The buffer shouldn't be NULL */ |
| RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| { |
| /* outgoing frame always wakeup PHY to prevent frame lost */ |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) |
| AsicForceWakeup(pAd, TRUE); |
| } |
| |
| pFirstTxWI = (struct rt_txwi *) (pSrcBufVA + TXINFO_SIZE); |
| pHeader_802_11 = (struct rt_header_802_11 *) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); /*TXWI_SIZE); */ |
| |
| 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 == BTYPE_DATA) && |
| (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) { |
| pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); |
| } |
| |
| { |
| /* Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. */ |
| if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED |
| || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) { |
| if (pAd->LatchRfRegs.Channel > 14) |
| pAd->CommonCfg.MlmeTransmit.field.MODE = 1; |
| else |
| pAd->CommonCfg.MlmeTransmit.field.MODE = 0; |
| } |
| } |
| |
| /* */ |
| /* 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. */ |
| /* */ |
| pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; /* (pAd->StaCfg.Psm == PWR_SAVE); */ |
| |
| /* */ |
| /* 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 ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) */ |
| { |
| if ((pHeader_802_11->FC.SubType == SUBTYPE_ACTION) || |
| ((pHeader_802_11->FC.Type == BTYPE_DATA) && |
| ((pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL) || |
| (pHeader_802_11->FC.SubType == SUBTYPE_NULL_FUNC)))) { |
| if (pAd->StaCfg.Psm == PWR_SAVE) |
| pHeader_802_11->FC.PwrMgmt = PWR_SAVE; |
| else |
| pHeader_802_11->FC.PwrMgmt = |
| pAd->CommonCfg.bAPSDForcePowerSave; |
| } |
| } |
| |
| bInsertTimestamp = FALSE; |
| if (pHeader_802_11->FC.Type == BTYPE_CNTL) /* must be PS-POLL */ |
| { |
| /*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; |
| } |
| bAckRequired = FALSE; |
| } else /* BTYPE_MGMT or BTYPE_DATA(must be NULL frame) */ |
| { |
| /*pAd->Sequence++; */ |
| /*pHeader_802_11->Sequence = pAd->Sequence; */ |
| |
| if (pHeader_802_11->Addr1[0] & 0x01) /* MULTICAST, BROADCAST */ |
| { |
| bAckRequired = FALSE; |
| pHeader_802_11->Duration = 0; |
| } else { |
| bAckRequired = TRUE; |
| pHeader_802_11->Duration = |
| RTMPCalcDuration(pAd, MlmeRate, 14); |
| if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) |
| && (pHeader_802_11->FC.Type == BTYPE_MGMT)) { |
| bInsertTimestamp = TRUE; |
| bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Response */ |
| } else |
| if ((pHeader_802_11->FC.SubType == |
| SUBTYPE_PROBE_REQ) |
| && (pHeader_802_11->FC.Type == BTYPE_MGMT)) { |
| bAckRequired = FALSE; /* Disable ACK to prevent retry 0x1f for Probe Request */ |
| } |
| } |
| } |
| |
| 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->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("MlmeHardTransmit --> radar detect not in normal mode!\n")); |
| /* if (!IrqState) */ |
| RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); |
| 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 */ |
| /* pAd->CommonCfg.MlmeTransmit.field.MODE = 1; */ |
| |
| /* management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. */ |
| PID = PID_MGMT; |
| |
| if (pMacEntry == NULL) { |
| RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, |
| FALSE, bAckRequired, FALSE, 0, RESERVED_WCID, |
| (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID, 0, |
| (u8)pAd->CommonCfg.MlmeTransmit.field.MCS, |
| IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); |
| } else { |
| /* dont use low rate to send QoS Null data frame */ |
| RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, |
| bInsertTimestamp, FALSE, bAckRequired, FALSE, |
| 0, pMacEntry->Aid, |
| (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), |
| pMacEntry->MaxHTPhyMode.field.MCS, 0, |
| (u8)pMacEntry->MaxHTPhyMode.field.MCS, |
| IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); |
| } |
| |
| /* Now do hardware-depened kick out. */ |
| HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); |
| |
| /* Make sure to release MGMT ring resource */ |
| /* if (!IrqState) */ |
| RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); |
| 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 u8 TxPktClassification(struct rt_rtmp_adapter *pAd, void *pPacket) |
| { |
| u8 TxFrameType = TX_UNKOWN_FRAME; |
| u8 Wcid; |
| struct rt_mac_table_entry *pMacEntry = NULL; |
| BOOLEAN bHTRate = FALSE; |
| |
| Wcid = RTMP_GET_PACKET_WCID(pPacket); |
| if (Wcid == MCAST_WCID) { /* Handle for RA is Broadcast/Multicast Address. */ |
| return TX_MCAST_FRAME; |
| } |
| /* Handle for unicast packets */ |
| pMacEntry = &pAd->MacTab.Content[Wcid]; |
| if (RTMP_GET_PACKET_LOWRATE(pPacket)) { /* It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame */ |
| TxFrameType = TX_LEGACY_FRAME; |
| } else if (IS_HT_RATE(pMacEntry)) { /* it's a 11n capable packet */ |
| |
| /* Depends on HTPhyMode to check if the peer support the HTRate transmission. */ |
| /* Currently didn't support A-MSDU embedded in A-MPDU */ |
| bHTRate = TRUE; |
| if (RTMP_GET_PACKET_MOREDATA(pPacket) |
| || (pMacEntry->PsMode == PWR_SAVE)) |
| TxFrameType = TX_LEGACY_FRAME; |
| else 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)) |
| return TX_AMSDU_FRAME; |
| else |
| TxFrameType = TX_LEGACY_FRAME; |
| } 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)))) { /* if peer support Ralink Aggregation, we use it. */ |
| TxFrameType = TX_RALINK_FRAME; |
| } else { |
| TxFrameType = TX_LEGACY_FRAME; |
| } |
| } |
| |
| /* Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. */ |
| if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) |
| && (TxFrameType == TX_LEGACY_FRAME)) |
| TxFrameType = TX_FRAG_FRAME; |
| |
| return TxFrameType; |
| } |
| |
| BOOLEAN RTMP_FillTxBlkInfo(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| struct rt_packet_info PacketInfo; |
| void *pPacket; |
| struct rt_mac_table_entry *pMacEntry = NULL; |
| |
| pPacket = pTxBlk->pPacket; |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, |
| &pTxBlk->SrcBufLen); |
| |
| pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); |
| pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); |
| pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); |
| pTxBlk->FrameGap = IFS_HTTXOP; /* ASIC determine Frame Gap */ |
| |
| if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); |
| else |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); |
| |
| /* Default to clear this flag */ |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); |
| |
| if (pTxBlk->Wcid == MCAST_WCID) { |
| pTxBlk->pMacEntry = NULL; |
| { |
| pTxBlk->pTransmit = |
| &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; |
| } |
| |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); /* AckRequired = FALSE, when broadcast packet in Adhoc mode. */ |
| /*TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); */ |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); |
| if (RTMP_GET_PACKET_MOREDATA(pPacket)) { |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); |
| } |
| |
| } else { |
| pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; |
| pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; |
| |
| pMacEntry = pTxBlk->pMacEntry; |
| |
| /* For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. */ |
| if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); |
| else |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); |
| |
| if ((pAd->OpMode == OPMODE_STA) && |
| (ADHOC_ON(pAd)) && |
| (RX_FILTER_TEST_FLAG(pAd, fRX_FILTER_ACCEPT_PROMISCUOUS))) { |
| if (pAd->CommonCfg.PSPXlink) |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); |
| } |
| |
| { |
| { |
| |
| /* 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); |
| |
| /* if (pAd->StaCfg.bAutoTxRateSwitch) */ |
| /* TX_BLK_SET_FLAG(pTxBlk, fTX_AutoRateSwitch); */ |
| } |
| } |
| |
| if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) { |
| if ((RTMP_GET_PACKET_LOWRATE(pPacket)) || ((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 = |
| &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; |
| |
| /* 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); |
| TX_BLK_SET_FLAG(pTxBlk, |
| fTX_bForceNonQoS); |
| } |
| } |
| |
| 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); |
| } |
| |
| if (RTMP_GET_PACKET_MOREDATA(pPacket)) { |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); |
| } |
| } else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) { |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); |
| } |
| |
| pMacEntry->DebugTxCount++; |
| } |
| |
| return TRUE; |
| } |
| |
| BOOLEAN CanDoAggregateTransmit(struct rt_rtmp_adapter *pAd, |
| char * pPacket, struct rt_tx_blk *pTxBlk) |
| { |
| |
| /*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)) |
| 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; |
| } |
| |
| if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) /* must be unicast to AP */ |
| 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(struct rt_rtmp_adapter *pAd, IN BOOLEAN bIntContext, u8 QIdx, /* BulkOutPipeId */ |
| u8 Max_Tx_Packets) |
| { |
| struct rt_queue_entry *pEntry = NULL; |
| void *pPacket; |
| int Status = NDIS_STATUS_SUCCESS; |
| u8 Count = 0; |
| struct rt_queue_header *pQueue; |
| unsigned long FreeNumber[NUM_OF_TX_RING]; |
| u8 QueIdx, sQIdx, eQIdx; |
| unsigned long IrqFlags = 0; |
| BOOLEAN hasTxDesc = FALSE; |
| struct rt_tx_blk TxBlk; |
| struct rt_tx_blk *pTxBlk; |
| |
| if (QIdx == NUM_OF_TX_RING) { |
| sQIdx = 0; |
| eQIdx = 3; /* 4 ACs, start from 0. */ |
| } else { |
| sQIdx = eQIdx = QIdx; |
| } |
| |
| for (QueIdx = sQIdx; QueIdx <= eQIdx; QueIdx++) { |
| Count = 0; |
| |
| RTMP_START_DEQUEUE(pAd, QueIdx, IrqFlags); |
| |
| while (1) { |
| if ((RTMP_TEST_FLAG |
| (pAd, |
| (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)))) { |
| RTMP_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); |
| return; |
| } |
| |
| if (Count >= Max_Tx_Packets) |
| break; |
| |
| DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); |
| if (&pAd->TxSwQueue[QueIdx] == NULL) { |
| DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, |
| IrqFlags); |
| break; |
| } |
| #ifdef RTMP_MAC_PCI |
| FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); |
| |
| if (FreeNumber[QueIdx] <= 5) { |
| /* free Tx(QueIdx) resources */ |
| RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); |
| FreeNumber[QueIdx] = |
| GET_TXRING_FREENO(pAd, QueIdx); |
| } |
| #endif /* RTMP_MAC_PCI // */ |
| |
| /* probe the Queue Head */ |
| pQueue = &pAd->TxSwQueue[QueIdx]; |
| pEntry = pQueue->Head; |
| if (pEntry == NULL) { |
| DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, |
| IrqFlags); |
| break; |
| } |
| |
| pTxBlk = &TxBlk; |
| NdisZeroMemory((u8 *)pTxBlk, sizeof(struct rt_tx_blk)); |
| /*InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. */ |
| pTxBlk->QueIdx = QueIdx; |
| |
| pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); |
| |
| /* Early check to make sure we have enoguh Tx Resource. */ |
| hasTxDesc = |
| RTMP_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, |
| FreeNumber[QueIdx], |
| pPacket); |
| if (!hasTxDesc) { |
| pAd->PrivateInfo.TxRingFullCnt++; |
| |
| DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, |
| IrqFlags); |
| |
| break; |
| } |
| |
| pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); |
| pEntry = RemoveHeadQueue(pQueue); |
| pTxBlk->TotalFrameNum++; |
| pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); /* The real fragment number maybe vary */ |
| pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); |
| pTxBlk->pPacket = pPacket; |
| InsertTailQueue(&pTxBlk->TxPacketList, |
| PACKET_TO_QUEUE_ENTRY(pPacket)); |
| |
| if (pTxBlk->TxFrameType == TX_RALINK_FRAME |
| || pTxBlk->TxFrameType == TX_AMSDU_FRAME) { |
| /* Enhance SW Aggregation Mechanism */ |
| if (NEED_QUEUE_BACK_FOR_AGG |
| (pAd, QueIdx, FreeNumber[QueIdx], |
| pTxBlk->TxFrameType)) { |
| InsertHeadQueue(pQueue, |
| PACKET_TO_QUEUE_ENTRY |
| (pPacket)); |
| DEQUEUE_UNLOCK(&pAd->irq_lock, |
| bIntContext, IrqFlags); |
| break; |
| } |
| |
| do { |
| pEntry = pQueue->Head; |
| if (pEntry == NULL) |
| break; |
| |
| /* For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. */ |
| pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); |
| FreeNumber[QueIdx] = |
| GET_TXRING_FREENO(pAd, QueIdx); |
| hasTxDesc = |
| RTMP_HAS_ENOUGH_FREE_DESC(pAd, |
| pTxBlk, |
| FreeNumber |
| [QueIdx], |
| pPacket); |
| if ((hasTxDesc == FALSE) |
| || |
| (CanDoAggregateTransmit |
| (pAd, pPacket, pTxBlk) == FALSE)) |
| break; |
| |
| /*Remove the packet from the TxSwQueue and insert into pTxBlk */ |
| pEntry = RemoveHeadQueue(pQueue); |
| ASSERT(pEntry); |
| pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); |
| pTxBlk->TotalFrameNum++; |
| pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); /* The real fragment number maybe vary */ |
| pTxBlk->TotalFrameLen += |
| GET_OS_PKT_LEN(pPacket); |
| InsertTailQueue(&pTxBlk->TxPacketList, |
| PACKET_TO_QUEUE_ENTRY |
| (pPacket)); |
| } while (1); |
| |
| if (pTxBlk->TxPacketList.Number == 1) |
| pTxBlk->TxFrameType = TX_LEGACY_FRAME; |
| } |
| #ifdef RTMP_MAC_USB |
| DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); |
| #endif /* RTMP_MAC_USB // */ |
| Count += pTxBlk->TxPacketList.Number; |
| |
| /* Do HardTransmit now. */ |
| Status = STAHardTransmit(pAd, pTxBlk, QueIdx); |
| |
| #ifdef RTMP_MAC_PCI |
| DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); |
| /* static rate also need NICUpdateFifoStaCounters() function. */ |
| /*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ |
| NICUpdateFifoStaCounters(pAd); |
| #endif /* RTMP_MAC_PCI // */ |
| |
| } |
| |
| RTMP_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); |
| |
| #ifdef RTMP_MAC_USB |
| if (!hasTxDesc) |
| RTUSBKickBulkOut(pAd); |
| #endif /* RTMP_MAC_USB // */ |
| } |
| |
| } |
| |
| /* |
| ======================================================================== |
| |
| 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: |
| |
| ======================================================================== |
| */ |
| u16 RTMPCalcDuration(struct rt_rtmp_adapter *pAd, u8 Rate, unsigned long Size) |
| { |
| unsigned long 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 += (u16)((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 * (u16)((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 (u16)Duration; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Calculates the duration which is required to transmit out frames |
| with given size and specified rate. |
| |
| Arguments: |
| pTxWI Pointer to head of each MPDU to HW. |
| Ack Setting for Ack requirement bit |
| Fragment Setting for Fragment bit |
| RetryMode Setting for retry mode |
| Ifs Setting for IFS gap |
| Rate Setting for transmit rate |
| Service Setting for service |
| Length Frame length |
| TxPreamble Short or Long preamble when using CCK rates |
| QueIdx - 0-3, according to 802.11e/d4.4 June/2003 |
| |
| Return Value: |
| None |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| See also : BASmartHardTransmit() ! |
| |
| ======================================================================== |
| */ |
| void RTMPWriteTxWI(struct rt_rtmp_adapter *pAd, struct rt_txwi * pOutTxWI, IN BOOLEAN FRAG, IN BOOLEAN CFACK, IN BOOLEAN InsTimestamp, IN BOOLEAN AMPDU, IN BOOLEAN Ack, IN BOOLEAN NSeq, /* HW new a sequence. */ |
| u8 BASize, |
| u8 WCID, |
| unsigned long Length, |
| u8 PID, |
| u8 TID, |
| u8 TxRate, |
| u8 Txopmode, |
| IN BOOLEAN CfAck, IN HTTRANSMIT_SETTING * pTransmit) |
| { |
| struct rt_mac_table_entry *pMac = NULL; |
| struct rt_txwi TxWI; |
| struct rt_txwi * pTxWI; |
| |
| if (WCID < MAX_LEN_OF_MAC_TABLE) |
| pMac = &pAd->MacTab.Content[WCID]; |
| |
| /* */ |
| /* Always use Long preamble before verifiation short preamble functionality works well. */ |
| /* Todo: remove the following line if short preamble functionality works */ |
| /* */ |
| OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
| NdisZeroMemory(&TxWI, TXWI_SIZE); |
| pTxWI = &TxWI; |
| |
| pTxWI->FRAG = FRAG; |
| |
| pTxWI->CFACK = CFACK; |
| pTxWI->TS = InsTimestamp; |
| pTxWI->AMPDU = AMPDU; |
| pTxWI->ACK = Ack; |
| pTxWI->txop = Txopmode; |
| |
| pTxWI->NSEQ = NSeq; |
| /* John tune the performace with Intel Client in 20 MHz performance */ |
| BASize = pAd->CommonCfg.TxBASize; |
| if (pAd->MACVersion == 0x28720200) { |
| if (BASize > 13) |
| BASize = 13; |
| } else { |
| if (BASize > 7) |
| BASize = 7; |
| } |
| pTxWI->BAWinSize = BASize; |
| pTxWI->ShortGI = pTransmit->field.ShortGI; |
| pTxWI->STBC = pTransmit->field.STBC; |
| |
| pTxWI->WirelessCliID = WCID; |
| pTxWI->MPDUtotalByteCount = Length; |
| pTxWI->PacketId = PID; |
| |
| /* If CCK or OFDM, BW must be 20 */ |
| pTxWI->BW = |
| (pTransmit->field.MODE <= |
| MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); |
| |
| pTxWI->MCS = pTransmit->field.MCS; |
| pTxWI->PHYMODE = pTransmit->field.MODE; |
| pTxWI->CFACK = CfAck; |
| |
| if (pMac) { |
| if (pAd->CommonCfg.bMIMOPSEnable) { |
| if ((pMac->MmpsMode == MMPS_DYNAMIC) |
| && (pTransmit->field.MCS > 7)) { |
| /* Dynamic MIMO Power Save Mode */ |
| pTxWI->MIMOps = 1; |
| } else if (pMac->MmpsMode == MMPS_STATIC) { |
| /* Static MIMO Power Save Mode */ |
| if (pTransmit->field.MODE >= MODE_HTMIX |
| && pTransmit->field.MCS > 7) { |
| pTxWI->MCS = 7; |
| pTxWI->MIMOps = 0; |
| } |
| } |
| } |
| /*pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; */ |
| if (pMac->bIAmBadAtheros |
| && (pMac->WepStatus != Ndis802_11WEPDisabled)) { |
| pTxWI->MpduDensity = 7; |
| } else { |
| pTxWI->MpduDensity = pMac->MpduDensity; |
| } |
| } |
| |
| pTxWI->PacketId = pTxWI->MCS; |
| NdisMoveMemory(pOutTxWI, &TxWI, sizeof(struct rt_txwi)); |
| } |
| |
| void RTMPWriteTxWI_Data(struct rt_rtmp_adapter *pAd, |
| struct rt_txwi * pTxWI, struct rt_tx_blk *pTxBlk) |
| { |
| HTTRANSMIT_SETTING *pTransmit; |
| struct rt_mac_table_entry *pMacEntry; |
| u8 BASize; |
| |
| ASSERT(pTxWI); |
| |
| pTransmit = pTxBlk->pTransmit; |
| pMacEntry = pTxBlk->pMacEntry; |
| |
| /* */ |
| /* Always use Long preamble before verifiation short preamble functionality works well. */ |
| /* Todo: remove the following line if short preamble functionality works */ |
| /* */ |
| OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
| NdisZeroMemory(pTxWI, TXWI_SIZE); |
| |
| pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); |
| pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); |
| pTxWI->txop = pTxBlk->FrameGap; |
| |
| pTxWI->WirelessCliID = pTxBlk->Wcid; |
| |
| pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; |
| pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); |
| |
| /* If CCK or OFDM, BW must be 20 */ |
| pTxWI->BW = |
| (pTransmit->field.MODE <= |
| MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); |
| pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); |
| |
| /* John tune the performace with Intel Client in 20 MHz performance */ |
| BASize = pAd->CommonCfg.TxBASize; |
| if ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) { |
| u8 RABAOriIdx = 0; /*The RA's BA Originator table index. */ |
| |
| RABAOriIdx = |
| pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; |
| BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; |
| } |
| |
| pTxWI->TxBF = pTransmit->field.TxBF; |
| pTxWI->BAWinSize = BASize; |
| pTxWI->ShortGI = pTransmit->field.ShortGI; |
| pTxWI->STBC = pTransmit->field.STBC; |
| |
| pTxWI->MCS = pTransmit->field.MCS; |
| pTxWI->PHYMODE = pTransmit->field.MODE; |
| |
| if (pMacEntry) { |
| if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) |
| && (pTransmit->field.MCS > 7)) { |
| /* Dynamic MIMO Power Save Mode */ |
| pTxWI->MIMOps = 1; |
| } else if (pMacEntry->MmpsMode == MMPS_STATIC) { |
| /* Static MIMO Power Save Mode */ |
| if (pTransmit->field.MODE >= MODE_HTMIX |
| && pTransmit->field.MCS > 7) { |
| pTxWI->MCS = 7; |
| pTxWI->MIMOps = 0; |
| } |
| } |
| |
| if (pMacEntry->bIAmBadAtheros |
| && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) { |
| pTxWI->MpduDensity = 7; |
| } else { |
| pTxWI->MpduDensity = pMacEntry->MpduDensity; |
| } |
| } |
| |
| /* for rate adapation */ |
| pTxWI->PacketId = pTxWI->MCS; |
| } |
| |
| void RTMPWriteTxWI_Cache(struct rt_rtmp_adapter *pAd, |
| struct rt_txwi * pTxWI, struct rt_tx_blk *pTxBlk) |
| { |
| PHTTRANSMIT_SETTING /*pTxHTPhyMode, */ pTransmit; |
| struct rt_mac_table_entry *pMacEntry; |
| |
| /* */ |
| /* update TXWI */ |
| /* */ |
| pMacEntry = pTxBlk->pMacEntry; |
| pTransmit = pTxBlk->pTransmit; |
| |
| /*if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ |
| /*if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pMacEntry)) */ |
| /*if (TX_BLK_TEST_FLAG(pTxBlk, fTX_AutoRateSwitch)) */ |
| if (pMacEntry->bAutoTxRateSwitch) { |
| pTxWI->txop = IFS_HTTXOP; |
| |
| /* If CCK or OFDM, BW must be 20 */ |
| pTxWI->BW = |
| (pTransmit->field.MODE <= |
| MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); |
| pTxWI->ShortGI = pTransmit->field.ShortGI; |
| pTxWI->STBC = pTransmit->field.STBC; |
| |
| pTxWI->MCS = pTransmit->field.MCS; |
| pTxWI->PHYMODE = pTransmit->field.MODE; |
| |
| /* set PID for TxRateSwitching */ |
| pTxWI->PacketId = pTransmit->field.MCS; |
| } |
| |
| pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE : FALSE); |
| pTxWI->MIMOps = 0; |
| |
| if (pAd->CommonCfg.bMIMOPSEnable) { |
| /* MIMO Power Save Mode */ |
| if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) |
| && (pTransmit->field.MCS > 7)) { |
| /* Dynamic MIMO Power Save Mode */ |
| pTxWI->MIMOps = 1; |
| } else if (pMacEntry->MmpsMode == MMPS_STATIC) { |
| /* Static MIMO Power Save Mode */ |
| if ((pTransmit->field.MODE >= MODE_HTMIX) |
| && (pTransmit->field.MCS > 7)) { |
| pTxWI->MCS = 7; |
| pTxWI->MIMOps = 0; |
| } |
| } |
| } |
| |
| pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; |
| |
| } |
| |
| /* should be called only when - */ |
| /* 1. MEADIA_CONNECTED */ |
| /* 2. AGGREGATION_IN_USED */ |
| /* 3. Fragmentation not in used */ |
| /* 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible */ |
| BOOLEAN TxFrameIsAggregatible(struct rt_rtmp_adapter *pAd, |
| u8 *pPrevAddr1, u8 *p8023hdr) |
| { |
| |
| /* can't aggregate EAPOL (802.1x) frame */ |
| if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) |
| return FALSE; |
| |
| /* can't aggregate multicast/broadcast frame */ |
| if (p8023hdr[0] & 0x01) |
| return FALSE; |
| |
| if (INFRA_ON(pAd)) /* must be unicast to AP */ |
| return TRUE; |
| else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) /* unicast to same STA */ |
| return TRUE; |
| else |
| return FALSE; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Check the MSDU Aggregation policy |
| 1.HT aggregation is A-MSDU |
| 2.legaacy rate aggregation is software aggregation by Ralink. |
| |
| Arguments: |
| |
| Return Value: |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| BOOLEAN PeerIsAggreOn(struct rt_rtmp_adapter *pAd, |
| unsigned long TxRate, struct rt_mac_table_entry *pMacEntry) |
| { |
| unsigned long AFlags = |
| (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); |
| |
| if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) { |
| if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) { |
| return TRUE; |
| } |
| #ifdef AGGREGATION_SUPPORT |
| if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) { /* legacy Ralink Aggregation support */ |
| return TRUE; |
| } |
| #endif /* AGGREGATION_SUPPORT // */ |
| } |
| |
| return FALSE; |
| |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Check and fine the packet waiting in SW queue with highest priority |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| pQueue Pointer to Waiting Queue |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| struct rt_queue_header *RTMPCheckTxSwQueue(struct rt_rtmp_adapter *pAd, u8 *pQueIdx) |
| { |
| |
| unsigned long Number; |
| /* 2004-11-15 to be removed. test aggregation only */ |
| /* if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) */ |
| /* return NULL; */ |
| |
| Number = pAd->TxSwQueue[QID_AC_BK].Number |
| + pAd->TxSwQueue[QID_AC_BE].Number |
| + pAd->TxSwQueue[QID_AC_VI].Number |
| + pAd->TxSwQueue[QID_AC_VO].Number; |
| |
| if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) { |
| *pQueIdx = QID_AC_VO; |
| return (&pAd->TxSwQueue[QID_AC_VO]); |
| } else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) { |
| *pQueIdx = QID_AC_VI; |
| return (&pAd->TxSwQueue[QID_AC_VI]); |
| } else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) { |
| *pQueIdx = QID_AC_BE; |
| return (&pAd->TxSwQueue[QID_AC_BE]); |
| } else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) { |
| *pQueIdx = QID_AC_BK; |
| return (&pAd->TxSwQueue[QID_AC_BK]); |
| } |
| /* No packet pending in Tx Sw queue */ |
| *pQueIdx = QID_AC_BK; |
| |
| return (NULL); |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Suspend MSDU transmission |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| void RTMPSuspendMsduTransmission(struct rt_rtmp_adapter *pAd) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("SCANNING, suspend MSDU transmission ...\n")); |
| |
| /* */ |
| /* Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and */ |
| /* use Lowbound as R66 value on ScanNextChannel(...) */ |
| /* */ |
| RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, |
| &pAd->BbpTuning.R66CurrentValue); |
| |
| /* set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) */ |
| /*RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); */ |
| RTMPSetAGCInitValue(pAd, BW_20); |
| |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); |
| /*RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings */ |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Resume MSDU transmission |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| void RTMPResumeMsduTransmission(struct rt_rtmp_adapter *pAd) |
| { |
| /* u8 IrqState; */ |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("SCAN done, resume MSDU transmission ...\n")); |
| |
| /* After finish BSS_SCAN_IN_PROGRESS, we need to restore Current R66 value */ |
| /* R66 should not be 0 */ |
| if (pAd->BbpTuning.R66CurrentValue == 0) { |
| pAd->BbpTuning.R66CurrentValue = 0x38; |
| DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n")); |
| } |
| |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, |
| pAd->BbpTuning.R66CurrentValue); |
| |
| RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); |
| /* sample, for IRQ LOCK to SEM LOCK */ |
| /* IrqState = pAd->irq_disabled; */ |
| /* if (IrqState) */ |
| /* RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); */ |
| /* else */ |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| } |
| |
| u32 deaggregate_AMSDU_announce(struct rt_rtmp_adapter *pAd, |
| void *pPacket, |
| u8 *pData, unsigned long DataSize) |
| { |
| u16 PayloadSize; |
| u16 SubFrameSize; |
| struct rt_header_802_3 * pAMSDUsubheader; |
| u32 nMSDU; |
| u8 Header802_3[14]; |
| |
| u8 *pPayload, *pDA, *pSA, *pRemovedLLCSNAP; |
| void *pClonePacket; |
| |
| nMSDU = 0; |
| |
| while (DataSize > LENGTH_802_3) { |
| |
| nMSDU++; |
| |
| /*hex_dump("subheader", pData, 64); */ |
| pAMSDUsubheader = (struct rt_header_802_3 *) pData; |
| /*pData += LENGTH_802_3; */ |
| PayloadSize = |
| pAMSDUsubheader->Octet[1] + |
| (pAMSDUsubheader->Octet[0] << 8); |
| SubFrameSize = PayloadSize + LENGTH_802_3; |
| |
| if ((DataSize < SubFrameSize) || (PayloadSize > 1518)) { |
| break; |
| } |
| /*DBGPRINT(RT_DEBUG_TRACE,("%d subframe: Size = %d\n", nMSDU, PayloadSize)); */ |
| |
| pPayload = pData + LENGTH_802_3; |
| pDA = pData; |
| pSA = pData + MAC_ADDR_LEN; |
| |
| /* convert to 802.3 header */ |
| CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, |
| pRemovedLLCSNAP); |
| |
| if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E)) { |
| /* avoid local heap overflow, use dyanamic allocation */ |
| struct rt_mlme_queue_elem *Elem = |
| kmalloc(sizeof(struct rt_mlme_queue_elem), |
| MEM_ALLOC_FLAG); |
| if (Elem != NULL) { |
| memmove(Elem->Msg + |
| (LENGTH_802_11 + LENGTH_802_1_H), |
| pPayload, PayloadSize); |
| Elem->MsgLen = |
| LENGTH_802_11 + LENGTH_802_1_H + |
| PayloadSize; |
| /*WpaEAPOLKeyAction(pAd, Elem); */ |
| REPORT_MGMT_FRAME_TO_MLME(pAd, BSSID_WCID, |
| Elem->Msg, |
| Elem->MsgLen, 0, 0, 0, |
| 0); |
| kfree(Elem); |
| } |
| } |
| |
| { |
| if (pRemovedLLCSNAP) { |
| pPayload -= LENGTH_802_3; |
| PayloadSize += LENGTH_802_3; |
| NdisMoveMemory(pPayload, &Header802_3[0], |
| LENGTH_802_3); |
| } |
| } |
| |
| pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); |
| if (pClonePacket) { |
| ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, |
| RTMP_GET_PACKET_IF |
| (pPacket)); |
| } |
| |
| /* A-MSDU has padding to multiple of 4 including subframe header. */ |
| /* align SubFrameSize up to multiple of 4 */ |
| SubFrameSize = (SubFrameSize + 3) & (~0x3); |
| |
| if (SubFrameSize > 1528 || SubFrameSize < 32) { |
| break; |
| } |
| |
| if (DataSize > SubFrameSize) { |
| pData += SubFrameSize; |
| DataSize -= SubFrameSize; |
| } else { |
| /* end of A-MSDU */ |
| DataSize = 0; |
| } |
| } |
| |
| /* finally release original rx packet */ |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); |
| |
| return nMSDU; |
| } |
| |
| u32 BA_Reorder_AMSDU_Annnounce(struct rt_rtmp_adapter *pAd, void *pPacket) |
| { |
| u8 *pData; |
| u16 DataSize; |
| u32 nMSDU = 0; |
| |
| pData = (u8 *)GET_OS_PKT_DATAPTR(pPacket); |
| DataSize = (u16)GET_OS_PKT_LEN(pPacket); |
| |
| nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); |
| |
| return nMSDU; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Look up the MAC address in the MAC table. Return NULL if not found. |
| Return: |
| pEntry - pointer to the MAC entry; NULL is not found |
| ========================================================================== |
| */ |
| struct rt_mac_table_entry *MacTableLookup(struct rt_rtmp_adapter *pAd, u8 *pAddr) |
| { |
| unsigned long HashIdx; |
| struct rt_mac_table_entry *pEntry = NULL; |
| |
| HashIdx = MAC_ADDR_HASH_INDEX(pAddr); |
| pEntry = pAd->MacTab.Hash[HashIdx]; |
| |
| while (pEntry |
| && (pEntry->ValidAsCLI || pEntry->ValidAsWDS |
| || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) { |
| if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) { |
| break; |
| } else |
| pEntry = pEntry->pNext; |
| } |
| |
| return pEntry; |
| } |
| |
| struct rt_mac_table_entry *MacTableInsertEntry(struct rt_rtmp_adapter *pAd, |
| u8 *pAddr, |
| u8 apidx, IN BOOLEAN CleanAll) |
| { |
| u8 HashIdx; |
| int i, FirstWcid; |
| struct rt_mac_table_entry *pEntry = NULL, *pCurrEntry; |
| /* u16 offset; */ |
| /* unsigned long addr; */ |
| |
| /* if FULL, return */ |
| if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) |
| return NULL; |
| |
| FirstWcid = 1; |
| |
| if (pAd->StaCfg.BssType == BSS_INFRA) |
| FirstWcid = 2; |
| |
| /* allocate one MAC entry */ |
| NdisAcquireSpinLock(&pAd->MacTabLock); |
| for (i = FirstWcid; i < MAX_LEN_OF_MAC_TABLE; i++) /* skip entry#0 so that "entry index == AID" for fast lookup */ |
| { |
| /* pick up the first available vacancy */ |
| if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && |
| (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && |
| (pAd->MacTab.Content[i].ValidAsApCli == FALSE) && |
| (pAd->MacTab.Content[i].ValidAsMesh == FALSE) |
| ) { |
| pEntry = &pAd->MacTab.Content[i]; |
| if (CleanAll == TRUE) { |
| pEntry->MaxSupportedRate = RATE_11; |
| pEntry->CurrTxRate = RATE_11; |
| NdisZeroMemory(pEntry, sizeof(struct rt_mac_table_entry)); |
| pEntry->PairwiseKey.KeyLen = 0; |
| pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; |
| } |
| { |
| { |
| pEntry->ValidAsCLI = TRUE; |
| pEntry->ValidAsWDS = FALSE; |
| pEntry->ValidAsApCli = FALSE; |
| pEntry->ValidAsMesh = FALSE; |
| pEntry->ValidAsDls = FALSE; |
| } |
| } |
| |
| pEntry->bIAmBadAtheros = FALSE; |
| pEntry->pAd = pAd; |
| pEntry->CMTimerRunning = FALSE; |
| pEntry->EnqueueEapolStartTimerRunning = |
| EAPOL_START_DISABLE; |
| pEntry->RSNIE_Len = 0; |
| NdisZeroMemory(pEntry->R_Counter, |
| sizeof(pEntry->R_Counter)); |
| pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; |
| |
| if (pEntry->ValidAsMesh) |
| pEntry->apidx = |
| (apidx - MIN_NET_DEVICE_FOR_MESH); |
| else if (pEntry->ValidAsApCli) |
| pEntry->apidx = |
| (apidx - MIN_NET_DEVICE_FOR_APCLI); |
| else if (pEntry->ValidAsWDS) |
| pEntry->apidx = |
| (apidx - MIN_NET_DEVICE_FOR_WDS); |
| else |
| pEntry->apidx = apidx; |
| |
| { |
| { |
| pEntry->AuthMode = pAd->StaCfg.AuthMode; |
| pEntry->WepStatus = |
| pAd->StaCfg.WepStatus; |
| pEntry->PrivacyFilter = |
| Ndis802_11PrivFilterAcceptAll; |
| #ifdef RTMP_MAC_PCI |
| AsicRemovePairwiseKeyEntry(pAd, |
| pEntry-> |
| apidx, |
| (u8)i); |
| #endif /* RTMP_MAC_PCI // */ |
| } |
| } |
| |
| pEntry->GTKState = REKEY_NEGOTIATING; |
| pEntry->PairwiseKey.KeyLen = 0; |
| pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; |
| pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; |
| |
| pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; |
| COPY_MAC_ADDR(pEntry->Addr, pAddr); |
| pEntry->Sst = SST_NOT_AUTH; |
| pEntry->AuthState = AS_NOT_AUTH; |
| pEntry->Aid = (u16)i; /*0; */ |
| pEntry->CapabilityInfo = 0; |
| pEntry->PsMode = PWR_ACTIVE; |
| pEntry->PsQIdleCount = 0; |
| pEntry->NoDataIdleCount = 0; |
| pEntry->AssocDeadLine = MAC_TABLE_ASSOC_TIMEOUT; |
| pEntry->ContinueTxFailCnt = 0; |
| InitializeQueueHeader(&pEntry->PsQueue); |
| |
| pAd->MacTab.Size++; |
| /* Add this entry into ASIC RX WCID search table */ |
| RTMP_STA_ENTRY_ADD(pAd, pEntry); |
| |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MacTableInsertEntry - allocate entry #%d, Total= %d\n", |
| i, pAd->MacTab.Size)); |
| break; |
| } |
| } |
| |
| /* add this MAC entry into HASH table */ |
| if (pEntry) { |
| HashIdx = MAC_ADDR_HASH_INDEX(pAddr); |
| if (pAd->MacTab.Hash[HashIdx] == NULL) { |
| pAd->MacTab.Hash[HashIdx] = pEntry; |
| } else { |
| pCurrEntry = pAd->MacTab.Hash[HashIdx]; |
| while (pCurrEntry->pNext != NULL) |
| pCurrEntry = pCurrEntry->pNext; |
| pCurrEntry->pNext = pEntry; |
| } |
| } |
| |
| NdisReleaseSpinLock(&pAd->MacTabLock); |
| return pEntry; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Delete a specified client from MAC table |
| ========================================================================== |
| */ |
| BOOLEAN MacTableDeleteEntry(struct rt_rtmp_adapter *pAd, |
| u16 wcid, u8 *pAddr) |
| { |
| u16 HashIdx; |
| struct rt_mac_table_entry *pEntry, *pPrevEntry, *pProbeEntry; |
| BOOLEAN Cancelled; |
| /*u16 offset; // unused variable */ |
| /*u8 j; // unused variable */ |
| |
| if (wcid >= MAX_LEN_OF_MAC_TABLE) |
| return FALSE; |
| |
| NdisAcquireSpinLock(&pAd->MacTabLock); |
| |
| HashIdx = MAC_ADDR_HASH_INDEX(pAddr); |
| /*pEntry = pAd->MacTab.Hash[HashIdx]; */ |
| pEntry = &pAd->MacTab.Content[wcid]; |
| |
| if (pEntry |
| && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS |
| || pEntry->ValidAsMesh)) { |
| if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) { |
| |
| /* Delete this entry from ASIC on-chip WCID Table */ |
| RTMP_STA_ENTRY_MAC_RESET(pAd, wcid); |
| |
| /* free resources of BA */ |
| BASessionTearDownALL(pAd, pEntry->Aid); |
| |
| pPrevEntry = NULL; |
| pProbeEntry = pAd->MacTab.Hash[HashIdx]; |
| ASSERT(pProbeEntry); |
| |
| /* update Hash list */ |
| do { |
| if (pProbeEntry == pEntry) { |
| if (pPrevEntry == NULL) { |
| pAd->MacTab.Hash[HashIdx] = |
| pEntry->pNext; |
| } else { |
| pPrevEntry->pNext = |
| pEntry->pNext; |
| } |
| break; |
| } |
| |
| pPrevEntry = pProbeEntry; |
| pProbeEntry = pProbeEntry->pNext; |
| } while (pProbeEntry); |
| |
| /* not found ! */ |
| ASSERT(pProbeEntry != NULL); |
| |
| RTMP_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); |
| |
| if (pEntry->EnqueueEapolStartTimerRunning != |
| EAPOL_START_DISABLE) { |
| RTMPCancelTimer(&pEntry-> |
| EnqueueStartForPSKTimer, |
| &Cancelled); |
| pEntry->EnqueueEapolStartTimerRunning = |
| EAPOL_START_DISABLE; |
| } |
| |
| NdisZeroMemory(pEntry, sizeof(struct rt_mac_table_entry)); |
| pAd->MacTab.Size--; |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("MacTableDeleteEntry1 - Total= %d\n", |
| pAd->MacTab.Size)); |
| } else { |
| DBGPRINT(RT_DEBUG_OFF, |
| ("\n%s: Impossible Wcid = %d !\n", |
| __func__, wcid)); |
| } |
| } |
| |
| NdisReleaseSpinLock(&pAd->MacTabLock); |
| |
| /*Reset operating mode when no Sta. */ |
| if (pAd->MacTab.Size == 0) { |
| pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; |
| RTMP_UPDATE_PROTECT(pAd); /* edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet */ |
| } |
| |
| return TRUE; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine reset the entire MAC table. All packets pending in |
| the power-saving queues are freed here. |
| ========================================================================== |
| */ |
| void MacTableReset(struct rt_rtmp_adapter *pAd) |
| { |
| int i; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); |
| /*NdisAcquireSpinLock(&pAd->MacTabLock); */ |
| |
| for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) { |
| #ifdef RTMP_MAC_PCI |
| RTMP_STA_ENTRY_MAC_RESET(pAd, i); |
| #endif /* RTMP_MAC_PCI // */ |
| if (pAd->MacTab.Content[i].ValidAsCLI == TRUE) { |
| |
| /* free resources of BA */ |
| BASessionTearDownALL(pAd, i); |
| |
| pAd->MacTab.Content[i].ValidAsCLI = FALSE; |
| |
| #ifdef RTMP_MAC_USB |
| NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); |
| RTMP_STA_ENTRY_MAC_RESET(pAd, i); |
| #endif /* RTMP_MAC_USB // */ |
| |
| /*AsicDelWcidTab(pAd, i); */ |
| } |
| } |
| |
| return; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| void AssocParmFill(struct rt_rtmp_adapter *pAd, |
| struct rt_mlme_assoc_req *AssocReq, |
| u8 *pAddr, |
| u16 CapabilityInfo, |
| unsigned long Timeout, u16 ListenIntv) |
| { |
| COPY_MAC_ADDR(AssocReq->Addr, pAddr); |
| /* Add mask to support 802.11b mode only */ |
| AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; /* not cf-pollable, not cf-poll-request */ |
| AssocReq->Timeout = Timeout; |
| AssocReq->ListenIntv = ListenIntv; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| void DisassocParmFill(struct rt_rtmp_adapter *pAd, |
| struct rt_mlme_disassoc_req *DisassocReq, |
| u8 *pAddr, u16 Reason) |
| { |
| COPY_MAC_ADDR(DisassocReq->Addr, pAddr); |
| DisassocReq->Reason = Reason; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Check the out going frame, if this is an DHCP or ARP datagram |
| will be duplicate another frame at low data rate transmit. |
| |
| Arguments: |
| pAd Pointer to our adapter |
| pPacket Pointer to outgoing Ndis frame |
| |
| Return Value: |
| TRUE To be duplicate at Low data rate transmit. (1mb) |
| FALSE Do nothing. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| MAC header + IP Header + UDP Header |
| 14 Bytes 20 Bytes |
| |
| UDP Header |
| 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| |
| Source Port |
| 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| |
| Destination Port |
| |
| port 0x43 means Bootstrap Protocol, server. |
| Port 0x44 means Bootstrap Protocol, client. |
| |
| ======================================================================== |
| */ |
| |
| BOOLEAN RTMPCheckDHCPFrame(struct rt_rtmp_adapter *pAd, void *pPacket) |
| { |
| struct rt_packet_info PacketInfo; |
| unsigned long NumberOfBytesRead = 0; |
| unsigned long CurrentOffset = 0; |
| void *pVirtualAddress = NULL; |
| u32 NdisBufferLength; |
| u8 *pSrc; |
| u16 Protocol; |
| u8 ByteOffset36 = 0; |
| u8 ByteOffset38 = 0; |
| BOOLEAN ReadFirstParm = TRUE; |
| |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, (u8 **) & pVirtualAddress, |
| &NdisBufferLength); |
| |
| NumberOfBytesRead += NdisBufferLength; |
| pSrc = (u8 *)pVirtualAddress; |
| Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); |
| |
| /* */ |
| /* Check DHCP & BOOTP protocol */ |
| /* */ |
| while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) { |
| if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) { |
| CurrentOffset = |
| 35 - (NumberOfBytesRead - NdisBufferLength); |
| ByteOffset36 = *(pSrc + CurrentOffset); |
| ReadFirstParm = FALSE; |
| } |
| |
| if (NumberOfBytesRead >= 37) { |
| CurrentOffset = |
| 37 - (NumberOfBytesRead - NdisBufferLength); |
| ByteOffset38 = *(pSrc + CurrentOffset); |
| /*End of Read */ |
| break; |
| } |
| return FALSE; |
| } |
| |
| /* Check for DHCP & BOOTP protocol */ |
| if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) { |
| /* */ |
| /* 2054 (hex 0806) for ARP datagrams */ |
| /* if this packet is not ARP datagrams, then do nothing */ |
| /* ARP datagrams will also be duplicate at 1mb broadcast frames */ |
| /* */ |
| if (Protocol != 0x0806) |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| BOOLEAN RTMPCheckEtherType(struct rt_rtmp_adapter *pAd, void *pPacket) |
| { |
| u16 TypeLen; |
| u8 Byte0, Byte1; |
| u8 *pSrcBuf; |
| u32 pktLen; |
| u16 srcPort, dstPort; |
| BOOLEAN status = TRUE; |
| |
| pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); |
| pktLen = GET_OS_PKT_LEN(pPacket); |
| |
| ASSERT(pSrcBuf); |
| |
| RTMP_SET_PACKET_SPECIFIC(pPacket, 0); |
| |
| /* get Ethernet protocol field */ |
| TypeLen = (pSrcBuf[12] << 8) | pSrcBuf[13]; |
| |
| pSrcBuf += LENGTH_802_3; /* Skip the Ethernet Header. */ |
| |
| 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)) |
| */ |
| if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA |
| && pSrcBuf[2] == 0x03) { |
| Sniff2BytesFromNdisBuffer((char *)pSrcBuf, 6, |
| &Byte0, &Byte1); |
| RTMP_SET_PACKET_LLCSNAP(pPacket, 1); |
| TypeLen = (u16)((Byte0 << 8) + Byte1); |
| pSrcBuf += 8; /* Skip this LLC/SNAP header */ |
| } else { |
| /*It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. */ |
| } |
| } |
| /* If it's a VLAN packet, get the real Type/Length field. */ |
| if (TypeLen == 0x8100) { |
| /* 0x8100 means VLAN packets */ |
| |
| /* Dest. MAC Address (6-bytes) + |
| Source MAC Address (6-bytes) + |
| Length/Type = 802.1Q Tag Type (2-byte) + |
| Tag Control Information (2-bytes) + |
| Length / Type (2-bytes) + |
| data payload (0-n bytes) + |
| Pad (0-p bytes) + |
| Frame Check Sequence (4-bytes) */ |
| |
| RTMP_SET_PACKET_VLAN(pPacket, 1); |
| Sniff2BytesFromNdisBuffer((char *)pSrcBuf, 2, &Byte0, |
| &Byte1); |
| TypeLen = (u16)((Byte0 << 8) + Byte1); |
| |
| pSrcBuf += 4; /* Skip the VLAN Header. */ |
| } |
| |
| switch (TypeLen) { |
| case 0x0800: |
| { |
| ASSERT((pktLen > 34)); |
| if (*(pSrcBuf + 9) == 0x11) { /* udp packet */ |
| ASSERT((pktLen > 34)); /* 14 for ethernet header, 20 for IP header */ |
| |
| pSrcBuf += 20; /* Skip the IP header */ |
| srcPort = |
| OS_NTOHS(get_unaligned |
| ((u16 *)(pSrcBuf))); |
| dstPort = |
| OS_NTOHS(get_unaligned |
| ((u16 *)(pSrcBuf + 2))); |
| |
| if ((srcPort == 0x44 && dstPort == 0x43) || (srcPort == 0x43 && dstPort == 0x44)) { /*It's a BOOTP/DHCP packet */ |
| RTMP_SET_PACKET_DHCP(pPacket, 1); |
| } |
| } |
| } |
| break; |
| case 0x0806: |
| { |
| /*ARP Packet. */ |
| RTMP_SET_PACKET_DHCP(pPacket, 1); |
| } |
| break; |
| case 0x888e: |
| { |
| /* EAPOL Packet. */ |
| RTMP_SET_PACKET_EAPOL(pPacket, 1); |
| } |
| break; |
| default: |
| status = FALSE; |
| break; |
| } |
| |
| return status; |
| |
| } |
| |
| void Update_Rssi_Sample(struct rt_rtmp_adapter *pAd, |
| struct rt_rssi_sample *pRssi, struct rt_rxwi * pRxWI) |
| { |
| char rssi0 = pRxWI->RSSI0; |
| char rssi1 = pRxWI->RSSI1; |
| char rssi2 = pRxWI->RSSI2; |
| |
| if (rssi0 != 0) { |
| pRssi->LastRssi0 = ConvertToRssi(pAd, (char)rssi0, RSSI_0); |
| pRssi->AvgRssi0X8 = |
| (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; |
| pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; |
| } |
| |
| if (rssi1 != 0) { |
| pRssi->LastRssi1 = ConvertToRssi(pAd, (char)rssi1, RSSI_1); |
| pRssi->AvgRssi1X8 = |
| (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; |
| pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; |
| } |
| |
| if (rssi2 != 0) { |
| pRssi->LastRssi2 = ConvertToRssi(pAd, (char)rssi2, RSSI_2); |
| pRssi->AvgRssi2X8 = |
| (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; |
| pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; |
| } |
| } |
| |
| /* Normal legacy Rx packet indication */ |
| void Indicate_Legacy_Packet(struct rt_rtmp_adapter *pAd, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| void *pRxPacket = pRxBlk->pRxPacket; |
| u8 Header802_3[LENGTH_802_3]; |
| |
| /* 1. get 802.3 Header */ |
| /* 2. remove LLC */ |
| /* a. pointer pRxBlk->pData to payload */ |
| /* b. modify pRxBlk->DataSize */ |
| RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); |
| |
| if (pRxBlk->DataSize > MAX_RX_PKT_LEN) { |
| |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); |
| |
| #ifdef RTMP_MAC_USB |
| if (pAd->CommonCfg.bDisableReordering == 0) { |
| struct rt_ba_rec_entry *pBAEntry; |
| unsigned long Now32; |
| u8 Wcid = pRxBlk->pRxWI->WirelessCliID; |
| u8 TID = pRxBlk->pRxWI->TID; |
| u16 Idx; |
| |
| #define REORDERING_PACKET_TIMEOUT ((100 * OS_HZ)/1000) /* system ticks -- 100 ms */ |
| |
| if (Wcid < MAX_LEN_OF_MAC_TABLE) { |
| Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; |
| if (Idx != 0) { |
| pBAEntry = &pAd->BATable.BARecEntry[Idx]; |
| /* update last rx time */ |
| NdisGetSystemUpTime(&Now32); |
| if ((pBAEntry->list.qlen > 0) && |
| RTMP_TIME_AFTER((unsigned long)Now32, |
| (unsigned long)(pBAEntry-> |
| LastIndSeqAtTimer |
| + |
| (REORDERING_PACKET_TIMEOUT))) |
| ) { |
| DBGPRINT(RT_DEBUG_OFF, |
| ("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", |
| pRxBlk->Flags, |
| pRxBlk->pRxWI->TID, |
| pRxBlk->RxD.AMPDU)); |
| hex_dump("Dump the legacy Packet:", |
| GET_OS_PKT_DATAPTR(pRxBlk-> |
| pRxPacket), |
| 64); |
| ba_flush_reordering_timeout_mpdus(pAd, |
| pBAEntry, |
| Now32); |
| } |
| } |
| } |
| } |
| #endif /* RTMP_MAC_USB // */ |
| |
| wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); |
| |
| /* */ |
| /* pass this 802.3 packet to upper layer or forward this packet to WM directly */ |
| /* */ |
| ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); |
| } |
| |
| /* Normal, AMPDU or AMSDU */ |
| void CmmRxnonRalinkFrameIndicate(struct rt_rtmp_adapter *pAd, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) |
| && (pAd->CommonCfg.bDisableReordering == 0)) { |
| Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); |
| } else { |
| if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) { |
| /* handle A-MSDU */ |
| Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); |
| } else { |
| Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); |
| } |
| } |
| } |
| |
| void CmmRxRalinkFrameIndicate(struct rt_rtmp_adapter *pAd, |
| struct rt_mac_table_entry *pEntry, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| u8 Header802_3[LENGTH_802_3]; |
| u16 Msdu2Size; |
| u16 Payload1Size, Payload2Size; |
| u8 *pData2; |
| void *pPacket2 = NULL; |
| |
| Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData + 1) << 8); |
| |
| if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) { |
| /* skip two byte MSDU2 len */ |
| pRxBlk->pData += 2; |
| pRxBlk->DataSize -= 2; |
| } else { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| /* get 802.3 Header and remove LLC */ |
| RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); |
| |
| ASSERT(pRxBlk->pRxPacket); |
| |
| /* Ralink Aggregation frame */ |
| pAd->RalinkCounters.OneSecRxAggregationCount++; |
| Payload1Size = pRxBlk->DataSize - Msdu2Size; |
| Payload2Size = Msdu2Size - LENGTH_802_3; |
| |
| pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; |
| |
| pPacket2 = |
| duplicate_pkt(pAd, (pData2 - LENGTH_802_3), LENGTH_802_3, pData2, |
| Payload2Size, FromWhichBSSID); |
| |
| if (!pPacket2) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| /* update payload size of 1st packet */ |
| pRxBlk->DataSize = Payload1Size; |
| wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); |
| |
| ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, |
| FromWhichBSSID); |
| |
| if (pPacket2) { |
| ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); |
| } |
| } |
| |
| #define RESET_FRAGFRAME(_fragFrame) \ |
| { \ |
| _fragFrame.RxSize = 0; \ |
| _fragFrame.Sequence = 0; \ |
| _fragFrame.LastFrag = 0; \ |
| _fragFrame.Flags = 0; \ |
| } |
| |
| void *RTMPDeFragmentDataFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) |
| { |
| struct rt_header_802_11 * pHeader = pRxBlk->pHeader; |
| void *pRxPacket = pRxBlk->pRxPacket; |
| u8 *pData = pRxBlk->pData; |
| u16 DataSize = pRxBlk->DataSize; |
| void *pRetPacket = NULL; |
| u8 *pFragBuffer = NULL; |
| BOOLEAN bReassDone = FALSE; |
| u8 HeaderRoom = 0; |
| |
| ASSERT(pHeader); |
| |
| HeaderRoom = pData - (u8 *) pHeader; |
| |
| /* Re-assemble the fragmented packets */ |
| if (pHeader->Frag == 0) /* Frag. Number is 0 : First frag or only one pkt */ |
| { |
| /* the first pkt of fragment, record it. */ |
| if (pHeader->FC.MoreFrag) { |
| ASSERT(pAd->FragFrame.pFragPacket); |
| pFragBuffer = |
| GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); |
| pAd->FragFrame.RxSize = DataSize + HeaderRoom; |
| NdisMoveMemory(pFragBuffer, pHeader, |
| pAd->FragFrame.RxSize); |
| pAd->FragFrame.Sequence = pHeader->Sequence; |
| pAd->FragFrame.LastFrag = pHeader->Frag; /* Should be 0 */ |
| ASSERT(pAd->FragFrame.LastFrag == 0); |
| goto done; /* end of processing this frame */ |
| } |
| } else /*Middle & End of fragment */ |
| { |
| if ((pHeader->Sequence != pAd->FragFrame.Sequence) || |
| (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) { |
| /* Fragment is not the same sequence or out of fragment number order */ |
| /* Reset Fragment control blk */ |
| RESET_FRAGFRAME(pAd->FragFrame); |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Fragment is not the same sequence or out of fragment number order.\n")); |
| goto done; /* give up this frame */ |
| } else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) { |
| /* Fragment frame is too large, it exeeds the maximum frame size. */ |
| /* Reset Fragment control blk */ |
| RESET_FRAGFRAME(pAd->FragFrame); |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Fragment frame is too large, it exeeds the maximum frame size.\n")); |
| goto done; /* give up this frame */ |
| } |
| /* */ |
| /* Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. */ |
| /* In this case, we will dropt it. */ |
| /* */ |
| if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", |
| pHeader->Sequence, pHeader->Frag)); |
| goto done; /* give up this frame */ |
| } |
| |
| pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); |
| |
| /* concatenate this fragment into the re-assembly buffer */ |
| NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, |
| DataSize); |
| pAd->FragFrame.RxSize += DataSize; |
| pAd->FragFrame.LastFrag = pHeader->Frag; /* Update fragment number */ |
| |
| /* Last fragment */ |
| if (pHeader->FC.MoreFrag == FALSE) { |
| bReassDone = TRUE; |
| } |
| } |
| |
| done: |
| /* always release rx fragmented packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); |
| |
| /* return defragmented packet if packet is reassembled completely */ |
| /* otherwise return NULL */ |
| if (bReassDone) { |
| void *pNewFragPacket; |
| |
| /* allocate a new packet buffer for fragment */ |
| pNewFragPacket = |
| RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); |
| if (pNewFragPacket) { |
| /* update RxBlk */ |
| pRetPacket = pAd->FragFrame.pFragPacket; |
| pAd->FragFrame.pFragPacket = pNewFragPacket; |
| pRxBlk->pHeader = |
| (struct rt_header_802_11 *) GET_OS_PKT_DATAPTR(pRetPacket); |
| pRxBlk->pData = (u8 *) pRxBlk->pHeader + HeaderRoom; |
| pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; |
| pRxBlk->pRxPacket = pRetPacket; |
| } else { |
| RESET_FRAGFRAME(pAd->FragFrame); |
| } |
| } |
| |
| return pRetPacket; |
| } |
| |
| void Indicate_AMSDU_Packet(struct rt_rtmp_adapter *pAd, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| u32 nMSDU; |
| |
| update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); |
| RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); |
| nMSDU = |
| deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, |
| pRxBlk->DataSize); |
| } |
| |
| void Indicate_EAPOL_Packet(struct rt_rtmp_adapter *pAd, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| struct rt_mac_table_entry *pEntry = NULL; |
| |
| { |
| pEntry = &pAd->MacTab.Content[BSSID_WCID]; |
| STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); |
| return; |
| } |
| |
| if (pEntry == NULL) { |
| DBGPRINT(RT_DEBUG_WARN, |
| ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } |
| |
| #define BCN_TBTT_OFFSET 64 /*defer 64 us */ |
| void ReSyncBeaconTime(struct rt_rtmp_adapter *pAd) |
| { |
| |
| u32 Offset; |
| |
| Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); |
| |
| pAd->TbttTickCount++; |
| |
| /* */ |
| /* The updated BeaconInterval Value will affect Beacon Interval after two TBTT */ |
| /* beacasue the original BeaconInterval had been loaded into next TBTT_TIMER */ |
| /* */ |
| if (Offset == (BCN_TBTT_OFFSET - 2)) { |
| BCN_TIME_CFG_STRUC csr; |
| RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); |
| csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1; /* ASIC register in units of 1/16 TU = 64us */ |
| RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); |
| } else { |
| if (Offset == (BCN_TBTT_OFFSET - 1)) { |
| BCN_TIME_CFG_STRUC csr; |
| |
| RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); |
| csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; /* ASIC register in units of 1/16 TU */ |
| RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); |
| } |
| } |
| } |