/* ************************************************************************* * 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" #include 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(%pM) in MacTab!\n", 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 = 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); } }