| /* |
| ************************************************************************* |
| * 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. * |
| * * |
| ************************************************************************* |
| |
| Module Name: |
| rtmp_data.c |
| |
| Abstract: |
| Data path subroutines |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| */ |
| #include "../rt_config.h" |
| |
| void STARxEAPOLFrameIndicate(struct rt_rtmp_adapter *pAd, |
| struct rt_mac_table_entry *pEntry, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); |
| struct rt_rxwi * pRxWI = pRxBlk->pRxWI; |
| u8 *pTmpBuf; |
| |
| if (pAd->StaCfg.WpaSupplicantUP) { |
| /* All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) */ |
| /* TBD : process fragmented EAPol frames */ |
| { |
| /* In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable */ |
| if (pAd->StaCfg.IEEE8021X == TRUE && |
| (EAP_CODE_SUCCESS == |
| WpaCheckEapCode(pAd, pRxBlk->pData, |
| pRxBlk->DataSize, |
| LENGTH_802_1_H))) { |
| u8 *Key; |
| u8 CipherAlg; |
| int idx = 0; |
| |
| DBGPRINT_RAW(RT_DEBUG_TRACE, |
| ("Receive EAP-SUCCESS Packet\n")); |
| /*pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; */ |
| STA_PORT_SECURED(pAd); |
| |
| if (pAd->StaCfg.IEEE8021x_required_keys == |
| FALSE) { |
| idx = pAd->StaCfg.DesireSharedKeyId; |
| CipherAlg = |
| pAd->StaCfg.DesireSharedKey[idx]. |
| CipherAlg; |
| Key = |
| pAd->StaCfg.DesireSharedKey[idx]. |
| Key; |
| |
| if (pAd->StaCfg.DesireSharedKey[idx]. |
| KeyLen > 0) { |
| #ifdef RTMP_MAC_PCI |
| struct rt_mac_table_entry *pEntry = |
| &pAd->MacTab. |
| Content[BSSID_WCID]; |
| |
| /* Set key material and cipherAlg to Asic */ |
| AsicAddSharedKeyEntry(pAd, BSS0, |
| idx, |
| CipherAlg, |
| Key, NULL, |
| NULL); |
| |
| /* Assign group key info */ |
| RTMPAddWcidAttributeEntry(pAd, |
| BSS0, |
| idx, |
| CipherAlg, |
| NULL); |
| |
| /* Assign pairwise key info */ |
| RTMPAddWcidAttributeEntry(pAd, |
| BSS0, |
| idx, |
| CipherAlg, |
| pEntry); |
| |
| pAd->IndicateMediaState = |
| NdisMediaStateConnected; |
| pAd->ExtraInfo = |
| GENERAL_LINK_UP; |
| #endif /* RTMP_MAC_PCI // */ |
| #ifdef RTMP_MAC_USB |
| union { |
| char buf[sizeof |
| (struct rt_ndis_802_11_wep) |
| + |
| MAX_LEN_OF_KEY |
| - 1]; |
| struct rt_ndis_802_11_wep keyinfo; |
| } |
| WepKey; |
| int len; |
| |
| NdisZeroMemory(&WepKey, |
| sizeof(WepKey)); |
| len = |
| pAd->StaCfg. |
| DesireSharedKey[idx].KeyLen; |
| |
| NdisMoveMemory(WepKey.keyinfo. |
| KeyMaterial, |
| pAd->StaCfg. |
| DesireSharedKey |
| [idx].Key, |
| pAd->StaCfg. |
| DesireSharedKey |
| [idx].KeyLen); |
| |
| WepKey.keyinfo.KeyIndex = |
| 0x80000000 + idx; |
| WepKey.keyinfo.KeyLength = len; |
| pAd->SharedKey[BSS0][idx]. |
| KeyLen = |
| (u8)(len <= 5 ? 5 : 13); |
| |
| pAd->IndicateMediaState = |
| NdisMediaStateConnected; |
| pAd->ExtraInfo = |
| GENERAL_LINK_UP; |
| /* need to enqueue cmd to thread */ |
| RTUSBEnqueueCmdFromNdis(pAd, |
| OID_802_11_ADD_WEP, |
| TRUE, |
| &WepKey, |
| sizeof |
| (WepKey. |
| keyinfo) |
| + len - |
| 1); |
| #endif /* RTMP_MAC_USB // */ |
| /* For Preventing ShardKey Table is cleared by remove key procedure. */ |
| pAd->SharedKey[BSS0][idx]. |
| CipherAlg = CipherAlg; |
| pAd->SharedKey[BSS0][idx]. |
| KeyLen = |
| pAd->StaCfg. |
| DesireSharedKey[idx].KeyLen; |
| NdisMoveMemory(pAd-> |
| SharedKey[BSS0] |
| [idx].Key, |
| pAd->StaCfg. |
| DesireSharedKey |
| [idx].Key, |
| pAd->StaCfg. |
| DesireSharedKey |
| [idx].KeyLen); |
| } |
| } |
| } |
| |
| Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); |
| return; |
| } |
| } else { |
| /* Special DATA frame that has to pass to MLME */ |
| /* 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process */ |
| /* 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process */ |
| { |
| pTmpBuf = pRxBlk->pData - LENGTH_802_11; |
| NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); |
| REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, |
| pTmpBuf, |
| pRxBlk->DataSize + |
| LENGTH_802_11, pRxWI->RSSI0, |
| pRxWI->RSSI1, pRxWI->RSSI2, |
| pRxD->PlcpSignal); |
| DBGPRINT_RAW(RT_DEBUG_TRACE, |
| ("report EAPOL/AIRONET DATA to MLME (len=%d) !\n", |
| pRxBlk->DataSize)); |
| } |
| } |
| |
| RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); |
| return; |
| |
| } |
| |
| void STARxDataFrameAnnounce(struct rt_rtmp_adapter *pAd, |
| struct rt_mac_table_entry *pEntry, |
| struct rt_rx_blk *pRxBlk, u8 FromWhichBSSID) |
| { |
| |
| /* non-EAP frame */ |
| if (!RTMPCheckWPAframe |
| (pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) { |
| |
| { |
| /* drop all non-EAP DATA frame before */ |
| /* this client's Port-Access-Control is secured */ |
| if (pRxBlk->pHeader->FC.Wep) { |
| /* unsupported cipher suite */ |
| if (pAd->StaCfg.WepStatus == |
| Ndis802_11EncryptionDisabled) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, |
| pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } else { |
| /* encryption in-use but receive a non-EAPOL clear text frame, drop it */ |
| if ((pAd->StaCfg.WepStatus != |
| Ndis802_11EncryptionDisabled) |
| && (pAd->StaCfg.PortSecured == |
| WPA_802_1X_PORT_NOT_SECURED)) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, |
| pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } |
| } |
| RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); |
| if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) { |
| /* Normal legacy, AMPDU or AMSDU */ |
| CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, |
| FromWhichBSSID); |
| |
| } else { |
| /* ARALINK */ |
| CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, |
| FromWhichBSSID); |
| } |
| } else { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); |
| |
| if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) |
| && (pAd->CommonCfg.bDisableReordering == 0)) { |
| Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); |
| } else { |
| /* Determin the destination of the EAP frame */ |
| /* to WPA state machine or upper layer */ |
| STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, |
| FromWhichBSSID); |
| } |
| } |
| } |
| |
| /* For TKIP frame, calculate the MIC value */ |
| BOOLEAN STACheckTkipMICValue(struct rt_rtmp_adapter *pAd, |
| struct rt_mac_table_entry *pEntry, struct rt_rx_blk *pRxBlk) |
| { |
| struct rt_header_802_11 * pHeader = pRxBlk->pHeader; |
| u8 *pData = pRxBlk->pData; |
| u16 DataSize = pRxBlk->DataSize; |
| u8 UserPriority = pRxBlk->UserPriority; |
| struct rt_cipher_key *pWpaKey; |
| u8 *pDA, *pSA; |
| |
| pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; |
| |
| pDA = pHeader->Addr1; |
| if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) { |
| pSA = pHeader->Addr3; |
| } else { |
| pSA = pHeader->Addr2; |
| } |
| |
| if (RTMPTkipCompareMICValue(pAd, |
| pData, |
| pDA, |
| pSA, |
| pWpaKey->RxMic, |
| UserPriority, DataSize) == FALSE) { |
| DBGPRINT_RAW(RT_DEBUG_ERROR, ("Rx MIC Value error 2\n")); |
| |
| if (pAd->StaCfg.WpaSupplicantUP) { |
| WpaSendMicFailureToWpaSupplicant(pAd, |
| (pWpaKey->Type == |
| PAIRWISEKEY) ? TRUE : |
| FALSE); |
| } else { |
| RTMPReportMicError(pAd, pWpaKey); |
| } |
| |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /* */ |
| /* All Rx routines use struct rt_rx_blk structure to hande rx events */ |
| /* It is very important to build pRxBlk attributes */ |
| /* 1. pHeader pointer to 802.11 Header */ |
| /* 2. pData pointer to payload including LLC (just skip Header) */ |
| /* 3. set payload size including LLC to DataSize */ |
| /* 4. set some flags with RX_BLK_SET_FLAG() */ |
| /* */ |
| void STAHandleRxDataFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) |
| { |
| PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); |
| struct rt_rxwi * pRxWI = pRxBlk->pRxWI; |
| struct rt_header_802_11 * pHeader = pRxBlk->pHeader; |
| void *pRxPacket = pRxBlk->pRxPacket; |
| BOOLEAN bFragment = FALSE; |
| struct rt_mac_table_entry *pEntry = NULL; |
| u8 FromWhichBSSID = BSS0; |
| u8 UserPriority = 0; |
| |
| { |
| /* before LINK UP, all DATA frames are rejected */ |
| if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| /* Drop not my BSS frames */ |
| if (pRxD->MyBss == 0) { |
| { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } |
| |
| pAd->RalinkCounters.RxCountSinceLastNULL++; |
| if (pAd->CommonCfg.bAPSDCapable |
| && pAd->CommonCfg.APEdcaParm.bAPSDCapable |
| && (pHeader->FC.SubType & 0x08)) { |
| u8 *pData; |
| DBGPRINT(RT_DEBUG_INFO, ("bAPSDCapable\n")); |
| |
| /* Qos bit 4 */ |
| pData = (u8 *)pHeader + LENGTH_802_11; |
| if ((*pData >> 4) & 0x01) { |
| DBGPRINT(RT_DEBUG_INFO, |
| ("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); |
| pAd->CommonCfg.bInServicePeriod = FALSE; |
| |
| /* Force driver to fall into sleep mode when rcv EOSP frame */ |
| if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
| u16 TbttNumToNextWakeUp; |
| u16 NextDtim = |
| pAd->StaCfg.DtimPeriod; |
| unsigned long Now; |
| |
| NdisGetSystemUpTime(&Now); |
| NextDtim -= |
| (u16)(Now - |
| pAd->StaCfg. |
| LastBeaconRxTime) / |
| pAd->CommonCfg.BeaconPeriod; |
| |
| TbttNumToNextWakeUp = |
| pAd->StaCfg.DefaultListenCount; |
| if (OPSTATUS_TEST_FLAG |
| (pAd, fOP_STATUS_RECEIVE_DTIM) |
| && (TbttNumToNextWakeUp > NextDtim)) |
| TbttNumToNextWakeUp = NextDtim; |
| |
| RTMP_SET_PSM_BIT(pAd, PWR_SAVE); |
| /* if WMM-APSD is failed, try to disable following line */ |
| AsicSleepThenAutoWakeup(pAd, |
| TbttNumToNextWakeUp); |
| } |
| } |
| |
| if ((pHeader->FC.MoreData) |
| && (pAd->CommonCfg.bInServicePeriod)) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("Sending another trigger frame when More Data bit is set to 1\n")); |
| } |
| } |
| /* Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame */ |
| if ((pHeader->FC.SubType & 0x04)) /* bit 2 : no DATA */ |
| { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| /* Drop not my BSS frame (we can not only check the MyBss bit in RxD) */ |
| |
| if (INFRA_ON(pAd)) { |
| /* Infrastructure mode, check address 2 for BSSID */ |
| if (!RTMPEqualMemory |
| (&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) { |
| /* Receive frame not my BSSID */ |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } else /* Ad-Hoc mode or Not associated */ |
| { |
| /* Ad-Hoc mode, check address 3 for BSSID */ |
| if (!RTMPEqualMemory |
| (&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) { |
| /* Receive frame not my BSSID */ |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| } |
| |
| /* */ |
| /* find pEntry */ |
| /* */ |
| if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) { |
| pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; |
| } else { |
| /* 1. release packet if infra mode */ |
| /* 2. new a pEntry if ad-hoc mode */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| /* infra or ad-hoc */ |
| if (INFRA_ON(pAd)) { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); |
| ASSERT(pRxWI->WirelessCliID == BSSID_WCID); |
| } |
| /* check Atheros Client */ |
| if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) |
| && (pHeader->FC.Retry)) { |
| pEntry->bIAmBadAtheros = TRUE; |
| pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; |
| pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; |
| if (!STA_AES_ON(pAd)) { |
| AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, |
| FALSE); |
| } |
| } |
| } |
| |
| pRxBlk->pData = (u8 *) pHeader; |
| |
| /* */ |
| /* update RxBlk->pData, DataSize */ |
| /* 802.11 Header, QOS, HTC, Hw Padding */ |
| /* */ |
| |
| /* 1. skip 802.11 HEADER */ |
| { |
| pRxBlk->pData += LENGTH_802_11; |
| pRxBlk->DataSize -= LENGTH_802_11; |
| } |
| |
| /* 2. QOS */ |
| if (pHeader->FC.SubType & 0x08) { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); |
| UserPriority = *(pRxBlk->pData) & 0x0f; |
| /* bit 7 in QoS Control field signals the HT A-MSDU format */ |
| if ((*pRxBlk->pData) & 0x80) { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); |
| } |
| /* skip QOS contorl field */ |
| pRxBlk->pData += 2; |
| pRxBlk->DataSize -= 2; |
| } |
| pRxBlk->UserPriority = UserPriority; |
| |
| /* check if need to resend PS Poll when received packet with MoreData = 1 */ |
| if ((pAd->StaCfg.Psm == PWR_SAVE) && (pHeader->FC.MoreData == 1)) { |
| if ((((UserPriority == 0) || (UserPriority == 3)) && |
| pAd->CommonCfg.bAPSDAC_BE == 0) || |
| (((UserPriority == 1) || (UserPriority == 2)) && |
| pAd->CommonCfg.bAPSDAC_BK == 0) || |
| (((UserPriority == 4) || (UserPriority == 5)) && |
| pAd->CommonCfg.bAPSDAC_VI == 0) || |
| (((UserPriority == 6) || (UserPriority == 7)) && |
| pAd->CommonCfg.bAPSDAC_VO == 0)) { |
| /* non-UAPSD delivery-enabled AC */ |
| RTMP_PS_POLL_ENQUEUE(pAd); |
| } |
| } |
| /* 3. Order bit: A-Ralink or HTC+ */ |
| if (pHeader->FC.Order) { |
| #ifdef AGGREGATION_SUPPORT |
| if ((pRxWI->PHYMODE <= MODE_OFDM) |
| && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) |
| { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); |
| } else |
| #endif /* AGGREGATION_SUPPORT // */ |
| { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); |
| /* skip HTC contorl field */ |
| pRxBlk->pData += 4; |
| pRxBlk->DataSize -= 4; |
| } |
| } |
| /* 4. skip HW padding */ |
| if (pRxD->L2PAD) { |
| /* just move pData pointer */ |
| /* because DataSize excluding HW padding */ |
| RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); |
| pRxBlk->pData += 2; |
| } |
| |
| if (pRxD->BA) { |
| RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); |
| } |
| /* */ |
| /* Case I Process Broadcast & Multicast data frame */ |
| /* */ |
| if (pRxD->Bcast || pRxD->Mcast) { |
| INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); |
| |
| /* Drop Mcast/Bcast frame with fragment bit on */ |
| if (pHeader->FC.MoreFrag) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| /* Filter out Bcast frame which AP relayed for us */ |
| if (pHeader->FC.FrDs |
| && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); |
| return; |
| } else if (pRxD->U2M) { |
| pAd->LastRxRate = |
| (u16)((pRxWI->MCS) + (pRxWI->BW << 7) + |
| (pRxWI->ShortGI << 8) + (pRxWI->PHYMODE << 14)); |
| |
| if (ADHOC_ON(pAd)) { |
| pEntry = MacTableLookup(pAd, pHeader->Addr2); |
| if (pEntry) |
| Update_Rssi_Sample(pAd, &pEntry->RssiSample, |
| pRxWI); |
| } |
| |
| Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); |
| |
| pAd->StaCfg.LastSNR0 = (u8)(pRxWI->SNR0); |
| pAd->StaCfg.LastSNR1 = (u8)(pRxWI->SNR1); |
| |
| pAd->RalinkCounters.OneSecRxOkDataCnt++; |
| |
| if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) { |
| /* re-assemble the fragmented packets */ |
| /* return complete frame (pRxPacket) or NULL */ |
| bFragment = TRUE; |
| pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); |
| } |
| |
| if (pRxPacket) { |
| pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; |
| |
| /* process complete frame */ |
| if (bFragment && (pRxD->Decrypted) |
| && (pEntry->WepStatus == |
| Ndis802_11Encryption2Enabled)) { |
| /* Minus MIC length */ |
| pRxBlk->DataSize -= 8; |
| |
| /* For TKIP frame, calculate the MIC value */ |
| if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == |
| FALSE) { |
| return; |
| } |
| } |
| |
| STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, |
| FromWhichBSSID); |
| return; |
| } else { |
| /* just return */ |
| /* because RTMPDeFragmentDataFrame() will release rx packet, */ |
| /* if packet is fragmented */ |
| return; |
| } |
| } |
| |
| ASSERT(0); |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); |
| } |
| |
| void STAHandleRxMgmtFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) |
| { |
| PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); |
| struct rt_rxwi * pRxWI = pRxBlk->pRxWI; |
| struct rt_header_802_11 * pHeader = pRxBlk->pHeader; |
| void *pRxPacket = pRxBlk->pRxPacket; |
| |
| do { |
| |
| /* check if need to resend PS Poll when received packet with MoreData = 1 */ |
| if ((pAd->StaCfg.Psm == PWR_SAVE) |
| && (pHeader->FC.MoreData == 1)) { |
| /* for UAPSD, all management frames will be VO priority */ |
| if (pAd->CommonCfg.bAPSDAC_VO == 0) { |
| /* non-UAPSD delivery-enabled AC */ |
| RTMP_PS_POLL_ENQUEUE(pAd); |
| } |
| } |
| |
| /* TODO: if MoreData == 0, station can go to sleep */ |
| |
| /* We should collect RSSI not only U2M data but also my beacon */ |
| if ((pHeader->FC.SubType == SUBTYPE_BEACON) |
| && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)) |
| && (pAd->RxAnt.EvaluatePeriod == 0)) { |
| Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); |
| |
| pAd->StaCfg.LastSNR0 = (u8)(pRxWI->SNR0); |
| pAd->StaCfg.LastSNR1 = (u8)(pRxWI->SNR1); |
| } |
| |
| /* First check the size, it MUST not exceed the mlme queue size */ |
| if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) { |
| DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); |
| break; |
| } |
| |
| REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, |
| pRxWI->MPDUtotalByteCount, |
| pRxWI->RSSI0, pRxWI->RSSI1, |
| pRxWI->RSSI2, pRxD->PlcpSignal); |
| } while (FALSE); |
| |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); |
| } |
| |
| void STAHandleRxControlFrame(struct rt_rtmp_adapter *pAd, struct rt_rx_blk *pRxBlk) |
| { |
| struct rt_rxwi * pRxWI = pRxBlk->pRxWI; |
| struct rt_header_802_11 * pHeader = pRxBlk->pHeader; |
| void *pRxPacket = pRxBlk->pRxPacket; |
| |
| switch (pHeader->FC.SubType) { |
| case SUBTYPE_BLOCK_ACK_REQ: |
| { |
| CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, |
| (pRxWI->MPDUtotalByteCount), |
| (struct rt_frame_ba_req *) pHeader); |
| } |
| break; |
| case SUBTYPE_BLOCK_ACK: |
| case SUBTYPE_ACK: |
| default: |
| break; |
| } |
| |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Process RxDone interrupt, running in DPC level |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| This routine has to maintain Rx ring read pointer. |
| Need to consider QOS DATA format when converting to 802.3 |
| ======================================================================== |
| */ |
| BOOLEAN STARxDoneInterruptHandle(struct rt_rtmp_adapter *pAd, IN BOOLEAN argc) |
| { |
| int Status; |
| u32 RxProcessed, RxPending; |
| BOOLEAN bReschedule = FALSE; |
| PRT28XX_RXD_STRUC pRxD; |
| u8 *pData; |
| struct rt_rxwi * pRxWI; |
| void *pRxPacket; |
| struct rt_header_802_11 * pHeader; |
| struct rt_rx_blk RxCell; |
| |
| RxProcessed = RxPending = 0; |
| |
| /* process whole rx ring */ |
| while (1) { |
| |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | |
| fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_NIC_NOT_EXIST) || |
| !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) { |
| break; |
| } |
| #ifdef RTMP_MAC_PCI |
| if (RxProcessed++ > MAX_RX_PROCESS_CNT) { |
| /* need to reschedule rx handle */ |
| bReschedule = TRUE; |
| break; |
| } |
| #endif /* RTMP_MAC_PCI // */ |
| |
| RxProcessed++; /* test */ |
| |
| /* 1. allocate a new data packet into rx ring to replace received packet */ |
| /* then processing the received packet */ |
| /* 2. the callee must take charge of release of packet */ |
| /* 3. As far as driver is concerned , */ |
| /* the rx packet must */ |
| /* a. be indicated to upper layer or */ |
| /* b. be released if it is discarded */ |
| pRxPacket = |
| GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, |
| &RxPending); |
| if (pRxPacket == NULL) { |
| /* no more packet to process */ |
| break; |
| } |
| /* get rx ring descriptor */ |
| pRxD = &(RxCell.RxD); |
| /* get rx data buffer */ |
| pData = GET_OS_PKT_DATAPTR(pRxPacket); |
| pRxWI = (struct rt_rxwi *) pData; |
| pHeader = (struct rt_header_802_11 *) (pData + RXWI_SIZE); |
| |
| /* build RxCell */ |
| RxCell.pRxWI = pRxWI; |
| RxCell.pHeader = pHeader; |
| RxCell.pRxPacket = pRxPacket; |
| RxCell.pData = (u8 *) pHeader; |
| RxCell.DataSize = pRxWI->MPDUtotalByteCount; |
| RxCell.Flags = 0; |
| |
| /* Increase Total receive byte counter after real data received no mater any error or not */ |
| pAd->RalinkCounters.ReceivedByteCount += |
| pRxWI->MPDUtotalByteCount; |
| pAd->RalinkCounters.OneSecReceivedByteCount += |
| pRxWI->MPDUtotalByteCount; |
| pAd->RalinkCounters.RxCount++; |
| |
| INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); |
| |
| if (pRxWI->MPDUtotalByteCount < 14) |
| Status = NDIS_STATUS_FAILURE; |
| |
| if (MONITOR_ON(pAd)) { |
| send_monitor_packets(pAd, &RxCell); |
| break; |
| } |
| |
| /* STARxDoneInterruptHandle() is called in rtusb_bulk.c */ |
| |
| /* Check for all RxD errors */ |
| Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); |
| |
| /* Handle the received frame */ |
| if (Status == NDIS_STATUS_SUCCESS) { |
| switch (pHeader->FC.Type) { |
| /* CASE I, receive a DATA frame */ |
| case BTYPE_DATA: |
| { |
| /* process DATA frame */ |
| STAHandleRxDataFrame(pAd, &RxCell); |
| } |
| break; |
| /* CASE II, receive a MGMT frame */ |
| case BTYPE_MGMT: |
| { |
| STAHandleRxMgmtFrame(pAd, &RxCell); |
| } |
| break; |
| /* CASE III. receive a CNTL frame */ |
| case BTYPE_CNTL: |
| { |
| STAHandleRxControlFrame(pAd, &RxCell); |
| } |
| break; |
| /* discard other type */ |
| default: |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| break; |
| } |
| } else { |
| pAd->Counters8023.RxErrors++; |
| /* discard this frame */ |
| RELEASE_NDIS_PACKET(pAd, pRxPacket, |
| NDIS_STATUS_FAILURE); |
| } |
| } |
| |
| return bReschedule; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Arguments: |
| pAd Pointer to our adapter |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ======================================================================== |
| */ |
| void RTMPHandleTwakeupInterrupt(struct rt_rtmp_adapter *pAd) |
| { |
| AsicForceWakeup(pAd, FALSE); |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Early checking and OS-depened parsing for Tx packet send to our STA driver. |
| |
| Arguments: |
| void * MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. |
| void ** ppPacketArray The packet array need to do transmission. |
| u32 NumberOfPackets Number of packet in packet array. |
| |
| Return Value: |
| NONE |
| |
| Note: |
| This function do early checking and classification for send-out packet. |
| You only can put OS-depened & STA related code in here. |
| ======================================================================== |
| */ |
| void STASendPackets(void *MiniportAdapterContext, |
| void **ppPacketArray, u32 NumberOfPackets) |
| { |
| u32 Index; |
| struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)MiniportAdapterContext; |
| void *pPacket; |
| BOOLEAN allowToSend = FALSE; |
| |
| for (Index = 0; Index < NumberOfPackets; Index++) { |
| pPacket = ppPacketArray[Index]; |
| |
| do { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) |
| || RTMP_TEST_FLAG(pAd, |
| fRTMP_ADAPTER_HALT_IN_PROGRESS) |
| || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) { |
| /* Drop send request since hardware is in reset state */ |
| break; |
| } else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) { |
| /* Drop send request since there are no physical connection yet */ |
| break; |
| } else { |
| /* Record that orignal packet source is from NDIS layer,so that */ |
| /* later on driver knows how to release this NDIS PACKET */ |
| RTMP_SET_PACKET_WCID(pPacket, 0); /* this field is useless when in STA mode */ |
| RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); |
| NDIS_SET_PACKET_STATUS(pPacket, |
| NDIS_STATUS_PENDING); |
| pAd->RalinkCounters.PendingNdisPacketCount++; |
| |
| allowToSend = TRUE; |
| } |
| } while (FALSE); |
| |
| if (allowToSend == TRUE) |
| STASendPacket(pAd, pPacket); |
| else |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| } |
| |
| /* Dequeue outgoing frames from TxSwQueue[] and process it */ |
| RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); |
| |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| This routine is used to do packet parsing and classification for Tx packet |
| to STA device, and it will en-queue packets to our TxSwQueue depends on AC |
| class. |
| |
| Arguments: |
| pAd Pointer to our adapter |
| pPacket Pointer to send packet |
| |
| Return Value: |
| NDIS_STATUS_SUCCESS If success to queue the packet into TxSwQueue. |
| NDIS_STATUS_FAILURE If failed to do en-queue. |
| |
| Note: |
| You only can put OS-indepened & STA related code in here. |
| ======================================================================== |
| */ |
| int STASendPacket(struct rt_rtmp_adapter *pAd, void *pPacket) |
| { |
| struct rt_packet_info PacketInfo; |
| u8 *pSrcBufVA; |
| u32 SrcBufLen; |
| u32 AllowFragSize; |
| u8 NumberOfFrag; |
| u8 RTSRequired; |
| u8 QueIdx, UserPriority; |
| struct rt_mac_table_entry *pEntry = NULL; |
| unsigned int IrqFlags; |
| u8 FlgIsIP = 0; |
| u8 Rate; |
| |
| /* Prepare packet information structure for buffer descriptor */ |
| /* chained within a single NDIS packet. */ |
| RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); |
| |
| if (pSrcBufVA == NULL) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("STASendPacket --> pSrcBufVA == NULL !SrcBufLen=%x\n", |
| SrcBufLen)); |
| /* Resourece is low, system did not allocate virtual address */ |
| /* return NDIS_STATUS_FAILURE directly to upper layer */ |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| if (SrcBufLen < 14) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("STASendPacket --> Ndis Packet buffer error!\n")); |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| return (NDIS_STATUS_FAILURE); |
| } |
| /* In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. */ |
| /* Note multicast packets in adhoc also use BSSID_WCID index. */ |
| { |
| if (INFRA_ON(pAd)) { |
| { |
| pEntry = &pAd->MacTab.Content[BSSID_WCID]; |
| RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); |
| Rate = pAd->CommonCfg.TxRate; |
| } |
| } else if (ADHOC_ON(pAd)) { |
| if (*pSrcBufVA & 0x01) { |
| RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); |
| pEntry = &pAd->MacTab.Content[MCAST_WCID]; |
| } else { |
| pEntry = MacTableLookup(pAd, pSrcBufVA); |
| } |
| Rate = pAd->CommonCfg.TxRate; |
| } |
| } |
| |
| if (!pEntry) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", |
| PRINT_MAC(pSrcBufVA))); |
| /* Resourece is low, system did not allocate virtual address */ |
| /* return NDIS_STATUS_FAILURE directly to upper layer */ |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| if (ADHOC_ON(pAd) |
| ) { |
| RTMP_SET_PACKET_WCID(pPacket, (u8)pEntry->Aid); |
| } |
| /* */ |
| /* Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. */ |
| /* Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). */ |
| RTMPCheckEtherType(pAd, pPacket); |
| |
| /* */ |
| /* WPA 802.1x secured port control - drop all non-802.1x frame before port secured */ |
| /* */ |
| if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) |
| || (pAd->StaCfg.IEEE8021X == TRUE) |
| ) |
| && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) |
| || (pAd->StaCfg.MicErrCnt >= 2)) |
| && (RTMP_GET_PACKET_EAPOL(pPacket) == FALSE) |
| ) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("STASendPacket --> Drop packet before port secured!\n")); |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| |
| return (NDIS_STATUS_FAILURE); |
| } |
| |
| /* STEP 1. Decide number of fragments required to deliver this MSDU. */ |
| /* The estimation here is not very accurate because difficult to */ |
| /* take encryption overhead into consideration here. The result */ |
| /* "NumberOfFrag" is then just used to pre-check if enough free */ |
| /* TXD are available to hold this MSDU. */ |
| |
| if (*pSrcBufVA & 0x01) /* fragmentation not allowed on multicast & broadcast */ |
| NumberOfFrag = 1; |
| else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) |
| NumberOfFrag = 1; /* Aggregation overwhelms fragmentation */ |
| else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) |
| NumberOfFrag = 1; /* Aggregation overwhelms fragmentation */ |
| else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) |
| || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) |
| NumberOfFrag = 1; /* MIMO RATE overwhelms fragmentation */ |
| else { |
| /* The calculated "NumberOfFrag" is a rough estimation because of various */ |
| /* encryption/encapsulation overhead not taken into consideration. This number is just */ |
| /* used to make sure enough free TXD are available before fragmentation takes place. */ |
| /* In case the actual required number of fragments of an NDIS packet */ |
| /* excceeds "NumberOfFrag"caculated here and not enough free TXD available, the */ |
| /* last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of */ |
| /* resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should */ |
| /* rarely happen and the penalty is just like a TX RETRY fail. Affordable. */ |
| |
| AllowFragSize = |
| (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - |
| LENGTH_CRC; |
| NumberOfFrag = |
| ((PacketInfo.TotalPacketLength - LENGTH_802_3 + |
| LENGTH_802_1_H) / AllowFragSize) + 1; |
| /* To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size */ |
| if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + |
| LENGTH_802_1_H) % AllowFragSize) == 0) { |
| NumberOfFrag--; |
| } |
| } |
| |
| /* Save fragment number to Ndis packet reserved field */ |
| RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); |
| |
| /* STEP 2. Check the requirement of RTS: */ |
| /* If multiple fragment required, RTS is required only for the first fragment */ |
| /* if the fragment size large than RTS threshold */ |
| /* For RT28xx, Let ASIC send RTS/CTS */ |
| /* RTMP_SET_PACKET_RTS(pPacket, 0); */ |
| if (NumberOfFrag > 1) |
| RTSRequired = |
| (pAd->CommonCfg.FragmentThreshold > |
| pAd->CommonCfg.RtsThreshold) ? 1 : 0; |
| else |
| RTSRequired = |
| (PacketInfo.TotalPacketLength > |
| pAd->CommonCfg.RtsThreshold) ? 1 : 0; |
| |
| /* Save RTS requirement to Ndis packet reserved field */ |
| RTMP_SET_PACKET_RTS(pPacket, RTSRequired); |
| RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); |
| |
| /* */ |
| /* STEP 3. Traffic classification. outcome = <UserPriority, QueIdx> */ |
| /* */ |
| UserPriority = 0; |
| QueIdx = QID_AC_BE; |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && |
| CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) { |
| u16 Protocol; |
| u8 LlcSnapLen = 0, Byte0, Byte1; |
| do { |
| /* get Ethernet protocol field */ |
| Protocol = |
| (u16)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); |
| if (Protocol <= 1500) { |
| /* get Ethernet protocol field from LLC/SNAP */ |
| if (Sniff2BytesFromNdisBuffer |
| (PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, |
| &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) |
| break; |
| |
| Protocol = (u16)((Byte0 << 8) + Byte1); |
| LlcSnapLen = 8; |
| } |
| /* always AC_BE for non-IP packet */ |
| if (Protocol != 0x0800) |
| break; |
| |
| /* get IP header */ |
| if (Sniff2BytesFromNdisBuffer |
| (PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, |
| &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) |
| break; |
| |
| /* return AC_BE if packet is not IPv4 */ |
| if ((Byte0 & 0xf0) != 0x40) |
| break; |
| |
| FlgIsIP = 1; |
| UserPriority = (Byte1 & 0xe0) >> 5; |
| QueIdx = MapUserPriorityToAccessCategory[UserPriority]; |
| |
| /* TODO: have to check ACM bit. apply TSPEC if ACM is ON */ |
| /* TODO: downgrade UP & QueIdx before passing ACM */ |
| /* |
| Under WMM ACM control, we dont need to check the bit; |
| Or when a TSPEC is built for VO but we will change to issue |
| BA session for BE here, so we will not use BA to send VO packets. |
| */ |
| if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) { |
| UserPriority = 0; |
| QueIdx = QID_AC_BE; |
| } |
| } while (FALSE); |
| } |
| |
| RTMP_SET_PACKET_UP(pPacket, UserPriority); |
| |
| /* Make sure SendTxWait queue resource won't be used by other threads */ |
| RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); |
| if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) { |
| RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| |
| return NDIS_STATUS_FAILURE; |
| } else { |
| InsertTailQueueAc(pAd, pEntry, &pAd->TxSwQueue[QueIdx], |
| PACKET_TO_QUEUE_ENTRY(pPacket)); |
| } |
| RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); |
| |
| if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE) && |
| IS_HT_STA(pEntry)) { |
| /*struct rt_mac_table_entry *pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; */ |
| if (((pEntry->TXBAbitmap & (1 << UserPriority)) == 0) && |
| ((pEntry->BADeclineBitmap & (1 << UserPriority)) == 0) && |
| (pEntry->PortSecured == WPA_802_1X_PORT_SECURED) |
| /* For IOT compatibility, if */ |
| /* 1. It is Ralink chip or */ |
| /* 2. It is OPEN or AES mode, */ |
| /* then BA session can be bulit. */ |
| && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) |
| || (pEntry->WepStatus != Ndis802_11WEPEnabled |
| && pEntry->WepStatus != |
| Ndis802_11Encryption2Enabled)) |
| ) { |
| BAOriSessionSetUp(pAd, pEntry, UserPriority, 0, 10, |
| FALSE); |
| } |
| } |
| |
| pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; /* TODO: for debug only. to be removed */ |
| return NDIS_STATUS_SUCCESS; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| This subroutine will scan through releative ring descriptor to find |
| out avaliable free ring descriptor and compare with request size. |
| |
| Arguments: |
| pAd Pointer to our adapter |
| QueIdx Selected TX Ring |
| |
| Return Value: |
| NDIS_STATUS_FAILURE Not enough free descriptor |
| NDIS_STATUS_SUCCESS Enough free descriptor |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| #ifdef RTMP_MAC_PCI |
| int RTMPFreeTXDRequest(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, |
| u8 NumberRequired, u8 *FreeNumberIs) |
| { |
| unsigned long FreeNumber = 0; |
| int Status = NDIS_STATUS_FAILURE; |
| |
| switch (QueIdx) { |
| case QID_AC_BK: |
| case QID_AC_BE: |
| case QID_AC_VI: |
| case QID_AC_VO: |
| if (pAd->TxRing[QueIdx].TxSwFreeIdx > |
| pAd->TxRing[QueIdx].TxCpuIdx) |
| FreeNumber = |
| pAd->TxRing[QueIdx].TxSwFreeIdx - |
| pAd->TxRing[QueIdx].TxCpuIdx - 1; |
| else |
| FreeNumber = |
| pAd->TxRing[QueIdx].TxSwFreeIdx + TX_RING_SIZE - |
| pAd->TxRing[QueIdx].TxCpuIdx - 1; |
| |
| if (FreeNumber >= NumberRequired) |
| Status = NDIS_STATUS_SUCCESS; |
| break; |
| |
| case QID_MGMT: |
| if (pAd->MgmtRing.TxSwFreeIdx > pAd->MgmtRing.TxCpuIdx) |
| FreeNumber = |
| pAd->MgmtRing.TxSwFreeIdx - pAd->MgmtRing.TxCpuIdx - |
| 1; |
| else |
| FreeNumber = |
| pAd->MgmtRing.TxSwFreeIdx + MGMT_RING_SIZE - |
| pAd->MgmtRing.TxCpuIdx - 1; |
| |
| if (FreeNumber >= NumberRequired) |
| Status = NDIS_STATUS_SUCCESS; |
| break; |
| |
| default: |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); |
| break; |
| } |
| *FreeNumberIs = (u8)FreeNumber; |
| |
| return (Status); |
| } |
| #endif /* RTMP_MAC_PCI // */ |
| #ifdef RTMP_MAC_USB |
| /* |
| Actually, this function used to check if the TxHardware Queue still has frame need to send. |
| If no frame need to send, go to sleep, else, still wake up. |
| */ |
| int RTMPFreeTXDRequest(struct rt_rtmp_adapter *pAd, |
| u8 QueIdx, |
| u8 NumberRequired, u8 *FreeNumberIs) |
| { |
| /*unsigned long FreeNumber = 0; */ |
| int Status = NDIS_STATUS_FAILURE; |
| unsigned long IrqFlags; |
| struct rt_ht_tx_context *pHTTXContext; |
| |
| switch (QueIdx) { |
| case QID_AC_BK: |
| case QID_AC_BE: |
| case QID_AC_VI: |
| case QID_AC_VO: |
| { |
| pHTTXContext = &pAd->TxContext[QueIdx]; |
| RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], |
| IrqFlags); |
| if ((pHTTXContext->CurWritePosition != |
| pHTTXContext->ENextBulkOutPosition) |
| || (pHTTXContext->IRPPending == TRUE)) { |
| Status = NDIS_STATUS_FAILURE; |
| } else { |
| Status = NDIS_STATUS_SUCCESS; |
| } |
| RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], |
| IrqFlags); |
| } |
| break; |
| case QID_MGMT: |
| if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) |
| Status = NDIS_STATUS_FAILURE; |
| else |
| Status = NDIS_STATUS_SUCCESS; |
| break; |
| default: |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); |
| break; |
| } |
| |
| return (Status); |
| } |
| #endif /* RTMP_MAC_USB // */ |
| |
| void RTMPSendDisassociationFrame(struct rt_rtmp_adapter *pAd) |
| { |
| } |
| |
| void RTMPSendNullFrame(struct rt_rtmp_adapter *pAd, |
| u8 TxRate, IN BOOLEAN bQosNull) |
| { |
| u8 NullFrame[48]; |
| unsigned long Length; |
| struct rt_header_802_11 * pHeader_802_11; |
| |
| /* WPA 802.1x secured port control */ |
| if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || |
| (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) |
| || (pAd->StaCfg.IEEE8021X == TRUE) |
| ) && (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) { |
| return; |
| } |
| |
| NdisZeroMemory(NullFrame, 48); |
| Length = sizeof(struct rt_header_802_11); |
| |
| pHeader_802_11 = (struct rt_header_802_11 *) NullFrame; |
| |
| pHeader_802_11->FC.Type = BTYPE_DATA; |
| pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; |
| pHeader_802_11->FC.ToDs = 1; |
| COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); |
| COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); |
| COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); |
| |
| if (pAd->CommonCfg.bAPSDForcePowerSave) { |
| pHeader_802_11->FC.PwrMgmt = PWR_SAVE; |
| } else { |
| pHeader_802_11->FC.PwrMgmt = |
| (pAd->StaCfg.Psm == PWR_SAVE) ? 1 : 0; |
| } |
| pHeader_802_11->Duration = |
| pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); |
| |
| pAd->Sequence++; |
| pHeader_802_11->Sequence = pAd->Sequence; |
| |
| /* Prepare QosNull function frame */ |
| if (bQosNull) { |
| pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; |
| |
| /* copy QOS control bytes */ |
| NullFrame[Length] = 0; |
| NullFrame[Length + 1] = 0; |
| Length += 2; /* if pad with 2 bytes for alignment, APSD will fail */ |
| } |
| |
| HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); |
| |
| } |
| |
| /* IRQL = DISPATCH_LEVEL */ |
| void RTMPSendRTSFrame(struct rt_rtmp_adapter *pAd, |
| u8 *pDA, |
| IN unsigned int NextMpduSize, |
| u8 TxRate, |
| u8 RTSRate, |
| u16 AckDuration, u8 QueIdx, u8 FrameGap) |
| { |
| } |
| |
| /* -------------------------------------------------------- */ |
| /* FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM */ |
| /* Find the WPA key, either Group or Pairwise Key */ |
| /* LEAP + TKIP also use WPA key. */ |
| /* -------------------------------------------------------- */ |
| /* Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst */ |
| /* In Cisco CCX 2.0 Leap Authentication */ |
| /* WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey */ |
| /* Instead of the SharedKey, SharedKey Length may be Zero. */ |
| void STAFindCipherAlgorithm(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| NDIS_802_11_ENCRYPTION_STATUS Cipher; /* To indicate cipher used for this packet */ |
| u8 CipherAlg = CIPHER_NONE; /* cipher alogrithm */ |
| u8 KeyIdx = 0xff; |
| u8 *pSrcBufVA; |
| struct rt_cipher_key *pKey = NULL; |
| |
| pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); |
| |
| { |
| /* Select Cipher */ |
| if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) |
| Cipher = pAd->StaCfg.GroupCipher; /* Cipher for Multicast or Broadcast */ |
| else |
| Cipher = pAd->StaCfg.PairCipher; /* Cipher for Unicast */ |
| |
| if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) { |
| ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= |
| CIPHER_CKIP128); |
| |
| /* 4-way handshaking frame must be clear */ |
| if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) |
| && (pAd->SharedKey[BSS0][0].CipherAlg) |
| && (pAd->SharedKey[BSS0][0].KeyLen)) { |
| CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; |
| KeyIdx = 0; |
| } |
| } else if (Cipher == Ndis802_11Encryption1Enabled) { |
| KeyIdx = pAd->StaCfg.DefaultKeyId; |
| } else if ((Cipher == Ndis802_11Encryption2Enabled) || |
| (Cipher == Ndis802_11Encryption3Enabled)) { |
| if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) /* multicast */ |
| KeyIdx = pAd->StaCfg.DefaultKeyId; |
| else if (pAd->SharedKey[BSS0][0].KeyLen) |
| KeyIdx = 0; |
| else |
| KeyIdx = pAd->StaCfg.DefaultKeyId; |
| } |
| |
| if (KeyIdx == 0xff) |
| CipherAlg = CIPHER_NONE; |
| else if ((Cipher == Ndis802_11EncryptionDisabled) |
| || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) |
| CipherAlg = CIPHER_NONE; |
| else if (pAd->StaCfg.WpaSupplicantUP && |
| (Cipher == Ndis802_11Encryption1Enabled) && |
| (pAd->StaCfg.IEEE8021X == TRUE) && |
| (pAd->StaCfg.PortSecured == |
| WPA_802_1X_PORT_NOT_SECURED)) |
| CipherAlg = CIPHER_NONE; |
| else { |
| /*Header_802_11.FC.Wep = 1; */ |
| CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; |
| pKey = &pAd->SharedKey[BSS0][KeyIdx]; |
| } |
| } |
| |
| pTxBlk->CipherAlg = CipherAlg; |
| pTxBlk->pKey = pKey; |
| } |
| |
| void STABuildCommon802_11Header(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| struct rt_header_802_11 *pHeader_802_11; |
| |
| /* */ |
| /* MAKE A COMMON 802.11 HEADER */ |
| /* */ |
| |
| /* normal wlan header size : 24 octets */ |
| pTxBlk->MpduHeaderLen = sizeof(struct rt_header_802_11); |
| |
| pHeader_802_11 = |
| (struct rt_header_802_11 *) & pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| |
| NdisZeroMemory(pHeader_802_11, sizeof(struct rt_header_802_11)); |
| |
| pHeader_802_11->FC.FrDs = 0; |
| pHeader_802_11->FC.Type = BTYPE_DATA; |
| pHeader_802_11->FC.SubType = |
| ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : |
| SUBTYPE_DATA); |
| |
| if (pTxBlk->pMacEntry) { |
| if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) { |
| pHeader_802_11->Sequence = |
| pTxBlk->pMacEntry->NonQosDataSeq; |
| pTxBlk->pMacEntry->NonQosDataSeq = |
| (pTxBlk->pMacEntry->NonQosDataSeq + 1) & MAXSEQ; |
| } else { |
| { |
| pHeader_802_11->Sequence = |
| pTxBlk->pMacEntry->TxSeq[pTxBlk-> |
| UserPriority]; |
| pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = |
| (pTxBlk->pMacEntry-> |
| TxSeq[pTxBlk->UserPriority] + 1) & MAXSEQ; |
| } |
| } |
| } else { |
| pHeader_802_11->Sequence = pAd->Sequence; |
| pAd->Sequence = (pAd->Sequence + 1) & MAXSEQ; /* next sequence */ |
| } |
| |
| pHeader_802_11->Frag = 0; |
| |
| pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); |
| |
| { |
| if (INFRA_ON(pAd)) { |
| { |
| COPY_MAC_ADDR(pHeader_802_11->Addr1, |
| pAd->CommonCfg.Bssid); |
| COPY_MAC_ADDR(pHeader_802_11->Addr2, |
| pAd->CurrentAddress); |
| COPY_MAC_ADDR(pHeader_802_11->Addr3, |
| pTxBlk->pSrcBufHeader); |
| pHeader_802_11->FC.ToDs = 1; |
| } |
| } else if (ADHOC_ON(pAd)) { |
| COPY_MAC_ADDR(pHeader_802_11->Addr1, |
| pTxBlk->pSrcBufHeader); |
| COPY_MAC_ADDR(pHeader_802_11->Addr2, |
| pAd->CurrentAddress); |
| COPY_MAC_ADDR(pHeader_802_11->Addr3, |
| pAd->CommonCfg.Bssid); |
| pHeader_802_11->FC.ToDs = 0; |
| } |
| } |
| |
| if (pTxBlk->CipherAlg != CIPHER_NONE) |
| pHeader_802_11->FC.Wep = 1; |
| |
| /* ----------------------------------------------------------------- */ |
| /* STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. */ |
| /* ----------------------------------------------------------------- */ |
| if (pAd->CommonCfg.bAPSDForcePowerSave) |
| pHeader_802_11->FC.PwrMgmt = PWR_SAVE; |
| else |
| pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); |
| } |
| |
| void STABuildCache802_11Header(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, u8 * pHeader) |
| { |
| struct rt_mac_table_entry *pMacEntry; |
| struct rt_header_802_11 * pHeader80211; |
| |
| pHeader80211 = (struct rt_header_802_11 *) pHeader; |
| pMacEntry = pTxBlk->pMacEntry; |
| |
| /* */ |
| /* Update the cached 802.11 HEADER */ |
| /* */ |
| |
| /* normal wlan header size : 24 octets */ |
| pTxBlk->MpduHeaderLen = sizeof(struct rt_header_802_11); |
| |
| /* More Bit */ |
| pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); |
| |
| /* Sequence */ |
| pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; |
| pMacEntry->TxSeq[pTxBlk->UserPriority] = |
| (pMacEntry->TxSeq[pTxBlk->UserPriority] + 1) & MAXSEQ; |
| |
| { |
| /* Check if the frame can be sent through DLS direct link interface */ |
| /* If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) */ |
| |
| /* The addr3 of normal packet send from DS is Dest Mac address. */ |
| if (ADHOC_ON(pAd)) |
| COPY_MAC_ADDR(pHeader80211->Addr3, |
| pAd->CommonCfg.Bssid); |
| else |
| COPY_MAC_ADDR(pHeader80211->Addr3, |
| pTxBlk->pSrcBufHeader); |
| } |
| |
| /* ----------------------------------------------------------------- */ |
| /* STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. */ |
| /* ----------------------------------------------------------------- */ |
| if (pAd->CommonCfg.bAPSDForcePowerSave) |
| pHeader80211->FC.PwrMgmt = PWR_SAVE; |
| else |
| pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); |
| } |
| |
| static inline u8 *STA_Build_ARalink_Frame_Header(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk) |
| { |
| u8 *pHeaderBufPtr; |
| struct rt_header_802_11 *pHeader_802_11; |
| void *pNextPacket; |
| u32 nextBufLen; |
| struct rt_queue_entry *pQEntry; |
| |
| STAFindCipherAlgorithm(pAd, pTxBlk); |
| STABuildCommon802_11Header(pAd, pTxBlk); |
| |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| pHeader_802_11 = (struct rt_header_802_11 *) pHeaderBufPtr; |
| |
| /* steal "order" bit to mark "aggregation" */ |
| pHeader_802_11->FC.Order = 1; |
| |
| /* skip common header */ |
| pHeaderBufPtr += pTxBlk->MpduHeaderLen; |
| |
| if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) { |
| /* */ |
| /* build QOS Control bytes */ |
| /* */ |
| *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); |
| |
| *(pHeaderBufPtr + 1) = 0; |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| } |
| /* padding at front of LLC header. LLC header should at 4-bytes aligment. */ |
| pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; |
| pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); |
| pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); |
| |
| /* For RA Aggregation, */ |
| /* put the 2nd MSDU length(extra 2-byte field) after struct rt_qos_control in little endian format */ |
| pQEntry = pTxBlk->TxPacketList.Head; |
| pNextPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| nextBufLen = GET_OS_PKT_LEN(pNextPacket); |
| if (RTMP_GET_PACKET_VLAN(pNextPacket)) |
| nextBufLen -= LENGTH_802_1Q; |
| |
| *pHeaderBufPtr = (u8)nextBufLen & 0xff; |
| *(pHeaderBufPtr + 1) = (u8)(nextBufLen >> 8); |
| |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| |
| return pHeaderBufPtr; |
| |
| } |
| |
| static inline u8 *STA_Build_AMSDU_Frame_Header(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk) |
| { |
| u8 *pHeaderBufPtr; /*, pSaveBufPtr; */ |
| struct rt_header_802_11 *pHeader_802_11; |
| |
| STAFindCipherAlgorithm(pAd, pTxBlk); |
| STABuildCommon802_11Header(pAd, pTxBlk); |
| |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| pHeader_802_11 = (struct rt_header_802_11 *) pHeaderBufPtr; |
| |
| /* skip common header */ |
| pHeaderBufPtr += pTxBlk->MpduHeaderLen; |
| |
| /* */ |
| /* build QOS Control bytes */ |
| /* */ |
| *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); |
| |
| /* */ |
| /* A-MSDU packet */ |
| /* */ |
| *pHeaderBufPtr |= 0x80; |
| |
| *(pHeaderBufPtr + 1) = 0; |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| |
| /*pSaveBufPtr = pHeaderBufPtr; */ |
| |
| /* */ |
| /* padding at front of LLC header */ |
| /* LLC header should locate at 4-octets aligment */ |
| /* */ |
| /* @@@ MpduHeaderLen excluding padding @@@ */ |
| /* */ |
| pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; |
| pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); |
| pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); |
| |
| return pHeaderBufPtr; |
| |
| } |
| |
| void STA_AMPDU_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| struct rt_header_802_11 *pHeader_802_11; |
| u8 *pHeaderBufPtr; |
| u16 FreeNumber; |
| struct rt_mac_table_entry *pMacEntry; |
| BOOLEAN bVLANPkt; |
| struct rt_queue_entry *pQEntry; |
| |
| ASSERT(pTxBlk); |
| |
| while (pTxBlk->TxPacketList.Head) { |
| pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) { |
| RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, |
| NDIS_STATUS_FAILURE); |
| continue; |
| } |
| |
| bVLANPkt = |
| (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); |
| |
| pMacEntry = pTxBlk->pMacEntry; |
| if (pMacEntry->isCached) { |
| /* NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]! */ |
| NdisMoveMemory((u8 *)& pTxBlk-> |
| HeaderBuf[TXINFO_SIZE], |
| (u8 *)& pMacEntry->CachedBuf[0], |
| TXWI_SIZE + sizeof(struct rt_header_802_11)); |
| pHeaderBufPtr = |
| (u8 *)(&pTxBlk-> |
| HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); |
| STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); |
| } else { |
| STAFindCipherAlgorithm(pAd, pTxBlk); |
| STABuildCommon802_11Header(pAd, pTxBlk); |
| |
| pHeaderBufPtr = |
| &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| } |
| |
| pHeader_802_11 = (struct rt_header_802_11 *) pHeaderBufPtr; |
| |
| /* skip common header */ |
| pHeaderBufPtr += pTxBlk->MpduHeaderLen; |
| |
| /* */ |
| /* build QOS Control bytes */ |
| /* */ |
| *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); |
| *(pHeaderBufPtr + 1) = 0; |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| |
| /* */ |
| /* build HTC+ */ |
| /* HTC control filed following QoS field */ |
| /* */ |
| if ((pAd->CommonCfg.bRdg == TRUE) |
| && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, |
| fCLIENT_STATUS_RDG_CAPABLE)) { |
| if (pMacEntry->isCached == FALSE) { |
| /* mark HTC bit */ |
| pHeader_802_11->FC.Order = 1; |
| |
| NdisZeroMemory(pHeaderBufPtr, 4); |
| *(pHeaderBufPtr + 3) |= 0x80; |
| } |
| pHeaderBufPtr += 4; |
| pTxBlk->MpduHeaderLen += 4; |
| } |
| /*pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; */ |
| ASSERT(pTxBlk->MpduHeaderLen >= 24); |
| |
| /* skip 802.3 header */ |
| pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; |
| pTxBlk->SrcBufLen -= LENGTH_802_3; |
| |
| /* skip vlan tag */ |
| if (bVLANPkt) { |
| pTxBlk->pSrcBufData += LENGTH_802_1Q; |
| pTxBlk->SrcBufLen -= LENGTH_802_1Q; |
| } |
| /* */ |
| /* padding at front of LLC header */ |
| /* LLC header should locate at 4-octets aligment */ |
| /* */ |
| /* @@@ MpduHeaderLen excluding padding @@@ */ |
| /* */ |
| pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; |
| pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); |
| pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); |
| |
| { |
| |
| /* */ |
| /* Insert LLC-SNAP encapsulation - 8 octets */ |
| /* */ |
| EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk-> |
| pSrcBufData - 2, |
| pTxBlk-> |
| pExtraLlcSnapEncap); |
| if (pTxBlk->pExtraLlcSnapEncap) { |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pExtraLlcSnapEncap, 6); |
| pHeaderBufPtr += 6; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pSrcBufData - 2, 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += LENGTH_802_1_H; |
| } |
| |
| } |
| |
| if (pMacEntry->isCached) { |
| RTMPWriteTxWI_Cache(pAd, |
| (struct rt_txwi *) (&pTxBlk-> |
| HeaderBuf |
| [TXINFO_SIZE]), |
| pTxBlk); |
| } else { |
| RTMPWriteTxWI_Data(pAd, |
| (struct rt_txwi *) (&pTxBlk-> |
| HeaderBuf |
| [TXINFO_SIZE]), |
| pTxBlk); |
| |
| NdisZeroMemory((u8 *)(&pMacEntry->CachedBuf[0]), |
| sizeof(pMacEntry->CachedBuf)); |
| NdisMoveMemory((u8 *)(&pMacEntry->CachedBuf[0]), |
| (u8 *)(&pTxBlk-> |
| HeaderBuf[TXINFO_SIZE]), |
| (pHeaderBufPtr - |
| (u8 *)(&pTxBlk-> |
| HeaderBuf[TXINFO_SIZE]))); |
| pMacEntry->isCached = TRUE; |
| } |
| |
| /* calculate Transmitted AMPDU count and ByteCount */ |
| { |
| pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u. |
| LowPart++; |
| pAd->RalinkCounters.TransmittedOctetsInAMPDUCount. |
| QuadPart += pTxBlk->SrcBufLen; |
| } |
| |
| /*FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); */ |
| |
| HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); |
| |
| /* */ |
| /* Kick out Tx */ |
| /* */ |
| if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) |
| HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| } |
| |
| } |
| |
| void STA_AMSDU_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| u8 *pHeaderBufPtr; |
| u16 FreeNumber; |
| u16 subFramePayloadLen = 0; /* AMSDU Subframe length without AMSDU-Header / Padding. */ |
| u16 totalMPDUSize = 0; |
| u8 *subFrameHeader; |
| u8 padding = 0; |
| u16 FirstTx = 0, LastTxIdx = 0; |
| BOOLEAN bVLANPkt; |
| int frameNum = 0; |
| struct rt_queue_entry *pQEntry; |
| |
| ASSERT(pTxBlk); |
| |
| ASSERT((pTxBlk->TxPacketList.Number > 1)); |
| |
| while (pTxBlk->TxPacketList.Head) { |
| pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) { |
| RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, |
| NDIS_STATUS_FAILURE); |
| continue; |
| } |
| |
| bVLANPkt = |
| (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); |
| |
| /* skip 802.3 header */ |
| pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; |
| pTxBlk->SrcBufLen -= LENGTH_802_3; |
| |
| /* skip vlan tag */ |
| if (bVLANPkt) { |
| pTxBlk->pSrcBufData += LENGTH_802_1Q; |
| pTxBlk->SrcBufLen -= LENGTH_802_1Q; |
| } |
| |
| if (frameNum == 0) { |
| pHeaderBufPtr = |
| STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); |
| |
| /* NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. */ |
| RTMPWriteTxWI_Data(pAd, |
| (struct rt_txwi *) (&pTxBlk-> |
| HeaderBuf |
| [TXINFO_SIZE]), |
| pTxBlk); |
| } else { |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; |
| padding = |
| ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + |
| subFramePayloadLen, |
| 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + |
| subFramePayloadLen); |
| NdisZeroMemory(pHeaderBufPtr, |
| padding + LENGTH_AMSDU_SUBFRAMEHEAD); |
| pHeaderBufPtr += padding; |
| pTxBlk->MpduHeaderLen = padding; |
| } |
| |
| /* */ |
| /* A-MSDU subframe */ |
| /* DA(6)+SA(6)+Length(2) + LLC/SNAP Encap */ |
| /* */ |
| subFrameHeader = pHeaderBufPtr; |
| subFramePayloadLen = pTxBlk->SrcBufLen; |
| |
| NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); |
| |
| pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; |
| pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; |
| |
| /* */ |
| /* Insert LLC-SNAP encapsulation - 8 octets */ |
| /* */ |
| EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData - 2, |
| pTxBlk->pExtraLlcSnapEncap); |
| |
| subFramePayloadLen = pTxBlk->SrcBufLen; |
| |
| if (pTxBlk->pExtraLlcSnapEncap) { |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pExtraLlcSnapEncap, 6); |
| pHeaderBufPtr += 6; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData - 2, |
| 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += LENGTH_802_1_H; |
| subFramePayloadLen += LENGTH_802_1_H; |
| } |
| /* update subFrame Length field */ |
| subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; |
| subFrameHeader[13] = subFramePayloadLen & 0xFF; |
| |
| totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; |
| |
| if (frameNum == 0) |
| FirstTx = |
| HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, |
| &FreeNumber); |
| else |
| LastTxIdx = |
| HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, |
| &FreeNumber); |
| |
| frameNum++; |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| /* calculate Transmitted AMSDU Count and ByteCount */ |
| { |
| pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart++; |
| pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += |
| totalMPDUSize; |
| } |
| |
| } |
| |
| HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); |
| HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); |
| |
| /* */ |
| /* Kick out Tx */ |
| /* */ |
| if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) |
| HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); |
| } |
| |
| void STA_Legacy_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| struct rt_header_802_11 *pHeader_802_11; |
| u8 *pHeaderBufPtr; |
| u16 FreeNumber; |
| BOOLEAN bVLANPkt; |
| struct rt_queue_entry *pQEntry; |
| |
| ASSERT(pTxBlk); |
| |
| pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) { |
| RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| if (pTxBlk->TxFrameType == TX_MCAST_FRAME) { |
| INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); |
| } |
| |
| if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) |
| TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); |
| else |
| TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); |
| |
| bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); |
| |
| if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) |
| pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; |
| |
| STAFindCipherAlgorithm(pAd, pTxBlk); |
| STABuildCommon802_11Header(pAd, pTxBlk); |
| |
| /* skip 802.3 header */ |
| pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; |
| pTxBlk->SrcBufLen -= LENGTH_802_3; |
| |
| /* skip vlan tag */ |
| if (bVLANPkt) { |
| pTxBlk->pSrcBufData += LENGTH_802_1Q; |
| pTxBlk->SrcBufLen -= LENGTH_802_1Q; |
| } |
| |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| pHeader_802_11 = (struct rt_header_802_11 *) pHeaderBufPtr; |
| |
| /* skip common header */ |
| pHeaderBufPtr += pTxBlk->MpduHeaderLen; |
| |
| if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) { |
| /* */ |
| /* build QOS Control bytes */ |
| /* */ |
| *(pHeaderBufPtr) = |
| ((pTxBlk->UserPriority & 0x0F) | (pAd->CommonCfg. |
| AckPolicy[pTxBlk-> |
| QueIdx] << 5)); |
| *(pHeaderBufPtr + 1) = 0; |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| } |
| /* The remaining content of MPDU header should locate at 4-octets aligment */ |
| pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; |
| pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); |
| pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); |
| |
| { |
| |
| /* */ |
| /* Insert LLC-SNAP encapsulation - 8 octets */ |
| /* */ |
| /* */ |
| /* if original Ethernet frame contains no LLC/SNAP, */ |
| /* then an extra LLC/SNAP encap is required */ |
| /* */ |
| EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, |
| pTxBlk->pExtraLlcSnapEncap); |
| if (pTxBlk->pExtraLlcSnapEncap) { |
| u8 vlan_size; |
| |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pExtraLlcSnapEncap, 6); |
| pHeaderBufPtr += 6; |
| /* skip vlan tag */ |
| vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pSrcBufHeader + 12 + vlan_size, |
| 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += LENGTH_802_1_H; |
| } |
| |
| } |
| |
| /* */ |
| /* prepare for TXWI */ |
| /* use Wcid as Key Index */ |
| /* */ |
| |
| RTMPWriteTxWI_Data(pAd, (struct rt_txwi *) (&pTxBlk->HeaderBuf[TXINFO_SIZE]), |
| pTxBlk); |
| |
| /*FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); */ |
| |
| HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| /* */ |
| /* Kick out Tx */ |
| /* */ |
| if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) |
| HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); |
| } |
| |
| void STA_ARalink_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| u8 *pHeaderBufPtr; |
| u16 FreeNumber; |
| u16 totalMPDUSize = 0; |
| u16 FirstTx, LastTxIdx; |
| int frameNum = 0; |
| BOOLEAN bVLANPkt; |
| struct rt_queue_entry *pQEntry; |
| |
| ASSERT(pTxBlk); |
| |
| ASSERT((pTxBlk->TxPacketList.Number == 2)); |
| |
| FirstTx = LastTxIdx = 0; /* Is it ok init they as 0? */ |
| while (pTxBlk->TxPacketList.Head) { |
| pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| |
| if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) { |
| RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, |
| NDIS_STATUS_FAILURE); |
| continue; |
| } |
| |
| bVLANPkt = |
| (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); |
| |
| /* skip 802.3 header */ |
| pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; |
| pTxBlk->SrcBufLen -= LENGTH_802_3; |
| |
| /* skip vlan tag */ |
| if (bVLANPkt) { |
| pTxBlk->pSrcBufData += LENGTH_802_1Q; |
| pTxBlk->SrcBufLen -= LENGTH_802_1Q; |
| } |
| |
| if (frameNum == 0) { /* For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header */ |
| |
| pHeaderBufPtr = |
| STA_Build_ARalink_Frame_Header(pAd, pTxBlk); |
| |
| /* It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount */ |
| /* will be updated after final frame was handled. */ |
| RTMPWriteTxWI_Data(pAd, |
| (struct rt_txwi *) (&pTxBlk-> |
| HeaderBuf |
| [TXINFO_SIZE]), |
| pTxBlk); |
| |
| /* */ |
| /* Insert LLC-SNAP encapsulation - 8 octets */ |
| /* */ |
| EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk-> |
| pSrcBufData - 2, |
| pTxBlk-> |
| pExtraLlcSnapEncap); |
| |
| if (pTxBlk->pExtraLlcSnapEncap) { |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pExtraLlcSnapEncap, 6); |
| pHeaderBufPtr += 6; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pSrcBufData - 2, 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += LENGTH_802_1_H; |
| } |
| } else { /* For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. */ |
| |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; |
| pTxBlk->MpduHeaderLen = 0; |
| |
| /* A-Ralink sub-sequent frame header is the same as 802.3 header. */ |
| /* DA(6)+SA(6)+FrameType(2) */ |
| NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, |
| 12); |
| pHeaderBufPtr += 12; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData - 2, |
| 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; |
| } |
| |
| totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; |
| |
| /*FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); */ |
| if (frameNum == 0) |
| FirstTx = |
| HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, |
| &FreeNumber); |
| else |
| LastTxIdx = |
| HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, |
| &FreeNumber); |
| |
| frameNum++; |
| |
| pAd->RalinkCounters.OneSecTxAggregationCount++; |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| } |
| |
| HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); |
| HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); |
| |
| /* */ |
| /* Kick out Tx */ |
| /* */ |
| if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) |
| HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); |
| |
| } |
| |
| void STA_Fragment_Frame_Tx(struct rt_rtmp_adapter *pAd, struct rt_tx_blk *pTxBlk) |
| { |
| struct rt_header_802_11 *pHeader_802_11; |
| u8 *pHeaderBufPtr; |
| u16 FreeNumber; |
| u8 fragNum = 0; |
| struct rt_packet_info PacketInfo; |
| u16 EncryptionOverhead = 0; |
| u32 FreeMpduSize, SrcRemainingBytes; |
| u16 AckDuration; |
| u32 NextMpduSize; |
| BOOLEAN bVLANPkt; |
| struct rt_queue_entry *pQEntry; |
| HTTRANSMIT_SETTING *pTransmit; |
| |
| ASSERT(pTxBlk); |
| |
| pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) { |
| RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); |
| return; |
| } |
| |
| ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); |
| bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); |
| |
| STAFindCipherAlgorithm(pAd, pTxBlk); |
| STABuildCommon802_11Header(pAd, pTxBlk); |
| |
| if (pTxBlk->CipherAlg == CIPHER_TKIP) { |
| pTxBlk->pPacket = |
| duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); |
| if (pTxBlk->pPacket == NULL) |
| return; |
| RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, |
| &pTxBlk->pSrcBufHeader, |
| &pTxBlk->SrcBufLen); |
| } |
| /* skip 802.3 header */ |
| pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; |
| pTxBlk->SrcBufLen -= LENGTH_802_3; |
| |
| /* skip vlan tag */ |
| if (bVLANPkt) { |
| pTxBlk->pSrcBufData += LENGTH_802_1Q; |
| pTxBlk->SrcBufLen -= LENGTH_802_1Q; |
| } |
| |
| pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; |
| pHeader_802_11 = (struct rt_header_802_11 *) pHeaderBufPtr; |
| |
| /* skip common header */ |
| pHeaderBufPtr += pTxBlk->MpduHeaderLen; |
| |
| if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) { |
| /* */ |
| /* build QOS Control bytes */ |
| /* */ |
| *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); |
| |
| *(pHeaderBufPtr + 1) = 0; |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += 2; |
| } |
| /* */ |
| /* padding at front of LLC header */ |
| /* LLC header should locate at 4-octets aligment */ |
| /* */ |
| pTxBlk->HdrPadLen = (unsigned long)pHeaderBufPtr; |
| pHeaderBufPtr = (u8 *)ROUND_UP(pHeaderBufPtr, 4); |
| pTxBlk->HdrPadLen = (unsigned long)(pHeaderBufPtr - pTxBlk->HdrPadLen); |
| |
| /* */ |
| /* Insert LLC-SNAP encapsulation - 8 octets */ |
| /* */ |
| /* */ |
| /* if original Ethernet frame contains no LLC/SNAP, */ |
| /* then an extra LLC/SNAP encap is required */ |
| /* */ |
| EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, |
| pTxBlk->pExtraLlcSnapEncap); |
| if (pTxBlk->pExtraLlcSnapEncap) { |
| u8 vlan_size; |
| |
| NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); |
| pHeaderBufPtr += 6; |
| /* skip vlan tag */ |
| vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; |
| /* get 2 octets (TypeofLen) */ |
| NdisMoveMemory(pHeaderBufPtr, |
| pTxBlk->pSrcBufHeader + 12 + vlan_size, 2); |
| pHeaderBufPtr += 2; |
| pTxBlk->MpduHeaderLen += LENGTH_802_1_H; |
| } |
| |
| /* If TKIP is used and fragmentation is required. Driver has to */ |
| /* append TKIP MIC at tail of the scatter buffer */ |
| /* MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC */ |
| if (pTxBlk->CipherAlg == CIPHER_TKIP) { |
| RTMPCalculateMICValue(pAd, pTxBlk->pPacket, |
| pTxBlk->pExtraLlcSnapEncap, pTxBlk->pKey, |
| 0); |
| |
| /* NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust */ |
| /* to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. */ |
| NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, |
| &pAd->PrivateInfo.Tx.MIC[0], 8); |
| /*skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); */ |
| pTxBlk->SrcBufLen += 8; |
| pTxBlk->TotalFrameLen += 8; |
| pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; |
| } |
| /* */ |
| /* calcuate the overhead bytes that encryption algorithm may add. This */ |
| /* affects the calculate of "duration" field */ |
| /* */ |
| if ((pTxBlk->CipherAlg == CIPHER_WEP64) |
| || (pTxBlk->CipherAlg == CIPHER_WEP128)) |
| EncryptionOverhead = 8; /*WEP: IV[4] + ICV[4]; */ |
| else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) |
| EncryptionOverhead = 12; /*TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength */ |
| else if (pTxBlk->CipherAlg == CIPHER_TKIP) |
| EncryptionOverhead = 20; /*TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] */ |
| else if (pTxBlk->CipherAlg == CIPHER_AES) |
| EncryptionOverhead = 16; /* AES: IV[4] + EIV[4] + MIC[8] */ |
| else |
| EncryptionOverhead = 0; |
| |
| pTransmit = pTxBlk->pTransmit; |
| /* Decide the TX rate */ |
| if (pTransmit->field.MODE == MODE_CCK) |
| pTxBlk->TxRate = pTransmit->field.MCS; |
| else if (pTransmit->field.MODE == MODE_OFDM) |
| pTxBlk->TxRate = pTransmit->field.MCS + RATE_FIRST_OFDM_RATE; |
| else |
| pTxBlk->TxRate = RATE_6_5; |
| |
| /* decide how much time an ACK/CTS frame will consume in the air */ |
| if (pTxBlk->TxRate <= RATE_LAST_OFDM_RATE) |
| AckDuration = |
| RTMPCalcDuration(pAd, |
| pAd->CommonCfg.ExpectedACKRate[pTxBlk-> |
| TxRate], |
| 14); |
| else |
| AckDuration = RTMPCalcDuration(pAd, RATE_6_5, 14); |
| |
| /* Init the total payload length of this frame. */ |
| SrcRemainingBytes = pTxBlk->SrcBufLen; |
| |
| pTxBlk->TotalFragNum = 0xff; |
| |
| do { |
| |
| FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; |
| |
| FreeMpduSize -= pTxBlk->MpduHeaderLen; |
| |
| if (SrcRemainingBytes <= FreeMpduSize) { /* this is the last or only fragment */ |
| |
| pTxBlk->SrcBufLen = SrcRemainingBytes; |
| |
| pHeader_802_11->FC.MoreFrag = 0; |
| pHeader_802_11->Duration = |
| pAd->CommonCfg.Dsifs + AckDuration; |
| |
| /* Indicate the lower layer that this's the last fragment. */ |
| pTxBlk->TotalFragNum = fragNum; |
| } else { /* more fragment is required */ |
| |
| pTxBlk->SrcBufLen = FreeMpduSize; |
| |
| NextMpduSize = |
| min(((u32)SrcRemainingBytes - pTxBlk->SrcBufLen), |
| ((u32)pAd->CommonCfg.FragmentThreshold)); |
| pHeader_802_11->FC.MoreFrag = 1; |
| pHeader_802_11->Duration = |
| (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + |
| RTMPCalcDuration(pAd, pTxBlk->TxRate, |
| NextMpduSize + EncryptionOverhead); |
| } |
| |
| if (fragNum == 0) |
| pTxBlk->FrameGap = IFS_HTTXOP; |
| else |
| pTxBlk->FrameGap = IFS_SIFS; |
| |
| RTMPWriteTxWI_Data(pAd, |
| (struct rt_txwi *) (&pTxBlk-> |
| HeaderBuf[TXINFO_SIZE]), |
| pTxBlk); |
| |
| HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); |
| |
| pAd->RalinkCounters.KickTxCount++; |
| pAd->RalinkCounters.OneSecTxDoneCount++; |
| |
| /* Update the frame number, remaining size of the NDIS packet payload. */ |
| |
| /* space for 802.11 header. */ |
| if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) |
| pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; |
| |
| fragNum++; |
| SrcRemainingBytes -= pTxBlk->SrcBufLen; |
| pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; |
| |
| pHeader_802_11->Frag++; /* increase Frag # */ |
| |
| } while (SrcRemainingBytes > 0); |
| |
| /* */ |
| /* Kick out Tx */ |
| /* */ |
| if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) |
| HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); |
| } |
| |
| #define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ |
| while(_pTxBlk->TxPacketList.Head) \ |
| { \ |
| _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ |
| RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Copy frame from waiting queue into relative ring buffer and set |
| appropriate ASIC register to kick hardware encryption before really |
| sent out to air. |
| |
| Arguments: |
| pAd Pointer to our adapter |
| void * Pointer to outgoing Ndis frame |
| NumberOfFrag Number of fragment required |
| |
| Return Value: |
| None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Note: |
| |
| ======================================================================== |
| */ |
| int STAHardTransmit(struct rt_rtmp_adapter *pAd, |
| struct rt_tx_blk *pTxBlk, u8 QueIdx) |
| { |
| char *pPacket; |
| struct rt_queue_entry *pQEntry; |
| |
| /* --------------------------------------------- */ |
| /* STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. */ |
| /* --------------------------------------------- */ |
| /* */ |
| ASSERT(pTxBlk->TxPacketList.Number); |
| if (pTxBlk->TxPacketList.Head == NULL) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("pTxBlk->TotalFrameNum == %ld!\n", |
| pTxBlk->TxPacketList.Number)); |
| return NDIS_STATUS_FAILURE; |
| } |
| |
| pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); |
| |
| /* ------------------------------------------------------------------ */ |
| /* STEP 1. WAKE UP PHY */ |
| /* outgoing frame always wakeup PHY to prevent frame lost and */ |
| /* turn off PSM bit to improve performance */ |
| /* ------------------------------------------------------------------ */ |
| /* not to change PSM bit, just send this frame out? */ |
| if ((pAd->StaCfg.Psm == PWR_SAVE) |
| && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) { |
| DBGPRINT_RAW(RT_DEBUG_INFO, ("AsicForceWakeup At HardTx\n")); |
| #ifdef RTMP_MAC_PCI |
| AsicForceWakeup(pAd, TRUE); |
| #endif /* RTMP_MAC_PCI // */ |
| #ifdef RTMP_MAC_USB |
| RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_FORCE_WAKE_UP, NULL, 0); |
| #endif /* RTMP_MAC_USB // */ |
| } |
| /* It should not change PSM bit, when APSD turn on. */ |
| if ((! |
| (pAd->CommonCfg.bAPSDCapable |
| && pAd->CommonCfg.APEdcaParm.bAPSDCapable) |
| && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) |
| || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) |
| || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) { |
| if ((pAd->StaCfg.Psm == PWR_SAVE) && |
| (pAd->StaCfg.WindowsPowerMode == |
| Ndis802_11PowerModeFast_PSP)) |
| RTMP_SET_PSM_BIT(pAd, PWR_ACTIVE); |
| } |
| |
| switch (pTxBlk->TxFrameType) { |
| case TX_AMPDU_FRAME: |
| STA_AMPDU_Frame_Tx(pAd, pTxBlk); |
| break; |
| case TX_AMSDU_FRAME: |
| STA_AMSDU_Frame_Tx(pAd, pTxBlk); |
| break; |
| case TX_LEGACY_FRAME: |
| STA_Legacy_Frame_Tx(pAd, pTxBlk); |
| break; |
| case TX_MCAST_FRAME: |
| STA_Legacy_Frame_Tx(pAd, pTxBlk); |
| break; |
| case TX_RALINK_FRAME: |
| STA_ARalink_Frame_Tx(pAd, pTxBlk); |
| break; |
| case TX_FRAG_FRAME: |
| STA_Fragment_Frame_Tx(pAd, pTxBlk); |
| break; |
| default: |
| { |
| /* It should not happened! */ |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("Send a packet was not classified! It should not happen!\n")); |
| while (pTxBlk->TxPacketList.Number) { |
| pQEntry = |
| RemoveHeadQueue(&pTxBlk->TxPacketList); |
| pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); |
| if (pPacket) |
| RELEASE_NDIS_PACKET(pAd, pPacket, |
| NDIS_STATUS_FAILURE); |
| } |
| } |
| break; |
| } |
| |
| return (NDIS_STATUS_SUCCESS); |
| |
| } |
| |
| unsigned long HashBytesPolynomial(u8 * value, unsigned int len) |
| { |
| unsigned char *word = value; |
| unsigned int ret = 0; |
| unsigned int i; |
| |
| for (i = 0; i < len; i++) { |
| int mod = i % 32; |
| ret ^= (unsigned int)(word[i]) << mod; |
| ret ^= (unsigned int)(word[i]) >> (32 - mod); |
| } |
| return ret; |
| } |
| |
| void Sta_Announce_or_Forward_802_3_Packet(struct rt_rtmp_adapter *pAd, |
| void *pPacket, |
| u8 FromWhichBSSID) |
| { |
| if (TRUE) { |
| announce_802_3_packet(pAd, pPacket); |
| } else { |
| /* release packet */ |
| RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); |
| } |
| } |