//============================================================ // Description: // // This file is for TXBF interface mechanism // //============================================================ #include "mp_precomp.h" #include "../phydm_precomp.h" #if (BEAMFORMING_SUPPORT == 1) #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) VOID Beamforming_GidPAid( PADAPTER Adapter, PRT_TCB pTcb ) { u1Byte Idx = 0; u1Byte RA[6] ={0}; pu1Byte pHeader = GET_FRAME_OF_FIRST_FRAG(Adapter, pTcb); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); if (Adapter->HardwareType < HARDWARE_TYPE_RTL8192EE) return; else if (IS_WIRELESS_MODE_N(Adapter) == FALSE) return; #if (SUPPORT_MU_BF == 1) if (pTcb->TxBFPktType == RT_BF_PKT_TYPE_BROADCAST_NDPA) { /* MU NDPA */ #else if (0) { #endif /* Fill G_ID and P_AID */ pTcb->G_ID = 63; if (pBeamInfo->FirstMUBFeeIndex < BEAMFORMEE_ENTRY_NUM) { pTcb->P_AID = pBeamInfo->BeamformeeEntry[pBeamInfo->FirstMUBFeeIndex].P_AID; RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, pTcb->G_ID, pTcb->P_AID)); } } else { GET_80211_HDR_ADDRESS1(pHeader, &RA); // VHT SU PPDU carrying one or more group addressed MPDUs or // Transmitting a VHT NDP intended for multiple recipients if (MacAddr_isBcst(RA) || MacAddr_isMulticast(RA) || pTcb->macId == MAC_ID_STATIC_FOR_BROADCAST_MULTICAST) { pTcb->G_ID = 63; pTcb->P_AID = 0; } else if (ACTING_AS_AP(Adapter)) { u2Byte AID = (u2Byte) (MacIdGetOwnerAssociatedClientAID(Adapter, pTcb->macId) & 0x1ff); /*AID[0:8]*/ /*RT_DISP(FBEAM, FBEAM_FUN, ("@%s pTcb->macId=0x%X, AID=0x%X\n", __func__, pTcb->macId, AID));*/ pTcb->G_ID = 63; if (AID == 0) /*A PPDU sent by an AP to a non associated STA*/ pTcb->P_AID = 0; else { /*Sent by an AP and addressed to a STA associated with that AP*/ u2Byte BSSID = 0; GET_80211_HDR_ADDRESS2(pHeader, &RA); BSSID = ((RA[5] & 0xf0) >> 4) ^ (RA[5] & 0xf); /*BSSID[44:47] xor BSSID[40:43]*/ pTcb->P_AID = (AID + BSSID *32) & 0x1ff; /*(dec(A) + dec(B)*32) mod 512*/ } } else if (ACTING_AS_IBSS(Adapter)) { pTcb->G_ID = 63; /*P_AID for infrasturcture mode; MACID for ad-hoc mode. */ pTcb->P_AID = pTcb->macId; } else if (MgntLinkStatusQuery(Adapter)) { /*Addressed to AP*/ pTcb->G_ID = 0; GET_80211_HDR_ADDRESS1(pHeader, &RA); pTcb->P_AID = RA[5]; /*RA[39:47]*/ pTcb->P_AID = (pTcb->P_AID << 1) | (RA[4] >> 7 ); } else { pTcb->G_ID = 63; pTcb->P_AID = 0; } /*RT_DISP(FBEAM, FBEAM_FUN, ("[David]@%s End, G_ID=0x%X, P_AID=0x%X\n", __func__, pTcb->G_ID, pTcb->P_AID));*/ } } RT_STATUS Beamforming_GetReportFrame( IN PADAPTER Adapter, IN PRT_RFD pRfd, IN POCTET_STRING pPduOS ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; PRT_BEAMFORMEE_ENTRY pBeamformEntry = NULL; pu1Byte pMIMOCtrlField, pCSIReport, pCSIMatrix; u1Byte Idx, Nc, Nr, CH_W; u2Byte CSIMatrixLen = 0; ACT_PKT_TYPE pktType = ACT_PKT_TYPE_UNKNOWN; //Memory comparison to see if CSI report is the same with previous one pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, Frame_Addr2(*pPduOS), &Idx); if (pBeamformEntry == NULL) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetReportFrame: Cannot find entry by addr\n")); return RT_STATUS_FAILURE; } pktType = PacketGetActionFrameType(pPduOS); //-@ Modified by David if (pktType == ACT_PKT_VHT_COMPRESSED_BEAMFORMING) { pMIMOCtrlField = pPduOS->Octet + 26; Nc = ((*pMIMOCtrlField) & 0x7) + 1; Nr = (((*pMIMOCtrlField) & 0x38) >> 3) + 1; CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6); pCSIMatrix = pMIMOCtrlField + 3 + Nc; //24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2) CSIMatrixLen = pPduOS->Length - 26 -3 -Nc; } else if (pktType == ACT_PKT_HT_COMPRESSED_BEAMFORMING) { pMIMOCtrlField = pPduOS->Octet + 26; Nc = ((*pMIMOCtrlField) & 0x3) + 1; Nr = (((*pMIMOCtrlField) & 0xC) >> 2) + 1; CH_W = (((*pMIMOCtrlField) & 0x10) >> 4); pCSIMatrix = pMIMOCtrlField + 6 + Nr; //24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField) +SNR(Nc=2) CSIMatrixLen = pPduOS->Length - 26 -6 -Nr; } else return RT_STATUS_SUCCESS; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] idx=%d, pkt type=%d, Nc=%d, Nr=%d, CH_W=%d\n", __func__, Idx, pktType, Nc, Nr, CH_W)); return RT_STATUS_SUCCESS; } VOID ConstructHTNDPAPacket( PADAPTER Adapter, pu1Byte RA, pu1Byte Buffer, pu4Byte pLength, CHANNEL_WIDTH BW ) { u2Byte Duration= 0; PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); OCTET_STRING pNDPAFrame,ActionContent; u1Byte ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; PlatformZeroMemory(Buffer, 32); SET_80211_HDR_FRAME_CONTROL(Buffer,0); SET_80211_HDR_ORDER(Buffer, 1); SET_80211_HDR_TYPE_AND_SUBTYPE(Buffer,Type_Action_No_Ack); SET_80211_HDR_ADDRESS1(Buffer, RA); SET_80211_HDR_ADDRESS2(Buffer, Adapter->CurrentAddress); SET_80211_HDR_ADDRESS3(Buffer, pMgntInfo->Bssid); Duration = 2*aSifsTime + 40; if (BW == CHANNEL_WIDTH_40) Duration+= 87; else Duration+= 180; SET_80211_HDR_DURATION(Buffer, Duration); //HT control field SET_HT_CTRL_CSI_STEERING(Buffer+sMacHdrLng, 3); SET_HT_CTRL_NDP_ANNOUNCEMENT(Buffer+sMacHdrLng, 1); FillOctetString(pNDPAFrame, Buffer, sMacHdrLng+sHTCLng); FillOctetString(ActionContent, ActionHdr, 4); PacketAppendData(&pNDPAFrame, ActionContent); *pLength = 32; } BOOLEAN SendFWHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u4Byte BufLen; pu1Byte BufAddr; u1Byte DescLen = 0, Idx = 0, NDPTxRate; PADAPTER pDefAdapter = GetDefaultAdapter(Adapter); PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__)); if (pBeamformEntry == NULL) return FALSE; NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) { #if(DEV_BUS_TYPE != RT_PCI_INTERFACE) DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength; #endif BufAddr = pBuf->Buffer.VirtualAddress + DescLen; ConstructHTNDPAPacket( Adapter, RA, BufAddr, &BufLen, BW ); pTcb->PacketLength = BufLen + DescLen; pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; if(ACTING_AS_IBSS(Adapter) || ACTING_AS_AP(Adapter)) pTcb->G_ID = 63; pTcb->P_AID = pBeamformEntry->P_AID; pTcb->DataRate = NDPTxRate; /*rate of NDP decide by Nr*/ Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN SendSWHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte Idx = 0, NDPTxRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo; PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__)); NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructHTNDPAPacket( Adapter, RA, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength, BW ); pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } VOID ConstructVHTNDPAPacket( IN PDM_ODM_T pDM_Odm, pu1Byte RA, u2Byte AID, pu1Byte Buffer, pu4Byte pLength, CHANNEL_WIDTH BW ) { u2Byte Duration= 0; u1Byte Sequence = 0; pu1Byte pNDPAFrame = Buffer; RT_NDPA_STA_INFO STAInfo; PADAPTER Adapter = pDM_Odm->Adapter; u1Byte Idx = 0; PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); // Frame control. SET_80211_HDR_FRAME_CONTROL(pNDPAFrame, 0); SET_80211_HDR_TYPE_AND_SUBTYPE(pNDPAFrame, Type_NDPA); SET_80211_HDR_ADDRESS1(pNDPAFrame, RA); SET_80211_HDR_ADDRESS2(pNDPAFrame, pBeamformEntry->MyMacAddr); Duration = 2*aSifsTime + 44; if (BW == CHANNEL_WIDTH_80) Duration += 40; else if(BW == CHANNEL_WIDTH_40) Duration+= 87; else Duration+= 180; SET_80211_HDR_DURATION(pNDPAFrame, Duration); Sequence = *(pDM_Odm->pSoundingSeq) << 2; ODM_MoveMemory(pDM_Odm, pNDPAFrame+16, &Sequence, 1); if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS) || phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP) == FALSE) AID = 0; STAInfo.AID = AID; STAInfo.FeedbackType = 0; STAInfo.NcIndex = 0; ODM_MoveMemory(pDM_Odm, pNDPAFrame+17, (pu1Byte)&STAInfo, 2); *pLength = 19; } BOOLEAN SendFWVHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u4Byte BufLen; pu1Byte BufAddr; u1Byte DescLen = 0, Idx = 0, NDPTxRate = 0; PADAPTER pDefAdapter = GetDefaultAdapter(Adapter); PRT_BEAMFORMING_INFO pBeamInfo = &pDM_Odm->BeamformingInfo; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PRT_BEAMFORMEE_ENTRY pBeamformEntry =phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__)); if (pBeamformEntry == NULL) return FALSE; NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetFWBuffer(pDefAdapter, &pTcb, &pBuf)) { #if(DEV_BUS_TYPE != RT_PCI_INTERFACE) DescLen = Adapter->HWDescHeadLength - pHalData->USBALLDummyLength; #endif BufAddr = pBuf->Buffer.VirtualAddress + DescLen; ConstructVHTNDPAPacket( pDM_Odm, RA, AID, BufAddr, &BufLen, BW ); pTcb->PacketLength = BufLen + DescLen; pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; if (phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_IBSS) || phydm_actingDetermine(pDM_Odm, PhyDM_ACTING_AS_AP)) pTcb->G_ID = 63; pTcb->P_AID = pBeamformEntry->P_AID; pTcb->DataRate = NDPTxRate; /*decide by Nr*/ Adapter->HalFunc.CmdSendPacketHandler(Adapter, pTcb, pBuf, pTcb->PacketLength, DESC_PACKET_TYPE_NORMAL, FALSE); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] End, ret=%d\n", __func__, ret)); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } BOOLEAN SendSWVHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte Idx = 0, NDPTxRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructVHTNDPAPacket( pDM_Odm, RA, AID, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength, BW ); pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; /*rate of NDP decide by Nr*/ MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } #ifdef SUPPORT_MU_BF #if (SUPPORT_MU_BF == 1) /* // Description: On VHT GID management frame by an MU beamformee. // // 2015.05.20. Created by tynli. */ RT_STATUS Beamforming_GetVHTGIDMgntFrame( IN PADAPTER Adapter, IN PRT_RFD pRfd, IN POCTET_STRING pPduOS ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; RT_STATUS rtStatus = RT_STATUS_SUCCESS; pu1Byte pBuffer = NULL; pu1Byte pRaddr = NULL; u1Byte MemStatus[8] = {0}, UserPos[16] = {0}; u1Byte idx; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMER_ENTRY pBeamformEntry = &pBeamInfo->BeamformerEntry[pBeamInfo->mu_ap_index]; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] On VHT GID mgnt frame!\n", __func__)); /* Check length*/ if (pPduOS->Length < (FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY+16)) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetVHTGIDMgntFrame(): Invalid length (%d)\n", pPduOS->Length)); return RT_STATUS_INVALID_LENGTH; } /* Check RA*/ pRaddr = (pu1Byte)(pPduOS->Octet)+4; if (!eqMacAddr(pRaddr, Adapter->CurrentAddress)) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Beamforming_GetVHTGIDMgntFrame(): Drop because of RA error.\n")); return RT_STATUS_PKT_DROP; } RT_DISP_DATA(FBEAM, FBEAM_DATA, "On VHT GID Mgnt Frame ==>:\n", pPduOS->Octet, pPduOS->Length); /*Parsing Membership Status Array*/ pBuffer = pPduOS->Octet + FRAME_OFFSET_VHT_GID_MGNT_MEMBERSHIP_STATUS_ARRAY; for (idx = 0; idx < 8; idx++) { MemStatus[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(pBuffer+idx); pBeamformEntry->gid_valid[idx] = GET_VHT_GID_MGNT_INFO_MEMBERSHIP_STATUS(pBuffer+idx); } RT_DISP_DATA(FBEAM, FBEAM_DATA, "MemStatus: ", MemStatus, 8); /* Parsing User Position Array*/ pBuffer = pPduOS->Octet + FRAME_OFFSET_VHT_GID_MGNT_USER_POSITION_ARRAY; for (idx = 0; idx < 16; idx++) { UserPos[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(pBuffer+idx); pBeamformEntry->user_position[idx] = GET_VHT_GID_MGNT_INFO_USER_POSITION(pBuffer+idx); } RT_DISP_DATA(FBEAM, FBEAM_DATA, "UserPos: ", UserPos, 16); /* Group ID detail printed*/ { u1Byte i, j; u1Byte tmpVal; u2Byte tmpVal2; for (i = 0; i < 8; i++) { tmpVal = MemStatus[i]; tmpVal2 = ((UserPos[i*2 + 1] << 8) & 0xFF00) + (UserPos[i * 2] & 0xFF); for (j = 0; j < 8; j++) { if ((tmpVal >> j) & BIT0) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("Use Group ID (%d), User Position (%d)\n", (i*8+j), (tmpVal2 >> 2 * j)&0x3)); } } } } /* Indicate GID frame to IHV service. */ { u1Byte Indibuffer[24] = {0}; u1Byte Indioffset = 0; PlatformMoveMemory(Indibuffer + Indioffset, pBeamformEntry->gid_valid, 8); Indioffset += 8; PlatformMoveMemory(Indibuffer + Indioffset, pBeamformEntry->user_position, 16); Indioffset += 16; PlatformIndicateCustomStatus( Adapter, RT_CUSTOM_EVENT_VHT_RECV_GID_MGNT_FRAME, RT_CUSTOM_INDI_TARGET_IHV, Indibuffer, Indioffset); } /* Config HW GID table */ halComTxbf_ConfigGtab(pDM_Odm); return rtStatus; } /* // Description: Construct VHT Group ID (GID) management frame. // // 2015.05.20. Created by tynli. */ VOID ConstructVHTGIDMgntFrame( IN PDM_ODM_T pDM_Odm, IN pu1Byte RA, IN PRT_BEAMFORMEE_ENTRY pBeamformEntry, OUT pu1Byte Buffer, OUT pu4Byte pLength ) { PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PADAPTER Adapter = pBeamInfo->SourceAdapter; OCTET_STRING osFTMFrame, tmp; FillOctetString(osFTMFrame, Buffer, 0); *pLength = 0; ConstructMaFrameHdr( Adapter, RA, ACT_CAT_VHT, ACT_VHT_GROUPID_MANAGEMENT, &osFTMFrame); /* Membership Status Array*/ FillOctetString(tmp, pBeamformEntry->gid_valid, 8); PacketAppendData(&osFTMFrame, tmp); /* User Position Array*/ FillOctetString(tmp, pBeamformEntry->user_position, 16); PacketAppendData(&osFTMFrame, tmp); *pLength = osFTMFrame.Length; RT_DISP_DATA(FBEAM, FBEAM_DATA, "ConstructVHTGIDMgntFrame():\n", Buffer, *pLength); } BOOLEAN SendSWVHTGIDMgntFrame( IN PVOID pDM_VOID, IN pu1Byte RA, IN u1Byte Idx ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte DataRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = &pBeamInfo->BeamformeeEntry[Idx]; PADAPTER Adapter = pBeamInfo->SourceAdapter; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructVHTGIDMgntFrame( pDM_Odm, RA, pBeamformEntry, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength ); pTcb->BWOfPacket = CHANNEL_WIDTH_20; DataRate = MGN_6M; MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, DataRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } /* // Description: Construct VHT beamforming report poll. // // 2015.05.20. Created by tynli. */ VOID ConstructVHTBFReportPoll( IN PDM_ODM_T pDM_Odm, IN pu1Byte RA, OUT pu1Byte Buffer, OUT pu4Byte pLength ) { PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PADAPTER Adapter = pBeamInfo->SourceAdapter; pu1Byte pBFRptPoll = Buffer; /* Frame control*/ SET_80211_HDR_FRAME_CONTROL(pBFRptPoll, 0); SET_80211_HDR_TYPE_AND_SUBTYPE(pBFRptPoll, Type_Beamforming_Report_Poll); /* Duration*/ SET_80211_HDR_DURATION(pBFRptPoll, 100); /* RA*/ SET_VHT_BF_REPORT_POLL_RA(pBFRptPoll, RA); /* TA*/ SET_VHT_BF_REPORT_POLL_TA(pBFRptPoll, Adapter->CurrentAddress); /* Feedback Segment Retransmission Bitmap*/ SET_VHT_BF_REPORT_POLL_FEEDBACK_SEG_RETRAN_BITMAP(pBFRptPoll, 0xFF); *pLength = 17; RT_DISP_DATA(FBEAM, FBEAM_DATA, "ConstructVHTBFReportPoll():\n", Buffer, *pLength); } BOOLEAN SendSWVHTBFReportPoll( IN PVOID pDM_VOID, IN pu1Byte RA, IN BOOLEAN bFinalPoll ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte Idx = 0, DataRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); PADAPTER Adapter = pBeamInfo->SourceAdapter; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start!\n", __func__)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructVHTBFReportPoll( pDM_Odm, RA, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength ); pTcb->bTxEnableSwCalcDur = TRUE; /* need?*/ pTcb->BWOfPacket = CHANNEL_WIDTH_20; if (bFinalPoll) pTcb->TxBFPktType = RT_BF_PKT_TYPE_FINAL_BF_REPORT_POLL; else pTcb->TxBFPktType = RT_BF_PKT_TYPE_BF_REPORT_POLL; DataRate = MGN_6M; /* Legacy OFDM rate*/ MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, DataRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "SendSWVHTBFReportPoll():\n", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } /* // Description: Construct VHT MU NDPA packet. // We should combine this function with ConstructVHTNDPAPacket() in the future. // // 2015.05.21. Created by tynli. */ VOID ConstructVHTMUNDPAPacket( IN PDM_ODM_T pDM_Odm, IN CHANNEL_WIDTH BW, OUT pu1Byte Buffer, OUT pu4Byte pLength ) { PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PADAPTER Adapter = pBeamInfo->SourceAdapter; u2Byte Duration = 0; u1Byte Sequence = 0; pu1Byte pNDPAFrame = Buffer; RT_NDPA_STA_INFO STAInfo; u1Byte idx; u1Byte DestAddr[6] = {0}; PRT_BEAMFORMEE_ENTRY pEntry = NULL; /* Fill the first MU BFee entry (STA1) MAC addr to destination address then HW will change A1 to broadcast addr. 2015.05.28. Suggested by SD1 Chunchu. */ for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) { pEntry = &(pBeamInfo->BeamformeeEntry[idx]); if (pEntry->is_mu_sta) { cpMacAddr(DestAddr, pEntry->MacAddr); break; } } if (pEntry == NULL) return; /* Frame control.*/ SET_80211_HDR_FRAME_CONTROL(pNDPAFrame, 0); SET_80211_HDR_TYPE_AND_SUBTYPE(pNDPAFrame, Type_NDPA); SET_80211_HDR_ADDRESS1(pNDPAFrame, DestAddr); SET_80211_HDR_ADDRESS2(pNDPAFrame, pEntry->MyMacAddr); /*--------------------------------------------*/ /* Need to modify "Duration" to MU consideration. */ Duration = 2*aSifsTime + 44; if (BW == CHANNEL_WIDTH_80) Duration += 40; else if(BW == CHANNEL_WIDTH_40) Duration+= 87; else Duration+= 180; /*--------------------------------------------*/ SET_80211_HDR_DURATION(pNDPAFrame, Duration); Sequence = *(pDM_Odm->pSoundingSeq) << 2; ODM_MoveMemory(pDM_Odm, pNDPAFrame + 16, &Sequence, 1); *pLength = 17; /* Construct STA info. for multiple STAs*/ for (idx = 0; idx < BEAMFORMEE_ENTRY_NUM; idx++) { pEntry = &(pBeamInfo->BeamformeeEntry[idx]); if (pEntry->is_mu_sta) { STAInfo.AID = pEntry->AID; STAInfo.FeedbackType = 1; /* 1'b1: MU*/ STAInfo.NcIndex = 0; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Get BeamformeeEntry idx(%d), AID =%d\n", __func__, idx, pEntry->AID)); ODM_MoveMemory(pDM_Odm, pNDPAFrame+(*pLength), (pu1Byte)&STAInfo, 2); *pLength += 2; } } } BOOLEAN SendSWVHTMUNDPAPacket( IN PVOID pDM_VOID, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PRT_TCB pTcb; PRT_TX_LOCAL_BUFFER pBuf; BOOLEAN ret = TRUE; u1Byte NDPTxRate = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PADAPTER Adapter = pBeamInfo->SourceAdapter; NDPTxRate = MGN_VHT2SS_MCS0; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); if (MgntGetBuffer(Adapter, &pTcb, &pBuf)) { ConstructVHTMUNDPAPacket( pDM_Odm, BW, pBuf->Buffer.VirtualAddress, &pTcb->PacketLength ); pTcb->bTxEnableSwCalcDur = TRUE; pTcb->BWOfPacket = BW; pTcb->TxBFPktType = RT_BF_PKT_TYPE_BROADCAST_NDPA; /*rate of NDP decide by Nr*/ MgntSendPacket(Adapter, pTcb, pBuf, pTcb->PacketLength, NORMAL_QUEUE, NDPTxRate); } else ret = FALSE; PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); if (ret) RT_DISP_DATA(FBEAM, FBEAM_DATA, "", pBuf->Buffer.VirtualAddress, pTcb->PacketLength); return ret; } #endif /*#if (SUPPORT_MU_BF == 1)*/ #endif /*#ifdef SUPPORT_MU_BF*/ #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) u4Byte Beamforming_GetReportFrame( IN PVOID pDM_VOID, union recv_frame *precv_frame ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; u4Byte ret = _SUCCESS; PRT_BEAMFORMEE_ENTRY pBeamformEntry = NULL; pu1Byte pframe = precv_frame->u.hdr.rx_data; u4Byte frame_len = precv_frame->u.hdr.len; pu1Byte TA; u1Byte Idx, offset; /*DBG_871X("beamforming_get_report_frame\n");*/ /*Memory comparison to see if CSI report is the same with previous one*/ TA = GetAddr2Ptr(pframe); pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, TA, &Idx); if(pBeamformEntry->BeamformEntryCap & BEAMFORMER_CAP_VHT_SU) offset = 31; /*24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ else if(pBeamformEntry->BeamformEntryCap & BEAMFORMER_CAP_HT_EXPLICIT) offset = 34; /*24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ else return ret; /*DBG_871X("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);*/ return ret; } BOOLEAN SendFWHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; struct rtw_ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u1Byte ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; u1Byte *pframe; u2Byte *fctrl; u2Byte duration = 0; u1Byte aSifsTime = 0, NDPTxRate = 0, Idx = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { DBG_871X("%s, alloc mgnt frame fail\n", __func__); return _FALSE; } //update attribute pattrib = &pmgntframe->attrib; update_mgntframe_attrib(Adapter, pattrib); pattrib->qsel = QSLT_BEACON; NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); pattrib->rate = NDPTxRate; pattrib->bwmode = BW; pattrib->order = 1; pattrib->subtype = WIFI_ACTION_NOACK; _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr*)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; SetOrderBit(pframe); SetFrameSubType(pframe, WIFI_ACTION_NOACK); _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); if( pmlmeext->cur_wireless_mode == WIRELESS_11B) aSifsTime = 10; else aSifsTime = 16; duration = 2*aSifsTime + 40; if(BW == CHANNEL_WIDTH_40) duration+= 87; else duration+= 180; SetDuration(pframe, duration); //HT control field SET_HT_CTRL_CSI_STEERING(pframe+24, 3); SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1); _rtw_memcpy(pframe+28, ActionHdr, 4); pattrib->pktlen = 32; pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe(Adapter, pmgntframe); return _TRUE; } BOOLEAN SendSWHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; struct rtw_ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u1Byte ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; pu1Byte pframe; pu2Byte fctrl; u2Byte duration = 0; u1Byte aSifsTime = 0, NDPTxRate = 0, Idx = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); NDPTxRate = Beamforming_GetHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { DBG_871X("%s, alloc mgnt frame fail\n", __func__); return _FALSE; } /*update attribute*/ pattrib = &pmgntframe->attrib; update_mgntframe_attrib(Adapter, pattrib); pattrib->qsel = QSLT_MGNT; pattrib->rate = NDPTxRate; pattrib->bwmode = BW; pattrib->order = 1; pattrib->subtype = WIFI_ACTION_NOACK; _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; SetOrderBit(pframe); SetFrameSubType(pframe, WIFI_ACTION_NOACK); _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); if (pmlmeext->cur_wireless_mode == WIRELESS_11B) aSifsTime = 10; else aSifsTime = 16; duration = 2*aSifsTime + 40; if (BW == CHANNEL_WIDTH_40) duration += 87; else duration += 180; SetDuration(pframe, duration); /*HT control field*/ SET_HT_CTRL_CSI_STEERING(pframe+24, 3); SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe+24, 1); _rtw_memcpy(pframe+28, ActionHdr, 4); pattrib->pktlen = 32; pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe(Adapter, pmgntframe); return _TRUE; } BOOLEAN SendFWVHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; struct rtw_ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); pu1Byte pframe; pu2Byte fctrl; u2Byte duration = 0; u1Byte sequence = 0, aSifsTime = 0, NDPTxRate= 0, Idx = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); RT_NDPA_STA_INFO sta_info; pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { DBG_871X("%s, alloc mgnt frame fail\n", __func__); return _FALSE; } //update attribute pattrib = &pmgntframe->attrib; _rtw_memcpy(pattrib->ra, RA, ETH_ALEN); update_mgntframe_attrib(Adapter, pattrib); pattrib->qsel = QSLT_BEACON; NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); pattrib->rate = NDPTxRate; pattrib->bwmode = BW; pattrib->subtype = WIFI_NDPA; _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr*)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; SetFrameSubType(pframe, WIFI_NDPA); _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN); if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode)) aSifsTime = 16; else aSifsTime = 10; duration = 2*aSifsTime + 44; if(BW == CHANNEL_WIDTH_80) duration += 40; else if(BW == CHANNEL_WIDTH_40) duration+= 87; else duration+= 180; SetDuration(pframe, duration); sequence = pBeamInfo->SoundingSequence<< 2; if (pBeamInfo->SoundingSequence >= 0x3f) pBeamInfo->SoundingSequence = 0; else pBeamInfo->SoundingSequence++; _rtw_memcpy(pframe+16, &sequence,1); if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) AID = 0; sta_info.AID = AID; sta_info.FeedbackType = 0; sta_info.NcIndex= 0; _rtw_memcpy(pframe+17, (u8 *)&sta_info, 2); pattrib->pktlen = 19; pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe(Adapter, pmgntframe); return _TRUE; } BOOLEAN SendSWVHTNDPAPacket( IN PVOID pDM_VOID, IN pu1Byte RA, IN u2Byte AID, IN CHANNEL_WIDTH BW ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; struct rtw_ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); RT_NDPA_STA_INFO ndpa_sta_info; u1Byte NDPTxRate = 0, sequence = 0, aSifsTime = 0, Idx = 0; pu1Byte pframe; pu2Byte fctrl; u2Byte duration = 0; PRT_BEAMFORMING_INFO pBeamInfo = &(pDM_Odm->BeamformingInfo); PRT_BEAMFORMEE_ENTRY pBeamformEntry = phydm_Beamforming_GetBFeeEntryByAddr(pDM_Odm, RA, &Idx); NDPTxRate = Beamforming_GetVHTNDPTxRate(pDM_Odm, pBeamformEntry->CompSteeringNumofBFer); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] NDPTxRate =%d\n", __func__, NDPTxRate)); pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { DBG_871X("%s, alloc mgnt frame fail\n", __func__); return _FALSE; } /*update attribute*/ pattrib = &pmgntframe->attrib; _rtw_memcpy(pattrib->ra, RA, ETH_ALEN); update_mgntframe_attrib(Adapter, pattrib); pattrib->qsel = QSLT_MGNT; pattrib->rate = NDPTxRate; pattrib->bwmode = BW; pattrib->subtype = WIFI_NDPA; _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; fctrl = &pwlanhdr->frame_ctl; *(fctrl) = 0; SetFrameSubType(pframe, WIFI_NDPA); _rtw_memcpy(pwlanhdr->addr1, RA, ETH_ALEN); _rtw_memcpy(pwlanhdr->addr2, pBeamformEntry->MyMacAddr, ETH_ALEN); if (IsSupported5G(pmlmeext->cur_wireless_mode) || IsSupportedHT(pmlmeext->cur_wireless_mode)) aSifsTime = 16; else aSifsTime = 10; duration = 2*aSifsTime + 44; if (BW == CHANNEL_WIDTH_80) duration += 40; else if (BW == CHANNEL_WIDTH_40) duration += 87; else duration += 180; SetDuration(pframe, duration); sequence = pBeamInfo->SoundingSequence << 2; if (pBeamInfo->SoundingSequence >= 0x3f) pBeamInfo->SoundingSequence = 0; else pBeamInfo->SoundingSequence++; _rtw_memcpy(pframe+16, &sequence, 1); if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) AID = 0; ndpa_sta_info.AID = AID; ndpa_sta_info.FeedbackType = 0; ndpa_sta_info.NcIndex = 0; _rtw_memcpy(pframe+17, (u8 *)&ndpa_sta_info, 2); pattrib->pktlen = 19; pattrib->last_txcmdsz = pattrib->pktlen; dump_mgntframe(Adapter, pmgntframe); ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] [%d]\n", __func__, __LINE__)); return _TRUE; } #endif VOID Beamforming_GetNDPAFrame( IN PVOID pDM_VOID, #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) IN OCTET_STRING pduOS #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) union recv_frame *precv_frame #endif ) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; PADAPTER Adapter = pDM_Odm->Adapter; pu1Byte TA ; u1Byte Idx, Sequence; #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) pu1Byte pNDPAFrame = pduOS.Octet; #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) pu1Byte pNDPAFrame = precv_frame->u.hdr.rx_data; #endif PRT_BEAMFORMER_ENTRY pBeamformerEntry = NULL; /*Modified By Jeffery @2014-10-29*/ #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) RT_DISP_DATA(FBEAM, FBEAM_DATA, "Beamforming_GetNDPAFrame\n", pduOS.Octet, pduOS.Length); if (IsCtrlNDPA(pNDPAFrame) == FALSE) #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) if (GetFrameSubType(pNDPAFrame) != WIFI_NDPA) #endif return; else if (!(pDM_Odm->SupportICType & (ODM_RTL8812 | ODM_RTL8821))) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] not 8812 or 8821A, return\n", __func__)); return; } #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) TA = Frame_Addr2(pduOS); #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) TA = GetAddr2Ptr(pNDPAFrame); #endif /*Remove signaling TA. */ TA[0] = TA[0] & 0xFE; pBeamformerEntry = phydm_Beamforming_GetBFerEntryByAddr(pDM_Odm, TA, &Idx); // Modified By Jeffery @2014-10-29 /*Break options for Clock Reset*/ if (pBeamformerEntry == NULL) return; else if (!(pBeamformerEntry->BeamformEntryCap & BEAMFORMEE_CAP_VHT_SU)) return; /*LogSuccess: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/ /*ClockResetTimes: While BFer entry always doesn't receive our CSI, clock will reset again and again.So ClockResetTimes is limited to 5 times.2015-04-13, Jeffery*/ else if ((pBeamformerEntry->LogSuccess == 1) || (pBeamformerEntry->ClockResetTimes == 5)) { ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, LogSuccess=%d, ClockResetTimes=%d, clock reset is no longer needed.\n", __func__, pBeamformerEntry->LogSeq, pBeamformerEntry->PreLogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->LogSuccess, pBeamformerEntry->ClockResetTimes)); return; } Sequence = (pNDPAFrame[16]) >> 2; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Start, Sequence=%d, LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, ClockResetTimes=%d, LogSuccess=%d\n", __func__, Sequence, pBeamformerEntry->LogSeq, pBeamformerEntry->PreLogSeq, pBeamformerEntry->LogRetryCnt, pBeamformerEntry->ClockResetTimes, pBeamformerEntry->LogSuccess)); if ((pBeamformerEntry->LogSeq != 0) && (pBeamformerEntry->PreLogSeq != 0)) { /*Success condition*/ if ((pBeamformerEntry->LogSeq != Sequence) && (pBeamformerEntry->PreLogSeq != pBeamformerEntry->LogSeq)) { /* break option for clcok reset, 2015-03-30, Jeffery */ pBeamformerEntry->LogRetryCnt = 0; /*As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/ /*That is, LogSuccess is NOT needed to be reset to zero, 2015-04-13, Jeffery*/ pBeamformerEntry->LogSuccess = 1; } else {/*Fail condition*/ if (pBeamformerEntry->LogRetryCnt == 5) { pBeamformerEntry->ClockResetTimes++; pBeamformerEntry->LogRetryCnt = 0; ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_TXBF, ODM_DBG_LOUD, ("[%s] Clock Reset!!! ClockResetTimes=%d\n", __func__, pBeamformerEntry->ClockResetTimes)); HalComTxbf_Set(pDM_Odm, TXBF_SET_SOUNDING_CLK, NULL); } else pBeamformerEntry->LogRetryCnt++; } } /*Update LogSeq & PreLogSeq*/ pBeamformerEntry->PreLogSeq = pBeamformerEntry->LogSeq; pBeamformerEntry->LogSeq = Sequence; } #endif