--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacDot11Associated.cpp Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,2725 @@
+/*
+* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation of the WlanDot11Associated class
+*
+*/
+
+/*
+* %version: 95 %
+*/
+
+#include "config.h"
+#include "UmacDot11Associated.h"
+#include "UmacContextImpl.h"
+#include "UmacWsaWriteMib.h"
+#include "umacinternaldefinitions.h"
+
+/**
+* Mask to determine the used encryption from WHA::ReceivePacket's aFlags
+* parameter
+*/
+const TUint32 KReceivePacketEncryptionMask = 0x00038000;
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnBeaconFrameRx(
+ WlanContextImpl& aCtxImpl,
+ const TAny* /*aFrame*/,
+ const TUint32 /*aLength*/,
+ WHA::TRcpi /*aRcpi*/,
+ TUint8* aBuffer )
+ {
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnProbeResponseFrameRx(
+ WlanContextImpl& aCtxImpl,
+ const TAny* /*aFrame*/,
+ const TUint32 /*aLength*/,
+ WHA::TRcpi /*aRcpi*/,
+ TUint8* aBuffer )
+ {
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnDeauthenticateFrameRx(
+ WlanContextImpl& aCtxImpl,
+ TUint8* aBuffer )
+ {
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnDisassociateFrameRx(
+ WlanContextImpl& aCtxImpl,
+ TUint8* aBuffer )
+ {
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TSnapStatus WlanDot11Associated::ValiDateSnapHeader(
+ WlanContextImpl& aCtxImpl,
+ const TUint8* aStartOfSnap ) const
+ {
+ TSnapStatus snapStatus( ESnapUnknown );
+
+ if ( !os_memcmp(
+ aStartOfSnap,
+ &KEncapsulatingRfc1042SnapHeader,
+ sizeof( KEncapsulatingRfc1042SnapHeader ) ) )
+ {
+ snapStatus = ESnapDot11Ok;
+ }
+ else if ( !os_memcmp(
+ aStartOfSnap,
+ &KEncapsulating802_1hSnapHeader,
+ sizeof( KEncapsulating802_1hSnapHeader ) ) )
+ {
+ snapStatus = ESnapDot11Ok;
+ }
+ else
+ {
+ // unknown SNAP. Status already correct. No action needed
+ }
+
+ if ( snapStatus == ESnapUnknown &&
+ aCtxImpl.NetworkOperationMode() == WHA::EBSS &&
+ aCtxImpl.GetProprietarySnapHeader() != KUndefinedSnapHeader )
+ {
+ // SNAP still unknown, but we a are in a infrastructure network and
+ // a proprietary SNAP header has been defined.
+ // Check if the SNAP is this proprietary SNAP header
+
+ if ( !os_memcmp(
+ aStartOfSnap,
+ &(aCtxImpl.GetProprietarySnapHeader()),
+ sizeof( aCtxImpl.GetProprietarySnapHeader() ) ) )
+ {
+ snapStatus = ESnapProprietaryOk;
+ }
+ }
+
+ return snapStatus;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline TBool WlanDot11Associated::RxDataMpduValid(
+ const TUint32 aLength,
+ const SDataFrameHeader& aFrameHeader,
+ TBool aQosData,
+ TBool aAmsdu,
+ TUint aHtControlLen,
+ TUint aSecurityHeaderLen,
+ TUint aSecurityTrailerLen ) const
+ {
+ //========================================================================
+ // validate frame length
+ //========================================================================
+
+ const TUint KMinAcceptableRxDataMpduLen (
+ MinAcceptableRxDataMpduLen(
+ aQosData,
+ aAmsdu,
+ aHtControlLen,
+ aSecurityHeaderLen,
+ aSecurityTrailerLen ) );
+
+ if ( aLength < KMinAcceptableRxDataMpduLen )
+ {
+ // frame shorter than min acceptable length; reject it
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::RxDataMpduValid: WARNING: MPDU rejected because its shorter than min acceptable length of %d"),
+ KMinAcceptableRxDataMpduLen );
+
+ return EFalse;
+ }
+
+ //========================================================================
+ // validate To DS & From DS bits
+ //========================================================================
+
+ if ( !DoIsValidAddressBitCombination( aFrameHeader ) )
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::RxDataMpduValid: MPDU rejected because of invalid To DS and/or From DS bit values") );
+
+ return EFalse;
+ }
+
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// defines the minimum acceptable Data MPDU length as:
+// dot11 MAC header length including SNAP and possibly existing HT Control
+// field
+// + security header length
+// + subframe header length if the QoS Data MPDU contains an A-MSDU
+// + security trailer length
+// + Ethernet type field length
+// ---------------------------------------------------------------------------
+//
+inline TUint WlanDot11Associated::MinAcceptableRxDataMpduLen(
+ TBool aQosData,
+ TBool aAmsdu,
+ TUint aHtControlLen,
+ TUint aSecurityHeaderLen,
+ TUint aSecurityTrailerLen ) const
+ {
+ return aQosData ?
+ sizeof( SQosDataMpduHeader ) + aHtControlLen
+ + aSecurityHeaderLen
+ + ( aAmsdu ? sizeof( SAmsduSubframeHeader ) : 0 )
+ + aSecurityTrailerLen
+ + sizeof( SEthernetType )
+ :
+ sizeof( SDataMpduHeader )
+ + aSecurityHeaderLen
+ + aSecurityTrailerLen
+ + sizeof( SEthernetType );
+ }
+
+// ---------------------------------------------------------------------------
+// Note that address 1 is the DA (Destination Address) both in infrastructure
+// and IBSS network Rx frames
+// ---------------------------------------------------------------------------
+//
+inline TDaType WlanDot11Associated::RxFrameDaType(
+ const SDataFrameHeader& aFrameHeader ) const
+ {
+ if ( IsGroupBitSet( aFrameHeader.iAddress1 ) )
+ {
+ // a multicast
+ if ( aFrameHeader.iAddress1 == KBroadcastMacAddr )
+ {
+ // also a brodcast
+ return EBroadcastAddress;
+ }
+ else
+ {
+ // a multicast but not a broadcast
+ return EMulticastAddress;
+ }
+ }
+ else
+ {
+ // a unicast
+ return EUnicastAddress;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline TBool WlanDot11Associated::RxMsduValid(
+ WlanContextImpl& aCtxImpl,
+ const SDataFrameHeader& aFrameHeader,
+ const SAmsduSubframeHeader* aSubFrameHeader,
+ const TUint8* aStartOfSnap,
+ TUint16 aEtherType,
+ TBool aMulticast,
+ TUint32 aFlags,
+ TSnapStatus& aSnapStatus ) const
+ {
+ //========================================================================
+ // validate SNAP header
+ //========================================================================
+
+ aSnapStatus = ValiDateSnapHeader( aCtxImpl, aStartOfSnap );
+
+ if ( aSnapStatus == ESnapUnknown )
+ {
+ // SNAP header is invalid
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::RxMsduValid: MSDU rejected because of invalid snap:"),
+ aStartOfSnap, aStartOfSnap + sizeof( SSnapHeader ) );
+
+ return EFalse;
+ }
+
+ // determine if SA is our MAC address
+ const TBool KSaIsOurMac (
+ DoIsRxFrameSAourAddress( aCtxImpl, aFrameHeader, aSubFrameHeader ) );
+
+ //========================================================================
+ // if this is a proprietary test MSDU but not sent by us, its not valid
+ // for us
+ //========================================================================
+
+ if ( aEtherType == KBounceType && !KSaIsOurMac )
+ {
+#ifndef NDEBUG
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::RxMsduValid: proprietary test MSDU, but not sent by us. MSDU rejected") );
+
+ if ( aSubFrameHeader )
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Subframe DA:"), aSubFrameHeader->iDa );
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Subframe SA:"), aSubFrameHeader->iSa );
+ }
+ else
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address1:"), aFrameHeader.iAddress1);
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address2:"), aFrameHeader.iAddress2);
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address3:"), aFrameHeader.iAddress3);
+ }
+#endif
+
+ return EFalse;
+ }
+
+ //========================================================================
+ // non-test multicast MSDUs sent by us are not relevant for us
+ //========================================================================
+
+ if ( // SA is our MAC address
+ KSaIsOurMac
+ // AND this is a multicast frame
+ && aMulticast
+ // AND this is not a test frame
+ && aEtherType != KBounceType )
+ {
+ // we have received a non-test multicast frame that was sent by us.
+ // Ignore it.
+
+#ifndef NDEBUG
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::RxMsduValid: MSDU rejected because its a non-test multicast MSDU sent by us"));
+
+ if ( aSubFrameHeader )
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Subframe DA:"), aSubFrameHeader->iDa );
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Subframe SA:"), aSubFrameHeader->iSa );
+ }
+ else
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address1:"), aFrameHeader.iAddress1);
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address2:"), aFrameHeader.iAddress2);
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: Address3:"), aFrameHeader.iAddress3);
+ }
+#endif
+
+ return EFalse;
+ }
+
+ // determine the encryption of the frame
+ const TUint32 KEncryption ( aFlags & KReceivePacketEncryptionMask );
+
+ if ( aSnapStatus != ESnapProprietaryOk )
+ {
+ //====================================================================
+ // validate MSDU with the applicable privacy mode filter
+ //====================================================================
+ if ( !aCtxImpl.ExecuteActivePrivacyModeFilter(
+ aFrameHeader,
+ aCtxImpl.iEnableUserData,
+ aEtherType,
+ aCtxImpl.PairWiseKeyType() != WHA::EKeyNone,
+ ( KEncryption == WHA::KEncryptAes ||
+ KEncryption == WHA::KEncryptTkip ||
+ KEncryption == WHA::KEncryptWapi ) ) )
+ {
+ return EFalse;
+ }
+ }
+
+ // this MSDU has passed all our checks, so it is valid for us
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline TUint WlanDot11Associated::RxMsduEthernetPayloadLength(
+ const TUint32 aMpduLength,
+ TUint aSubframeLength,
+ TBool aQosData,
+ TUint aHtControlLen,
+ TUint aSecurityHeaderLen,
+ TUint aSecurityTrailerLen ) const
+ {
+ TUint length ( 0 );
+
+ if ( aSubframeLength )
+ {
+ // this ethernet payload is carried in an A-MSDU subframe
+
+ length = aSubframeLength - sizeof( SSnapHeader );
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: subframe eth payload len: %d"),
+ length );
+ }
+ else
+ {
+ // this ethernet payload is carried in a non-A-MSDU frame
+
+ if ( aQosData )
+ {
+ length =
+ // total length of the Rx frame
+ aMpduLength
+ // - MAC header length including SNAP
+ - ( sizeof( SQosDataMpduHeader ) + aHtControlLen )
+ // - security header length
+ - aSecurityHeaderLen
+ // - security trailer length
+ - aSecurityTrailerLen;
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: qos data eth payload len: %d"),
+ length );
+ }
+ else
+ {
+ length =
+ // total length of the Rx frame
+ aMpduLength
+ // MAC header length including SNAP
+ - sizeof( SDataMpduHeader )
+ // - security header length
+ - aSecurityHeaderLen
+ // - security trailer length
+ - aSecurityTrailerLen;
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: non-qos data eth payload len: %d"),
+ length );
+ }
+ }
+
+ return length;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline TUint8* WlanDot11Associated::NewBufForMgmtClientRxFrame(
+ WlanContextImpl& aCtxImpl,
+ TBool aProprieatarySnapFrame,
+ TBool aQosFrame,
+ TUint aHtControlLen,
+ TUint aEtherPayloadLength ) const
+ {
+ TUint requiredLength ( 0 );
+
+ if ( aProprieatarySnapFrame )
+ {
+ // forwarded as a Data MPDU
+
+ requiredLength = aQosFrame ?
+ sizeof( SQosDataFrameHeader )
+ + aHtControlLen
+ + aEtherPayloadLength :
+ sizeof( SDataFrameHeader )
+ + aEtherPayloadLength;
+ }
+ else
+ {
+ // forwarded as Ethernet frame
+
+ requiredLength = 2 * sizeof( TMacAddress ) + aEtherPayloadLength;
+ }
+
+ // request for a new Rx buffer
+ return aCtxImpl.GetRxBuffer(
+ requiredLength,
+ // tell that this is an internally triggered buffer request
+ ETrue );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline TBool WlanDot11Associated::RxMsduForUser(
+ TUint16 aEtherType,
+ TSnapStatus aSnapstatus ) const
+ {
+ if ( // not an EAPOL frame AND
+ aEtherType != KEapolType &&
+ // not a WAI frame AND
+ aEtherType != KWaiType &&
+ // not a WLAN Mgmt Client test frame
+ aEtherType != KBounceType &&
+ // not a proprietary SNAP frame
+ aSnapstatus != ESnapProprietaryOk )
+ {
+ // a user data / protocol stack data frame
+
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+inline void WlanDot11Associated::UpdateDataFrameRxStatistics(
+ WlanContextImpl& aCtxImpl,
+ TUint16 aEtherType,
+ TBool aMulticast,
+ WHA::TQueueId aAccessCategory ) const
+ {
+ if ( aEtherType != KBounceType )
+ {
+ // other than WLAN Mgmt Client test data frame received
+
+ if ( aMulticast )
+ {
+ // multicast frame
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: inc rx mcast cnt for AC: %d"),
+ aAccessCategory );
+
+ // update frame statistics
+ aCtxImpl.IncrementRxMulticastDataFrameCount( aAccessCategory );
+ }
+ else
+ {
+ // unicast frame
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: inc rx unicast cnt for AC: %d"),
+ aAccessCategory );
+
+ // update frame statistics
+ aCtxImpl.IncrementRxUnicastDataFrameCount( aAccessCategory );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnDataFrameRx(
+ WlanContextImpl& aCtxImpl,
+ const TAny* aFrame,
+ const TUint32 aLength,
+ TUint32 aFlags,
+ WHA::TRcpi aRcpi,
+ TUint8* aBuffer )
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::OnDataFrameRx") );
+
+ SDataMpduHeader* hdr
+ = reinterpret_cast<SDataMpduHeader*>(const_cast<TAny*>(aFrame));
+ SQosDataMpduHeader* qoshdr
+ = reinterpret_cast<SQosDataMpduHeader*>(const_cast<TAny*>(aFrame));
+
+ // determine the length of the security header (e.g. IV etc.) ...
+ const TUint KSecurityHeaderLen( DecryptHdrOffset( aCtxImpl, aFlags ) );
+
+ OsTracePrint( KRxFrame, (TUint8*)("UMAC: KSecurityHeaderLen: %d"),
+ KSecurityHeaderLen );
+
+ // ... and the security trailer (e.g. MIC etc.)
+ const TUint KSecurityTrailerLen( DecryptTrailerOffset( aCtxImpl, aFlags ) );
+
+ OsTracePrint( KRxFrame, (TUint8*)("UMAC: KSecurityTrailerLen: %d"),
+ KSecurityTrailerLen );
+
+ // as the MAC header of a QoS data MPDU has an additional field
+ // we need to take that into account; so make a note if we indeed have
+ // received a QoS data MPDU
+ const TBool KQosData =
+ ( hdr->iHdr.iFrameControl.iType == E802Dot11FrameTypeQosData ) ?
+ ETrue : EFalse;
+
+ // the MAC header of HT QoS data MPDU also has an additional field,
+ // so determine if that field is present and hence has a non-zero length
+ const TUint KHtControlLen (
+ KQosData && HtcFieldPresent( aCtxImpl, aFrame, aFlags ) ?
+ KHtControlFieldLength : 0 );
+
+ // determine if the MPDU contains an A-MSDU
+ const TBool KAmsdu (
+ KQosData && qoshdr->iHdr.AmsduPresent() ? ETrue : EFalse );
+
+ if ( !RxDataMpduValid(
+ aLength,
+ hdr->iHdr,
+ KQosData,
+ KAmsdu,
+ KHtControlLen,
+ KSecurityHeaderLen,
+ KSecurityTrailerLen ) )
+ {
+ // the overall MAC MPDU (disregarding the included MSDU(s) at this
+ // point) is not valid for us. Release the Rx buffer & abort
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ return;
+ }
+
+ TUint8* framePtr ( 0 );
+ WHA::TQueueId accessCategory( WHA::ELegacy );
+
+ // User Priority is regarded as Best Effort (i.e. Legacy, i.e. zero) unless
+ // the received MPDU is a QoS Data MPDU & a different priority is
+ // specified in its MAC header
+ TUint8 userPriority( 0 );
+
+ if ( KQosData )
+ {
+ // a QoS Data MPDU
+
+ // move framePtr past the MAC header
+ framePtr = reinterpret_cast<TUint8 *>(
+ reinterpret_cast<SQosDataFrameHeader *>( hdr ) + 1 )
+ + KHtControlLen;
+
+ // get the User Priority
+ userPriority = qoshdr->iHdr.UserPriority();
+
+ // make a note of the Access Category corresponding to the
+ // user priority of the MPDU (note that there's a one to one
+ // mapping between Queue id and Access Category)
+ accessCategory = Queue( userPriority );
+ }
+ else
+ {
+ // move framePtr past the MAC header
+ framePtr = reinterpret_cast<TUint8 *>(
+ reinterpret_cast<SDataFrameHeader *>( hdr ) + 1 );
+ }
+
+ // move after possibly existing security header and possibly existing
+ // A-MSDU subframe header, i.e. beginning of SNAP header
+ framePtr += KAmsdu ?
+ KSecurityHeaderLen + sizeof( SAmsduSubframeHeader ) :
+ KSecurityHeaderLen;
+ TUint8* snapLocation ( framePtr );
+
+ // determine the DA type
+ const TDaType KDaType ( RxFrameDaType( hdr->iHdr ) );
+
+ TSnapStatus snapstatus( ESnapUnknown );
+ TDataBuffer* latestValidPacketForUsr ( NULL );
+ TUint nbrOfpacketsForUsr ( 0 );
+ TUint nbrOfpacketsForMgmtClient ( 0 );
+ const TUint KMaxNbrOfPacketsForUsr ( 30 );
+ const TUint KMaxNbrOfPacketsForMgmtClient ( 10 );
+ const TDataBuffer* packetsForUsr[KMaxNbrOfPacketsForUsr];
+ const TDataBuffer* packetsForMgmtClient[KMaxNbrOfPacketsForMgmtClient];
+ // one byte past the last actual payload byte (so excluding the potentially
+ // present security trailer) of the MPDU
+ const TUint8* const KMpduPayloadEnd (
+ reinterpret_cast<const TUint8*>(aFrame)
+ + aLength
+ - KSecurityTrailerLen );
+ TPowerMgmtModeChange powerMgmtModeChange ( ENoChange );
+
+ // handle every MSDU contained in this MPDU. If this is not an A-MSDU
+ // there's only a single MSDU in it.
+ do
+ {
+ TUint8* rxBuffer ( aBuffer );
+
+ // move after SNAP header to Ethernet type field
+ framePtr += sizeof( SSnapHeader );
+ const SEthernetType* const KEtherTypeLocation
+ = reinterpret_cast<const SEthernetType*>( framePtr );
+
+ // determine Ethernet type
+ const TUint16 KEtherType = KEtherTypeLocation->Type();
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: ether type: 0x%04x"),
+ KEtherType );
+
+ // pointer to subframe heaader; or NULL if the MPDU doesn't contain
+ // an A-MSDU
+ const SAmsduSubframeHeader* KSubframeHdr ( KAmsdu ?
+ ( reinterpret_cast<const SAmsduSubframeHeader*>(
+ snapLocation) - 1 ) :
+ NULL );
+
+ // determine if this is a multicast MSDU
+ TBool KMulticastMsdu ( EFalse );
+ if ( KSubframeHdr )
+ {
+ KMulticastMsdu = IsGroupBitSet( KSubframeHdr->iDa );
+ }
+ else
+ {
+ KMulticastMsdu = ( KDaType == EUnicastAddress ? EFalse : ETrue );
+ }
+
+ // determine subframe length, which can be non-zero only if the MPDU
+ // contains an A-MSDU
+ const TUint KSubframeLen ( KSubframeHdr ? KSubframeHdr->Length() : 0 );
+
+ if ( !RxMsduValid(
+ aCtxImpl,
+ hdr->iHdr,
+ KSubframeHdr,
+ snapLocation,
+ KEtherType,
+ KMulticastMsdu,
+ aFlags,
+ snapstatus ) )
+ {
+ // this MSDU is not valid/relevant for us
+
+ if ( KAmsdu )
+ {
+ // move pointer to the SNAP of the possibly existing next
+ // subframe
+ snapLocation +=
+ Align4( sizeof( SAmsduSubframeHeader ) + KSubframeLen );
+ // update frame pointer accordingly
+ framePtr = snapLocation;
+
+ continue;
+ }
+ else
+ {
+ // this MPDU doesn't contain an A-MSDU, so there cannot be
+ // more than a single MSDU in it
+ break;
+ }
+ }
+
+ // determine if this MSDU is for user / protocol stack
+ const TBool KMsduForUser ( RxMsduForUser( KEtherType, snapstatus) );
+
+ if ( KMsduForUser && !aCtxImpl.iUmac.ProtocolStackSideClientReady() )
+ {
+ // this MSDU should be forwarded up the protocol stack but the
+ // protocol stack client is not ready. So we need to skip at
+ // least this MSDU.
+ // Move pointer to the SNAP of the possibly existing next subframe
+ snapLocation +=
+ Align4( sizeof( SAmsduSubframeHeader ) + KSubframeLen );
+ // update frame pointer accordingly
+ framePtr = snapLocation;
+
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WARNING: protocol stack client not ready; MSDU ignored") );
+
+ continue;
+ }
+
+ TDataBuffer* metaHdr ( aCtxImpl.GetRxFrameMetaHeader() );
+ if ( !metaHdr )
+ {
+ // no memory available for Rx frame meta header. This means that
+ // we are not able to forward to higher layers the current MSDU or
+ // any MSDU(s) that possibly follow it in this same MPDU
+
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WARNING: no memory for Rx frame meta hdr; MSDU ignored") );
+ break;
+ }
+
+ const TUint KEtherPayloadLen( RxMsduEthernetPayloadLength(
+ aLength,
+ KSubframeLen,
+ KQosData,
+ KHtControlLen,
+ KSecurityHeaderLen,
+ KSecurityTrailerLen ) );
+
+ if ( !KMsduForUser && KAmsdu )
+ {
+ // an MSDU for WLAN Mgmt Client which is also a part of an
+ // A-MSDU. In this case we need to allocate a new buffer for
+ // this packet and copy it there. This is necessary as an
+ // A-MSDU may contain MSDUs both for the protocol stack side
+ // and for WLAN Mgmt Client. Either one of those clients may
+ // complete the handling of its MSDUs first at which point the
+ // Rx buffer(s) for its MSDU(s) is freed. So we need to make
+ // sure that a buffer is not freed while a client is still
+ // handling MSDU(s) contained in it. We do this by always
+ // copying WLAN Mgmt client MSDU(s) part of an A-MSDU to
+ // new buffers.
+
+ rxBuffer = NewBufForMgmtClientRxFrame(
+ aCtxImpl,
+ snapstatus == ESnapProprietaryOk,
+ KQosData,
+ KHtControlLen,
+ snapstatus == ESnapProprietaryOk ?
+ KSubframeLen : KEtherPayloadLen );
+
+ if ( !rxBuffer )
+ {
+ // allocation failed so we need to skip at least this MSDU.
+
+ // Move pointer to the SNAP of the possibly existing next
+ // subframe
+ snapLocation +=
+ Align4( sizeof( SAmsduSubframeHeader ) + KSubframeLen ); // update frame pointer accordingly
+ // update frame pointer accordingly
+ framePtr = snapLocation;
+
+ // also release the meta hdr which was planned to be used for
+ // this MSDU
+ aCtxImpl.FreeRxFrameMetaHeader( metaHdr );
+
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WARNING: new buf alloc for mgmt client frame failed; MSDU ignored") );
+ continue;
+ }
+ }
+
+ // set the offset to the beginning of the Rx buffer from the beginning
+ // of the meta header. Note that this may be also negative
+ metaHdr->KeSetBufferOffset(
+ rxBuffer
+ - reinterpret_cast<TUint8*>(metaHdr) );
+
+ if ( snapstatus == ESnapProprietaryOk )
+ {
+ HandleProprietarySnapRxFrame(
+ *metaHdr,
+ KQosData,
+ aFrame,
+ KSubframeHdr,
+ aLength,
+ KSecurityHeaderLen,
+ KSecurityTrailerLen,
+ KHtControlLen,
+ KAmsdu ? rxBuffer : NULL );
+ }
+ else
+ {
+ DoBuildEthernetFrame(
+ *metaHdr,
+ *hdr,
+ // start of ethernet payload (includes ether type field)
+ reinterpret_cast<const TUint8*>(KEtherTypeLocation),
+ // length of ethernet payload
+ KEtherPayloadLen,
+ KAmsdu,
+ !KMsduForUser && KAmsdu ? rxBuffer : NULL );
+ }
+
+ // set the frame's User Priority to the Rx buffer being passed
+ // to the client
+ metaHdr->SetUserPriority( userPriority );
+ // set the RCPI
+ metaHdr->KeSetRcpi( aRcpi );
+
+ if ( KEtherType == KBounceType )
+ {
+ metaHdr->FrameType(
+ TDataBuffer::KEthernetTestFrame );
+ }
+
+ if ( KMsduForUser )
+ {
+ // a user data / protocol stack data frame
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: data frame rx"));
+
+ packetsForUsr[nbrOfpacketsForUsr++] = metaHdr;
+ latestValidPacketForUsr = metaHdr;
+ if ( KAmsdu )
+ {
+ metaHdr->KeSetFlags( TDataBuffer::KDontReleaseBuffer );
+ }
+ }
+ else
+ {
+ // a WLAN Mgmt Client data frame
+
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: mgmt client frame rx"));
+
+ packetsForMgmtClient[nbrOfpacketsForMgmtClient++] = metaHdr;
+ }
+
+ // move pointer to the SNAP of the possibly existing next subframe
+ snapLocation += Align4( sizeof( SAmsduSubframeHeader ) + KSubframeLen );
+ // update frame pointer accordingly
+ framePtr = snapLocation;
+
+ UpdateDataFrameRxStatistics(
+ aCtxImpl,
+ KEtherType,
+ KMulticastMsdu,
+ accessCategory );
+
+ // inform dynamic power mode mgr about Rx data frame acceptance
+ if ( // if this is not our test frame AND
+ KEtherType != KBounceType &&
+ // need to change power mgmt mode hasn't already been detected
+ // based on this received (A-)MSDU
+ powerMgmtModeChange == ENoChange )
+ {
+ powerMgmtModeChange = aCtxImpl.OnFrameRx(
+ accessCategory,
+ KEtherType,
+ KEtherPayloadLen,
+ KDaType );
+ }
+
+ // inform Null Send Controller about data frame Rx
+ aCtxImpl.OnDataRxCompleted(
+ ( KEtherType == KEapolType || KEtherType == KWaiType ) ?
+ // as EAPOL and WAI frames or not really Voice data (they
+ // are just sometimes sent with Voice priority), handle them
+ // here as Best Effort (Legacy)
+ WHA::ELegacy :
+ accessCategory,
+ KEtherPayloadLen );
+
+ // for a non-A-MSDU this loop is executed only once
+ } while ( KAmsdu && snapLocation < KMpduPayloadEnd );
+
+ if ( nbrOfpacketsForUsr )
+ {
+ latestValidPacketForUsr->KeClearFlags(
+ TDataBuffer::KDontReleaseBuffer );
+
+ // complete user data / protocol stack data frame(s)
+ if ( !aCtxImpl.iUmac.ProtocolStackDataReceiveComplete(
+ packetsForUsr[0],
+ nbrOfpacketsForUsr ) )
+ {
+ // there's no protocol stack client to whom to complete Rx packets.
+ // (Actually the control should never arrive here as we have
+ // checked the readiness of the protocol stack client already
+ // earlier)
+ nbrOfpacketsForUsr = 0;
+ }
+ }
+
+ if ( nbrOfpacketsForMgmtClient )
+ {
+ // complete WLAN Mgmt Client data frame(s)
+ aCtxImpl.iUmac.MgmtDataReceiveComplete(
+ packetsForMgmtClient[0],
+ nbrOfpacketsForMgmtClient );
+ }
+
+ if ( ( !nbrOfpacketsForUsr && !nbrOfpacketsForMgmtClient ) ||
+ ( KAmsdu && !nbrOfpacketsForUsr ) )
+ {
+ // the contents of the original Rx buffer are not needed any more,
+ // so deallocate it
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: free original Rx buf"));
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+
+ // if any change is needed regarding our power mgmt mode,
+ // proceed with it
+ PowerMgmtModeChange( aCtxImpl, powerMgmtModeChange );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnManagementActionFrameRx(
+ WlanContextImpl& aCtxImpl,
+ const TAny* aFrame,
+ const TUint32 aLength,
+ WHA::TRcpi aRcpi,
+ TUint8* aBuffer ) const
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::OnManagementActionFrameRx"));
+
+ TDataBuffer* metaHdr ( aCtxImpl.GetRxFrameMetaHeader() );
+
+ if ( metaHdr )
+ {
+ // set length and type
+ metaHdr->KeSetLength( aLength );
+ metaHdr->FrameType( TDataBuffer::KDot11Frame );
+ // set RCPI
+ metaHdr->KeSetRcpi( aRcpi );
+
+ // set the offset to the beginning of the Rx buffer from the beginning
+ // of the meta header. Note that this may be also negative
+ metaHdr->KeSetBufferOffset(
+ aBuffer
+ - reinterpret_cast<TUint8*>(metaHdr) );
+
+ // set the offset to the beginning of the actual frame within the
+ // Rx buffer
+ metaHdr->KeSetOffsetToFrameBeginning(
+ reinterpret_cast<const TUint8*>(aFrame) // frame beginning
+ - aBuffer ); // buffer beginning
+
+ // complete
+ const TDataBuffer* KMetaHdr ( metaHdr );
+ aCtxImpl.iUmac.MgmtDataReceiveComplete( KMetaHdr, 1 );
+ }
+ else
+ {
+ // no memory available for the meta header. In this case we have no
+ // other choice than to discard the received frame.
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ OsTracePrint( KWarningLevel | KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::OnManagementActionFrameRx: WARNING: no memory for meta hdr => abort rx") );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TAny* WlanDot11Associated::RequestForBuffer(
+ WlanContextImpl& aCtxImpl,
+ TUint16 aLength )
+ {
+ return aCtxImpl.GetRxBuffer( aLength );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::ReceivePacket(
+ WlanContextImpl& aCtxImpl,
+ WHA::TStatus aStatus,
+ const void* aFrame,
+ TUint16 aLength,
+ WHA::TRate /*aRate*/,
+ WHA::TRcpi aRcpi,
+ WHA::TChannelNumber /*aChannel*/,
+ TUint8* aBuffer,
+ TUint32 aFlags )
+ {
+ SDataMpduHeader* hdr(
+ reinterpret_cast<SDataMpduHeader*>(const_cast<TAny*>(aFrame)) );
+
+ if ( aStatus == WHA::KSuccess )
+ {
+ // packet reception success lets see what type of frame we have
+ OsTracePrint( KRxFrame,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::ReceivePacket:frame receive success, frame type: 0x%02x"),
+ hdr->iHdr.iFrameControl.iType );
+
+ if ( ( hdr->iHdr.iFrameControl.iType == E802Dot11FrameTypeData )
+ || ( hdr->iHdr.iFrameControl.iType == E802Dot11FrameTypeQosData ) )
+ {
+ OnDataFrameRx( aCtxImpl, aFrame, aLength, aFlags, aRcpi, aBuffer );
+
+ if ( aCtxImpl.InsertNewRcpiIntoPredictor( os_systemTime(), aRcpi ) )
+ {
+ // indicate WLAN signal loss prediction to WLAN Mgmt Client
+ OnInDicationEvent( aCtxImpl, ESignalLossPrediction );
+ }
+ }
+ else if ( hdr->iHdr.iFrameControl.iType
+ == E802Dot11FrameTypeManagementAction )
+ {
+ OnManagementActionFrameRx(
+ aCtxImpl,
+ aFrame,
+ aLength,
+ aRcpi,
+ aBuffer );
+
+ if ( aCtxImpl.InsertNewRcpiIntoPredictor( os_systemTime(), aRcpi ) )
+ {
+ // indicate WLAN signal loss prediction to WLAN Mgmt Client
+ OnInDicationEvent( aCtxImpl, ESignalLossPrediction );
+ }
+ }
+ else if ( hdr->iHdr.iFrameControl.iType
+ == E802Dot11FrameTypeDeauthentication )
+ {
+ OnDeauthenticateFrameRx( aCtxImpl, aBuffer );
+ }
+ else if ( hdr->iHdr.iFrameControl.iType
+ == E802Dot11FrameTypeDisassociation )
+ {
+ OnDisassociateFrameRx( aCtxImpl, aBuffer );
+ }
+ else if ( hdr->iHdr.iFrameControl.iType
+ == E802Dot11FrameTypeBeacon )
+ {
+ OnBeaconFrameRx( aCtxImpl, aFrame, aLength, aRcpi, aBuffer );
+ }
+ else if ( hdr->iHdr.iFrameControl.iType
+ == E802Dot11FrameTypeProbeResp )
+ {
+ OnProbeResponseFrameRx( aCtxImpl, aFrame, aLength, aRcpi, aBuffer );
+ }
+ else
+ {
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::ReceivePacket: unsupported frame type: 0x%02x"),
+ hdr->iHdr.iFrameControl.iType );
+
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+ }
+ else if ( aStatus == WHA::KDecryptFailure )
+ {
+ // decryption error
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::ReceivePacket: decrypt error for frame:"), hdr->iHdr );
+
+ OnInDicationEvent( aCtxImpl, EWepDecryptFailure );
+
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+ else if ( aStatus == WHA::KMicFailure )
+ {
+ // MIC failed
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::ReceivePacket: MIC error for frame:"), hdr->iHdr );
+
+ // address 1 is always the DA in our case
+ OnInDicationEvent( aCtxImpl,
+ (IsGroupBitSet( hdr->iHdr.iAddress1 ))
+ ? EGroupKeyMicFailure : EPairwiseKeyMicFailure
+ );
+
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+ else
+ {
+ // packet rececption failed
+ OsTracePrint( KRxFrame | KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::ReceivePacket: frame receive failure"));
+
+ // release the Rx buffer
+ aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::EncryptTxFrames(
+ WlanContextImpl& aCtxImpl,
+ const TDataBuffer& aDataBuffer ) const
+ {
+ TBool encrypt ( EFalse );
+
+ if ( aDataBuffer.KeFlags() & TDataBuffer::KTxFrameMustNotBeEncrypted )
+ {
+ // our client has instructed us not the encrypt this frame under
+ // any circumstances. EFalse will be returned.
+ // No further action needed
+ }
+ else
+ {
+ const WHA::TKeyType pairwiseKey ( aCtxImpl.PairWiseKeyType() );
+ const WHA::TKeyType groupKey ( aCtxImpl.GroupKeyType() );
+
+ if ( pairwiseKey != WHA::EKeyNone )
+ {
+ // pairwise key set => use encryption
+ encrypt = ETrue;
+ }
+ else
+ {
+ // pairwise key not set
+
+ if ( groupKey == WHA::EWepGroupKey )
+ {
+ // wep group key set => use encryption
+ encrypt = ETrue;
+ }
+ }
+ }
+
+ return encrypt;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint WlanDot11Associated::DecryptHdrOffset(
+ WlanContextImpl& aCtxImpl,
+ TUint32 aFlags ) const
+ {
+ TUint offset( 0 );
+
+ const TUint32 encryption ( aFlags & KReceivePacketEncryptionMask );
+
+ if ( aCtxImpl.WHASettings().iCapability & WHA::SSettings::KNoSecHdrAndTrailer )
+ {
+ // no security header is present on this sw layer. It is removed
+ // on lower layers; when necessary.
+ // We will return zero, so no further actions
+ }
+ else
+ {
+ // IV and/or Ext IV or CCMP header is present
+ // on this sw layer; when applicable
+
+ if ( encryption == WHA::KEncryptAes )
+ {
+ offset = KCcmpHeaderLength;
+ }
+ else if ( encryption == WHA::KEncryptTkip )
+ {
+ offset = KWepIVLength + KWepExtendedIVLength;
+ }
+ else if ( encryption == WHA::KEncryptWep )
+ {
+ offset = KWepIVLength;
+ }
+ else if ( encryption == WHA::KEncryptWapi )
+ {
+ offset = KWapiHeaderLength;
+ }
+ else
+ {
+ // frame not encrypted; returns zero
+ }
+ }
+
+ return offset;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint WlanDot11Associated::DecryptTrailerOffset(
+ WlanContextImpl& aCtxImpl,
+ TUint32 aFlags ) const
+ {
+ TUint offset( 0 );
+
+ const TUint32 encryption ( aFlags & KReceivePacketEncryptionMask );
+
+ if ( aCtxImpl.WHASettings().iCapability & WHA::SSettings::KNoSecHdrAndTrailer )
+ {
+ // no security trailer is present on this sw layer. It is removed
+ // on lower layers; when necessary.
+ // We will return zero, so no further actions
+ }
+ else
+ {
+ // ICV and/or MIC field is present on this sw layer; when applicable
+
+ if ( encryption == WHA::KEncryptAes )
+ {
+ offset = KMicLength;
+ }
+ else if ( encryption == WHA::KEncryptTkip )
+ {
+ offset = KMicLength + KWEPICVLength;
+ }
+ else if ( encryption == WHA::KEncryptWep )
+ {
+ offset = KWEPICVLength;
+ }
+ else if ( encryption == WHA::KEncryptWapi )
+ {
+ offset = KWapiMicLength;
+ }
+ else
+ {
+ // frame not encrypted; returns zero
+ }
+ }
+
+ return offset;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint WlanDot11Associated::ComputeEncryptionOffsetAmount(
+ const WlanContextImpl& aCtxImpl,
+ const TDataBuffer& aDataBuffer ) const
+ {
+ TUint offset( 0 );
+
+ if ( // our client has instructed us not the encrypt this frame under
+ // any circumstances OR
+ ( aDataBuffer.KeFlags() & TDataBuffer::KTxFrameMustNotBeEncrypted ) ||
+ // no space is reserved for security header on this sw layer. It is
+ // done on lower layers; when necessary.
+ ( aCtxImpl.WHASettings().iCapability &
+ WHA::SSettings::KNoSecHdrAndTrailer ) )
+ {
+ // We will return zero, so no further actions
+ }
+ else
+ {
+ // encryption is allowed if relevant and
+ // space is reserved for IV and/or Ext IV or CCMP header
+ // on this sw layer; when necessary
+
+ const WHA::TKeyType groupKey( aCtxImpl.GroupKeyType() );
+ const WHA::TKeyType pairwiseKey( aCtxImpl.PairWiseKeyType() );
+
+ if ( pairwiseKey == WHA::EAesPairWiseKey )
+ {
+ offset = KCcmpHeaderLength;
+ }
+ else if ( pairwiseKey == WHA::ETkipPairWiseKey )
+ {
+ offset = KWepIVLength + KWepExtendedIVLength;
+ }
+ else if ( pairwiseKey == WHA::EWepPairWiseKey )
+ {
+ offset = KWepIVLength;
+ }
+ else if ( pairwiseKey == WHA::EWapiPairWiseKey )
+ {
+ offset = KWapiHeaderLength;
+ }
+ else
+ {
+ // don't care of anything else
+ }
+
+ if ( !offset )
+ {
+ // no encryption used based on pairwise key presence
+ // check for WEP groupkey presence
+ if ( groupKey == WHA::EWepGroupKey )
+ {
+ offset = KWepIVLength;
+ }
+ else
+ {
+ // don't care of anything else as group key encyption is not
+ // supported for the other key types. For them we always have
+ // a pairwise key
+ }
+ }
+ }
+
+ return offset;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint WlanDot11Associated::EncryptTrailerLength(
+ WlanContextImpl& aCtxImpl,
+ const TDataBuffer& aDataBuffer ) const
+ {
+ TUint length( 0 );
+
+ if ( // our client has instructed us not the encrypt this frame under
+ // any circumstances OR
+ ( aDataBuffer.KeFlags() & TDataBuffer::KTxFrameMustNotBeEncrypted ) ||
+ // no space is reserved for security header on this sw layer. It is
+ // done on lower layers; when necessary.
+ ( aCtxImpl.WHASettings().iCapability &
+ WHA::SSettings::KNoSecHdrAndTrailer ) )
+ {
+ // We will return zero, so no further actions
+ }
+ else
+ {
+ // encryption is allowed if relevant and
+ // space is reserved for ICV and/or MIC
+ // on this sw layer; when necessary
+
+ const WHA::TKeyType groupKey( aCtxImpl.GroupKeyType() );
+ const WHA::TKeyType pairwiseKey( aCtxImpl.PairWiseKeyType() );
+
+ if ( pairwiseKey == WHA::EAesPairWiseKey )
+ {
+ length = KMicLength;
+ }
+ else if ( pairwiseKey == WHA::ETkipPairWiseKey )
+ {
+ length = KMicLength + KWEPICVLength;
+ }
+ else if ( pairwiseKey == WHA::EWepPairWiseKey )
+ {
+ length = KWEPICVLength;
+ }
+ else if ( pairwiseKey == WHA::EWapiPairWiseKey )
+ {
+ length = KWapiMicLength;
+ }
+ else
+ {
+ // don't care of anything else
+ }
+
+ if ( !length )
+ {
+ // no pairwise key present
+ // check for groupkey
+ if ( groupKey == WHA::EWepGroupKey )
+ {
+ length = KWEPICVLength;
+ }
+ else
+ {
+ // don't care of anything else as group key encyption is not
+ // supported for the other key types. For them we always have
+ // a pairwise key
+ }
+ }
+ }
+
+ return length;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TUint WlanDot11Associated::ComputeQosOffsetAmount(
+ WlanContextImpl& aCtxImpl ) const
+ {
+ const TUint KNoQosHeader( 0 );
+
+ if ( aCtxImpl.QosEnabled() )
+ {
+ return sizeof( T802Dot11QosControl );
+ }
+ else
+ {
+ return KNoQosHeader;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::EncapsulateEthernetFrame(
+ WlanContextImpl& aCtxImpl,
+ TWlanUserTxDataCntx& aDataCntx,
+ TDataBuffer& aDataBuffer,
+ TUint16& aEtherType ) const
+ {
+ TUint8* etherFrameBeginning ( aDataBuffer.GetBuffer() );
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::EncapsulateEthernetFrame: supplied ether frame start address: 0x%08x"),
+ reinterpret_cast<TUint32>(etherFrameBeginning) );
+
+ // start of dot11 frame
+ SDataFrameHeader* dot11_dataframe_hdr ( NULL );
+
+ // start of ethernet frame
+ const SEthernetHeader* ether_hdr
+ = reinterpret_cast<const SEthernetHeader*>(etherFrameBeginning);
+
+ // determine Ethernet type
+ aEtherType = ether_hdr->Type();
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: ether type: 0x%04x"),
+ aEtherType );
+
+ // compute space required for encryption header
+ // after dot11 radio header and before data payload
+ const TUint encryption_offset = (
+ ComputeEncryptionOffsetAmount( aCtxImpl, aDataBuffer ) );
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: encryption_offset: %d"),
+ encryption_offset );
+
+ const TUint32 ether_offset = (KMacAddressLength << 1);
+
+ // take a backup copy of the destination and source addresses from the
+ // ethernet frame as they will get overwritten
+
+ TMacAddress da;
+ os_memcpy(
+ reinterpret_cast<TUint8*>(&da),
+ etherFrameBeginning,
+ sizeof( TMacAddress ) );
+ TMacAddress sa;
+ os_memcpy(
+ reinterpret_cast<TUint8*>(&sa),
+ etherFrameBeginning + sizeof( TMacAddress ),
+ sizeof( TMacAddress ) );
+
+ // compute space possibly required at the end of the dot11 mac
+ // header for the QoS control field, which is required for QoS data frames
+ // This will be needed (i.e. the qosOffset will be > 0) if QoS is enabled
+ const TUint qosOffset = ComputeQosOffsetAmount( aCtxImpl );
+ // the mac header of HT QoS data frames also has an additional field,
+ // so determine if that field needs to be present and hence has a non-zero
+ // length
+ const TUint KHtControlOffset ( aCtxImpl.HtSupportedByNw() ?
+ KHtControlFieldLength : 0 );
+
+ if ( qosOffset )
+ {
+ // a QoS data frame
+
+ OsTracePrint( KWsaTxDetails | KQos, (TUint8*)
+ ("UMAC: qos data frame"));
+
+ SQosDataFrameHeader* dot11QosDataFrameHdr =
+ reinterpret_cast<SQosDataFrameHeader*>(
+ etherFrameBeginning
+ + ether_offset
+ - sizeof( KEncapsulatingRfc1042SnapHeader )
+ - encryption_offset
+ - KHtControlOffset
+ - sizeof( SQosDataFrameHeader ) );
+
+ // construct the MAC header
+ new (dot11QosDataFrameHdr) SQosDataFrameHeader;
+
+ // set the frame type
+ dot11QosDataFrameHdr->iHdr.iFrameControl.iType = E802Dot11FrameTypeQosData;
+
+ // reset the QoS control field
+ // => ack policy == acknowledge && priority == best effort
+ dot11QosDataFrameHdr->ResetQosControl();
+
+ // set the user priority
+ dot11QosDataFrameHdr->SetUserPriority( aDataBuffer.UserPriority() );
+
+ dot11_dataframe_hdr = reinterpret_cast<SDataFrameHeader*>(
+ dot11QosDataFrameHdr);
+
+ if ( KHtControlOffset )
+ {
+ // HT control field is present => order bit needs to be set
+ dot11QosDataFrameHdr->iHdr.SetOrderBit();
+
+ // clear the HT Control field, too
+ reinterpret_cast<SHtQosDataFrameHeader*>(
+ dot11QosDataFrameHdr)->ResetHtControl();
+ }
+ else
+ {
+ // HT control field is not present => order bit needs to be cleared
+ dot11QosDataFrameHdr->iHdr.ClearOrderBit();
+ }
+ }
+ else
+ {
+ // a non-QoS data frame
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: non-qos data frame"));
+
+ dot11_dataframe_hdr = reinterpret_cast<SDataFrameHeader*>(
+ etherFrameBeginning
+ + ether_offset
+ - sizeof( KEncapsulatingRfc1042SnapHeader )
+ - encryption_offset
+ - sizeof( SDataFrameHeader ) );
+
+ // construct the MAC header. In this case this also sets the frame type
+ // correctly
+ new (dot11_dataframe_hdr) SDataFrameHeader;
+ }
+
+ // set the source address
+ dot11_dataframe_hdr->iAddress2 = sa;
+
+ // set the destination address
+ DoSetTxMpduDaAddress( *dot11_dataframe_hdr, da );
+
+ // set the To DS bit
+ if ( aCtxImpl.NetworkOperationMode() == WHA::EBSS )
+ {
+ dot11_dataframe_hdr->SetToDsBit();
+ // set the BSS ID
+ dot11_dataframe_hdr->iAddress1 = aCtxImpl.GetBssId();
+ }
+ else
+ {
+ dot11_dataframe_hdr->ClearToDsBit();
+ // set the BSS ID
+ dot11_dataframe_hdr->iAddress3 = aCtxImpl.GetBssId();
+ }
+
+ // determine if the frame needs to be encrypted
+ if ( EncryptTxFrames( aCtxImpl, aDataBuffer ) )
+ {
+ dot11_dataframe_hdr->SetWepBit();
+ }
+ else
+ {
+ dot11_dataframe_hdr->ClearWepBit();
+ }
+
+ // set the snap header to correct location.
+ os_memcpy(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr)
+ + sizeof( SDataFrameHeader )
+ + qosOffset
+ + KHtControlOffset
+ // space occupied by encryption header(s)
+ + encryption_offset,
+ &KEncapsulatingRfc1042SnapHeader,
+ sizeof( KEncapsulatingRfc1042SnapHeader ) );
+
+ // clear the area reserved for IV etc, when necessary
+ if ( encryption_offset )
+ {
+ os_memset(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr)
+ + sizeof( SDataFrameHeader )
+ + qosOffset
+ + KHtControlOffset,
+ 0,
+ encryption_offset );
+ }
+
+ // compute padding required for encryption trailer (ICV, MIC etc)
+ const TUint encryptTrailerLength = (
+ EncryptTrailerLength( aCtxImpl, aDataBuffer ) );
+
+ // clear the area reserved for encryption trailer, when necessary
+ if ( encryptTrailerLength )
+ {
+ os_memset(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr)
+ + sizeof( SDataFrameHeader )
+ + qosOffset
+ + KHtControlOffset
+ + encryption_offset
+ + sizeof( SSnapHeader )
+ + aDataBuffer.GetLength() - ether_offset,
+ 0,
+ encryptTrailerLength );
+ }
+
+ // calculate frame length
+ const TUint length_of_frame =
+ // MAC header length
+ sizeof( SDataFrameHeader )
+ // length of possibly existing QoS control field
+ + qosOffset
+ // length of possibly existing HT control field
+ + KHtControlOffset
+ // SNAP header length
+ + sizeof( SSnapHeader )
+ // length of ethernet payload (including ether type)
+ + aDataBuffer.GetLength() - ether_offset
+ // encryption header length
+ + encryption_offset
+ // encryption trailer length
+ + encryptTrailerLength;
+
+ // we now have a dot11 frame ready to be sent
+ aDataCntx.Dot11FrameReady(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr),
+ length_of_frame );
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: length_of_frame (excl. fcs): %d"),
+ length_of_frame );
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: frame start address: 0x%08x"),
+ reinterpret_cast<TUint32>(dot11_dataframe_hdr) );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::EncapsulateSnapFrame(
+ WlanContextImpl& aCtxImpl,
+ TWlanUserTxDataCntx& aDataCntx,
+ TDataBuffer& aDataBuffer,
+ TBool aEncrypt,
+ TUint aEncryptionOffset,
+ TUint aEncryptTrailerLength,
+ TUint aQosOffset,
+ TUint aHtControlOffset ) const
+ {
+ // extract start of frame. The frame starts with a SNAP header
+ TUint8* snapFrameBeginning ( aDataBuffer.GetBuffer() );
+
+ // start of dot11 frame
+ SDataFrameHeader* dot11_dataframe_hdr( NULL );
+
+ if ( aQosOffset )
+ {
+ OsTracePrint( KWsaTxDetails | KQos, (TUint8*)
+ ("UMAC: qos data frame"));
+
+ SQosDataFrameHeader* dot11QosDataFrameHdr(
+ reinterpret_cast<SQosDataFrameHeader*>(
+ snapFrameBeginning
+ - aEncryptionOffset
+ - aHtControlOffset
+ - sizeof( SQosDataFrameHeader )) );
+
+ // construct the MAC header
+ new (dot11QosDataFrameHdr) SQosDataFrameHeader;
+
+ // set the frame type
+ dot11QosDataFrameHdr->iHdr.iFrameControl.iType = E802Dot11FrameTypeQosData;
+
+ // reset the QoS control field
+ // => ack policy == acknowledge && priority == best effort
+ dot11QosDataFrameHdr->ResetQosControl();
+
+ // set the user priority
+ dot11QosDataFrameHdr->SetUserPriority( aDataBuffer.UserPriority() );
+
+ dot11_dataframe_hdr = reinterpret_cast<SDataFrameHeader*>(
+ dot11QosDataFrameHdr);
+
+ if ( aHtControlOffset )
+ {
+ // HT control field is present => order bit needs to be set
+ dot11QosDataFrameHdr->iHdr.SetOrderBit();
+ // clear the HT Control field, too
+ reinterpret_cast<SHtQosDataFrameHeader*>(
+ dot11QosDataFrameHdr)->ResetHtControl();
+ }
+ else
+ {
+ // HT control field is not present => order bit needs to be cleared
+ dot11QosDataFrameHdr->iHdr.ClearOrderBit();
+ }
+ }
+ else
+ {
+ OsTracePrint( KWsaTxDetails | KQos, (TUint8*)
+ ("UMAC: non-qos data frame"));
+
+ dot11_dataframe_hdr = reinterpret_cast<SDataFrameHeader*>(
+ snapFrameBeginning
+ - aEncryptionOffset
+ - sizeof( SDataFrameHeader ) );
+
+ // construct the MAC header. In this case this also sets the frame type
+ // correctly
+ new (dot11_dataframe_hdr) SDataFrameHeader;
+ }
+
+ // set the source address
+ dot11_dataframe_hdr->iAddress2 = aCtxImpl.iWlanMib.dot11StationId;
+
+ // set the destination address
+ DoSetTxMpduDaAddress( *dot11_dataframe_hdr,
+ aDataBuffer.KeDestinationAddress() );
+
+ // set the To DS bit
+ if ( aCtxImpl.NetworkOperationMode() == WHA::EBSS )
+ {
+ dot11_dataframe_hdr->SetToDsBit();
+ // set the BSS ID
+ dot11_dataframe_hdr->iAddress1 = aCtxImpl.GetBssId();
+ }
+ else
+ {
+ dot11_dataframe_hdr->ClearToDsBit();
+ // set the BSS ID
+ dot11_dataframe_hdr->iAddress3 = aCtxImpl.GetBssId();
+ }
+
+ // determine if the frame needs to be encrypted
+ if ( aEncrypt )
+ {
+ dot11_dataframe_hdr->SetWepBit();
+ }
+ else
+ {
+ dot11_dataframe_hdr->ClearWepBit();
+ }
+
+ // clear the area reserved for IV etc, when necessary
+ if ( aEncryptionOffset )
+ {
+ os_memset(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr)
+ + sizeof( SDataFrameHeader )
+ + aQosOffset
+ + aHtControlOffset,
+ 0,
+ aEncryptionOffset );
+ }
+
+ // clear the area reserved for encryption trailer, when necessary
+ if ( aEncryptTrailerLength )
+ {
+ os_memset(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr)
+ + sizeof( SDataFrameHeader )
+ + aQosOffset
+ + aHtControlOffset
+ + aEncryptionOffset
+ + aDataBuffer.GetLength(),
+ 0,
+ aEncryptTrailerLength );
+ }
+
+ // calculate frame length
+ const TUint length_of_frame =
+ // MAC header length
+ sizeof( SDataFrameHeader ) +
+ // length of possibly existing QoS control field
+ aQosOffset +
+ // length of possibly existing HT control field
+ aHtControlOffset +
+ // payload (including SNAP header)
+ aDataBuffer.GetLength()
+ // encryption header length
+ + aEncryptionOffset
+ // encryption trailer length
+ + aEncryptTrailerLength;
+
+ // we now have a dot11 frame ready to be sent
+ aDataCntx.Dot11FrameReady(
+ reinterpret_cast<TUint8*>(dot11_dataframe_hdr),
+ length_of_frame );
+
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: length_of_frame: %d"),
+ length_of_frame );
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: frame start address: 0x%08x"),
+ reinterpret_cast<TUint32>(dot11_dataframe_hdr) );
+ // trace the dot11 frame header
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: Encapsulated prorietary SNAP Tx frame:"),
+ *(reinterpret_cast<Sdot11MacHeader*>(dot11_dataframe_hdr)));
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::SetDot11FrameToTxBuffer(
+ const WlanContextImpl& aCtxImpl,
+ TWlanUserTxDataCntx& aDataCntx,
+ TDataBuffer& aDataBuffer ) const
+ {
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::SetDot11FrameToTxBuffer") );
+
+ if ( aCtxImpl.HtSupportedByNw() && aCtxImpl.QosEnabled() )
+ {
+ // in this case we need to insert the HT Control field to the
+ // otherwise ready 802.11 MAC frame
+
+ const TUint KOrigLengthOfFrame = aDataBuffer.GetLength();
+ const TUint KMgmtFrameMacHdrLen = sizeof( SManagementFrameHeader );
+ TUint8* KFrameStart = aDataBuffer.GetBuffer();
+
+ os_memcpy(
+ KFrameStart +
+ KMgmtFrameMacHdrLen +
+ KHtControlFieldLength,
+ KFrameStart +
+ KMgmtFrameMacHdrLen,
+ KOrigLengthOfFrame - KMgmtFrameMacHdrLen );
+
+ // clear the added HT Control field
+ reinterpret_cast<SHtManagementFrameHeader*>(
+ KFrameStart)->ResetHtControl();
+ // update frame length
+ aDataBuffer.KeSetLength( KOrigLengthOfFrame + KHtControlFieldLength );
+ // as the HT control field is present the order bit needs to be set
+ reinterpret_cast<SHtManagementFrameHeader*>(
+ KFrameStart)->iMgmtFrameHdr.SetOrderBit();
+ }
+
+ // we now have a dot11 frame ready to be sent
+ aDataCntx.Dot11FrameReady(
+ aDataBuffer.GetBuffer(),
+ aDataBuffer.GetLength() );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::EncapsulateFrame(
+ WlanContextImpl& aCtxImpl,
+ TWlanUserTxDataCntx& aDataCntx,
+ TDataBuffer& aDataBuffer,
+ TUint16& aEtherType )
+ {
+ const TDataBuffer::TFrameType KFrameType( aDataBuffer.FrameType() );
+
+ OsTracePrint( KWsaTx, (TUint8*)
+ ("UMAC: WlanDot11Associated::EncapsulateFrame: frame type: %d"),
+ KFrameType );
+
+ if ( KFrameType == TDataBuffer::KEthernetFrame ||
+ KFrameType == TDataBuffer::KEthernetTestFrame )
+ {
+ // ethernet II frame in the buffer for tx
+
+ EncapsulateEthernetFrame(
+ aCtxImpl,
+ aDataCntx,
+ aDataBuffer,
+ aEtherType );
+ }
+ else if ( KFrameType == TDataBuffer::KSnapFrame )
+ {
+ // frame beginning with a SNAP header in the buffer for tx
+
+ EncapsulateSnapFrame(
+ aCtxImpl,
+ aDataCntx,
+ aDataBuffer,
+ EncryptTxFrames( aCtxImpl, aDataBuffer ),
+ ComputeEncryptionOffsetAmount( aCtxImpl, aDataBuffer ),
+ EncryptTrailerLength( aCtxImpl, aDataBuffer ),
+ ComputeQosOffsetAmount( aCtxImpl ),
+ aCtxImpl.HtSupportedByNw() ?
+ KHtControlFieldLength :
+ 0 );
+ }
+ else if ( KFrameType == TDataBuffer::KDot11Frame )
+ {
+ // ready made 802.11 frame in the buffer for tx
+
+ SetDot11FrameToTxBuffer( aCtxImpl, aDataCntx, aDataBuffer );
+ }
+ else
+ {
+ // not supported
+ OsTracePrint( KErrorLevel, (TUint8*)("UMAC: frame_type: %d"),
+ KFrameType );
+ OsAssert( (TUint8*)("UMAC: panic"),(TUint8*)(WLAN_FILE), __LINE__ );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::TxData(
+ WlanContextImpl& aCtxImpl,
+ TDataBuffer& aDataBuffer,
+ TBool aMore )
+ {
+ TWlanUserTxDataCntx& data_cntx( aCtxImpl.GetTxDataCntx() );
+
+ TBool stateChange( EFalse );
+
+ if ( (aCtxImpl.ProtocolStackTxDataAllowed()) )
+ {
+ // protocol stack tx data allowed
+ // now construct a dot11 frame from databuffer to storage
+
+ TUint16 etherType( 0 ); // initial value: not relevant
+
+ // construct the frame
+ EncapsulateFrame( aCtxImpl, data_cntx, aDataBuffer, etherType );
+
+ // dot11 frame ready to be sent so push it to the packet sceduler
+
+ // start of dot11 frame to send
+ const TUint8* start_of_frame(
+ data_cntx.StartOfFrame() );
+
+ // select correct tx queue
+ const WHA::TQueueId queue_id(
+ QueueId( aCtxImpl, start_of_frame ) );
+
+ // push the frame to packet scheduler for transmission
+ aCtxImpl.PushPacketToPacketScheduler(
+ start_of_frame,
+ data_cntx.LengthOfFrame(),
+ queue_id,
+ E802Dot11FrameTypeData,
+ &aDataBuffer,
+ aMore,
+ OutgoingMulticastDataFrame(
+ reinterpret_cast<const SDataFrameHeader*>( start_of_frame ) ) );
+ // now just wait for the scheduler to call completion methods
+
+ // check if we need to change power mgmt mode because of frame Tx
+ const TPowerMgmtModeChange KPowerMgmtModeChange (
+ aCtxImpl.OnFrameTx( queue_id, etherType ) );
+
+ // if any change change is needed regarding our power mgmt mode,
+ // proceed with it
+ stateChange = PowerMgmtModeChange( aCtxImpl, KPowerMgmtModeChange );
+ }
+ else
+ {
+ // protocol stack tx data not allowed
+
+#ifndef NDEBUG
+ // programming error
+ OsTracePrint( KErrorLevel, (TUint8*)
+ ("UMAC: Tx attempted when it's not allowed") );
+ OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
+#else
+ aCtxImpl.iUmac.OnTxProtocolStackDataComplete(
+ KErrNone,
+ &aDataBuffer );
+#endif
+ }
+
+ return stateChange;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::OnPacketSendComplete(
+ WlanContextImpl& aCtxImpl,
+ WHA::TStatus aStatus,
+ TUint32 aPacketId,
+ WHA::TRate aRate,
+ TUint32 /*aPacketQueueDelay*/,
+ TUint32 aMediaDelay,
+ TUint aTotalTxDelay,
+ TUint8 aAckFailures,
+ WHA::TQueueId aQueueId,
+ WHA::TRate aRequestedRate,
+ TBool aMulticastData )
+ {
+ if ( aPacketId == E802Dot11FrameTypeData ||
+ aPacketId == E802Dot11FrameTypeDataEapol )
+ {
+ // update data frame statistics
+ UpdateTxDataFrameStatistics(
+ aCtxImpl,
+ aQueueId,
+ aStatus,
+ aMulticastData,
+ aAckFailures,
+ aMediaDelay,
+ aTotalTxDelay );
+ }
+ else if ( aPacketId == E802Dot11FrameTypeQosDataNull )
+ {
+ // inform Null Data frame sending controller of QoS Null data Tx
+ // completion; successful or not
+ aCtxImpl.OnQosNullDataTxCompleted();
+ }
+ else if ( aPacketId == E802Dot11FrameTypeDataNull )
+ {
+ // inform Null Data frame sending controller of Null data Tx
+ // completion; successful or not
+ aCtxImpl.OnNullDataTxCompleted();
+ }
+
+ if ( aStatus == WHA::KSuccess )
+ {
+ aCtxImpl.OnTxCompleted( aRate, ETrue, aQueueId, aRequestedRate );
+
+ aCtxImpl.ResetFailedTxPacketCount();
+ DoRegainedBSSIndication( aCtxImpl );
+
+ if ( aPacketId == E802Dot11FrameTypeData ||
+ aPacketId == E802Dot11FrameTypeDataEapol ||
+ aPacketId == E802Dot11FrameTypeTestFrame )
+ {
+ // inform Null Data frame sending controller of successful
+ // data frame Tx completion
+ aCtxImpl.OnDataTxCompleted(
+ aPacketId == E802Dot11FrameTypeDataEapol ?
+ // as EAPOL and WAI frames or not really Voice data (we just
+ // send them with Voice priority in WMM nw), handle them
+ // here as Best Effort (Legacy)
+ WHA::ELegacy :
+ aQueueId );
+ }
+ }
+ else if ( aStatus == WHA::KErrorLifetimeExceeded && !aAckFailures )
+ {
+ // the packet was discarded by WLAN PDD without any Tx attempts
+ // So this is not a Tx failure and we don't need to take
+ // any further actions
+ OsTracePrint( KWsaTxDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::OnPacketSendComplete: packet expired in PDD without any Tx attempts)"));
+ }
+ else
+ {
+ // an actual Tx failure has occurred
+
+ aCtxImpl.OnTxCompleted( aRate, EFalse, aQueueId, aRequestedRate );
+
+ aCtxImpl.IncrementFailedTxPacketCount();
+
+ // if we have failed to send more than threshold number of
+ // consecutive packets, send Consecutive Tx Failures indication to
+ // WLAN Mgmt Client - unless already sent
+ if ( aCtxImpl.FailedTxPacketCount() >
+ aCtxImpl.iWlanMib.iFailedTxPacketCountThreshold )
+ {
+ DoConsecutiveTxFailuresIndication( aCtxImpl );
+ aCtxImpl.ResetFailedTxPacketCount();
+ }
+ }
+
+ aCtxImpl.iUmac.OnTxDataSent();
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::DoConsecutiveBeaconsLostIndication(
+ WlanContextImpl& aCtxImpl )
+ {
+ if ( aCtxImpl.OnConsecutiveBeaconsLost() )
+ {
+ OnInDicationEvent( aCtxImpl, EConsecutiveBeaconsLost );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void WlanDot11Associated::DoConsecutiveTxFailuresIndication(
+ WlanContextImpl& aCtxImpl )
+ {
+ if ( aCtxImpl.OnConsecutiveTxFailures() )
+ {
+ OnInDicationEvent( aCtxImpl, EConsecutiveTxFailures );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::DoRegainedBSSIndication(
+ WlanContextImpl& aCtxImpl )
+ {
+ if ( aCtxImpl.OnBssRegained() )
+ {
+ OnInDicationEvent( aCtxImpl, EBSSRegained );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::AddMulticastAddr(
+ WlanContextImpl& aCtxImpl,
+ const TMacAddress& aMacAddr )
+ {
+ TBool stateTransitionOccurred( EFalse );
+
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): addr to be added:"),
+ aMacAddr);
+
+ if ( aCtxImpl.MulticastFilteringDisAllowed() )
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): Multicast filtering disallowed"));
+
+ OnOidComplete( aCtxImpl, KErrGeneral );
+ }
+ else
+ {
+ if ( aCtxImpl.WHASettings().iNumOfGroupTableEntrys >
+ aCtxImpl.MulticastAddressCount() )
+ {
+ // wha layer is able to take in an address
+
+ // 1st try to add the address to our own internal bookkeeping
+ WlanContextImpl::TGroupAddStatus addStatus =
+ aCtxImpl.AddMulticastAddress( aMacAddr );
+
+ switch ( addStatus )
+ {
+ case WlanContextImpl::EOk:
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): Address will be added to the MIB"));
+ // the address needed to be added and adding went ok.
+ // Now update the group addresses MIB
+ stateTransitionOccurred = SetGroupAddressesTableMib( aCtxImpl );
+ break;
+ case WlanContextImpl::EAlreadyExists:
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): Address already exists"));
+ // the specified address already exists so there's no need
+ // to update the group addresses MIB
+ // just complete the request with OK status
+ OnOidComplete( aCtxImpl );
+ stateTransitionOccurred = EFalse;
+ break;
+ case WlanContextImpl::EFull:
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): Internal address table full; disallow multicast filtering"));
+ // we are not able to take in any more addresses.
+ // We will totally disable the multicast filtering
+ // and we won't allow it to be enabled any more during
+ // the current nw connection
+ //
+ aCtxImpl.ResetMulticastAddresses();
+ aCtxImpl.MulticastFilteringDisAllowed( ETrue );
+ stateTransitionOccurred =
+ SetGroupAddressesTableMib( aCtxImpl );
+ break;
+ default:
+ // programming error
+ OsTracePrint( KErrorLevel, (TUint8*)
+ ("UMAC: addStatus: %d"), addStatus );
+ OsAssert( (TUint8*)("UMAC: panic"),
+ (TUint8*)(WLAN_FILE), __LINE__ );
+ }
+ }
+ else
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::AddMulticastAddr(): WHA not able to accept address; disallow multicast filtering"));
+ // wha layer is not able to take in an address. Either this is one
+ // address too many, or it doesn't support even a single address.
+ // In either case we will totally disable the multicast filtering
+ // and we won't allow it to be enabled any more during the current
+ // nw connection
+ aCtxImpl.ResetMulticastAddresses();
+ aCtxImpl.MulticastFilteringDisAllowed( ETrue );
+ stateTransitionOccurred = SetGroupAddressesTableMib( aCtxImpl );
+ }
+ }
+
+ // signal caller whether a state transition occurred or not
+ return stateTransitionOccurred;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::RemoveMulticastAddr(
+ WlanContextImpl& aCtxImpl,
+ TBool aRemoveAll,
+ const TMacAddress& aMacAddr )
+ {
+ TBool stateTransitionOccurred( EFalse );
+
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::RemoveMulticastAddr(): addr to be removed:"),
+ aMacAddr);
+
+ if ( aCtxImpl.MulticastFilteringDisAllowed() )
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::RemoveMulticastAddr(): Multicast filtering disallowed"));
+ // filtering is not allowed currently so there can't be any addresses
+ // to remove. Just complete the request with OK status
+ OnOidComplete( aCtxImpl );
+ }
+ else
+ {
+ if ( aRemoveAll )
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::RemoveMulticastAddr(): remove all"));
+ // remove all addresses; naturally will also disable filtering
+ aCtxImpl.ResetMulticastAddresses();
+ stateTransitionOccurred = SetGroupAddressesTableMib( aCtxImpl );
+ }
+ else
+ {
+ // 1st remove the specified address from our own internal
+ // bookkeeping, if it exists
+ if ( aCtxImpl.RemoveMulticastAddress( aMacAddr ) )
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::RemoveMulticastAddr(): removing the specified address"));
+ // it existed, so update the group addresses MIB, too
+ stateTransitionOccurred = SetGroupAddressesTableMib( aCtxImpl );
+ }
+ else
+ {
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::RemoveMulticastAddr(): specified address doesn't exist, nothing to do"));
+ // it did't exist, so there's nothing to remove
+ // Just complete the request with OK status
+ OnOidComplete( aCtxImpl );
+ }
+ }
+ }
+
+ // signal caller whether a state transition occurred or not
+ return stateTransitionOccurred;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::AddBroadcastWepKey(
+ WlanContextImpl& aCtxImpl,
+ TUint32 aKeyIndex,
+ TBool aUseAsDefaulKey,
+ TUint32 aKeyLength,
+ const TUint8 aKey[KMaxWEPKeyLength],
+ const TMacAddress& aMac )
+ {
+ return OnAddBroadcastWepKey( aCtxImpl, aKeyIndex, aUseAsDefaulKey,
+ EFalse, // do NOT set as PTK
+ aKeyLength, aKey, aMac );
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::ConfigureTxQueueIfNecessary(
+ WlanContextImpl& aCtxImpl,
+ TQueueId aQueueId,
+ TUint16 aMediumTime,
+ TUint32 aMaxTxMSDULifetime )
+ {
+ // this cast is safe as the types are effectively the same
+ const WHA::TQueueId whaQueueId = static_cast<WHA::TQueueId>(aQueueId);
+
+ if ( aMediumTime != aCtxImpl.iWlanMib.iMediumTime[whaQueueId] ||
+ aMaxTxMSDULifetime !=
+ aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[whaQueueId] )
+ {
+ // at least one of the parameters for this queue is changed => a
+ // reconfiguration is needed
+
+ // update the queue parameters. These values will be used in the
+ // queue reconfiguration
+
+ aCtxImpl.iWlanMib.iMediumTime[aQueueId] = aMediumTime;
+ aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[whaQueueId] =
+ aMaxTxMSDULifetime;
+
+ OsTracePrint( KUmacDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::ConfigureTxQueueIfNecessary: reconfiguring the queue is necessary") );
+
+ // reconfigure the queue. Also request the WLAN mgmt client request
+ // to be completed
+ return ConfigureTxQueue( aCtxImpl, whaQueueId, ETrue );
+ }
+ else
+ {
+ // the provided queue parameters have not changed, so no need to
+ // reconfigure the queue
+
+ OsTracePrint( KUmacDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::ConfigureTxQueueIfNecessary: no queue reconfigure is necessary") );
+
+ // complete the WLAN Mgmt Client request
+ OnOidComplete( aCtxImpl, KErrNone );
+
+ // signal caller that no state transition occurred
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::SetGroupAddressesTableMib(
+ WlanContextImpl& aCtxImpl )
+ {
+ const TMacAddress* multicastAddresses( NULL );
+ const TUint32 nbrOfAddrs(
+ aCtxImpl.GetMulticastAddresses( multicastAddresses ) );
+
+ TUint32 mibLength(
+ // mib header length
+ WHA::Sdot11GroupAddressesTable::KHeaderSize
+ // + mib data length
+ + ( sizeof( TMacAddress ) * nbrOfAddrs ) );
+
+ // align length of MIB to 4-byte boundary
+ mibLength = Align4( mibLength );
+
+ OsTracePrint(
+ KWlmCmdDetails,
+ (TUint8*)
+ ("UMAC: WlanDot11Associated::SetGroupAddressesTableMib(): mibLength: %d"),
+ mibLength );
+
+ // allocate memory for the mib to write
+ WHA::Sdot11GroupAddressesTable* mib
+ = static_cast<WHA::Sdot11GroupAddressesTable*>
+ (os_alloc( mibLength ));
+
+ if ( !mib )
+ {
+ // allocation failed
+ // simulate macnotresponding error
+ OsTracePrint( KWarningLevel, (TUint8*)
+ ("UMAC: WlanDot11Associated::SetGroupAddressesTableMib(): memory allocating failed") );
+ return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding );
+ }
+
+ if ( nbrOfAddrs )
+ {
+ // at least one address exists, so enable multicast address filtering
+ mib->iEnable = ETrue;
+ }
+ else
+ {
+ // no addresses, so disable filtering
+ mib->iEnable = EFalse;
+ OsTracePrint( KWlmCmdDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::SetGroupAddressesTableMib(): no addresses; disable filtering") );
+ }
+
+ mib->iNumOfAddrs = nbrOfAddrs;
+
+ // copy the multicast addresses after the mib header
+ os_memcpy( mib->iAddrData,
+ reinterpret_cast<TUint8*>(const_cast<TMacAddress*>(
+ multicastAddresses)),
+ ( sizeof( TMacAddress ) * nbrOfAddrs ) );
+
+ WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib();
+
+ wha_cmd.Set(
+ aCtxImpl,
+ WHA::KMibDot11GroupAddressesTable,
+ mibLength,
+ mib );
+
+ // change global state: entry procedure triggers action
+ ChangeState( aCtxImpl,
+ *this, // prev state
+ wha_cmd, // next state
+ // the ACT
+ KCompleteManagementRequest
+ );
+
+ os_free( mib ); // release the allocated memory
+
+ // signal caller that a state transition occurred
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::PowerMgmtModeChange(
+ WlanContextImpl& aCtxImpl,
+ TPowerMgmtModeChange aPowerMgmtModeChange )
+ {
+ TBool stateChange ( EFalse );
+
+ if ( aPowerMgmtModeChange != ENoChange )
+ {
+ // power mgmt mode change needed
+
+ if ( aPowerMgmtModeChange == EToActive )
+ {
+ aCtxImpl.DesiredDot11PwrMgmtMode( WHA::KPsDisable );
+ }
+ else if ( aPowerMgmtModeChange == EToLightPs )
+ {
+ aCtxImpl.DesiredDot11PwrMgmtMode( WHA::KPsEnable );
+ aCtxImpl.SetDesiredPsModeConfig(
+ aCtxImpl.ClientLightPsModeConfig() );
+ }
+ else // aPowerMgmtModeChange == EToDeepPs
+ {
+ aCtxImpl.DesiredDot11PwrMgmtMode( WHA::KPsEnable );
+ aCtxImpl.SetDesiredPsModeConfig(
+ aCtxImpl.ClientDeepPsModeConfig() );
+ }
+
+ if ( !(aCtxImpl.WsaCmdActive()) )
+ {
+ // proceed with the power mgmt mode change
+ stateChange = ChangePowerMgmtMode( aCtxImpl );
+ }
+ else
+ {
+ // WHA command is in progress so we must defer this access
+ aCtxImpl.RegisterEvent( KPowerMgmtTransition );
+
+ OsTracePrint( KEventDispatcher | KPwrStateTransition,
+ (TUint8*)("UMAC: WlanDot11Associated::PowerMgmtModeChange: power mgmt mode change event registered"));
+ }
+ }
+
+ return stateChange;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void WlanDot11Associated::HandleProprietarySnapRxFrame(
+ TDataBuffer& aBuffer,
+ TBool aQosData,
+ const TAny* const aFrame,
+ const SAmsduSubframeHeader* aSubFrameHeader,
+ TUint aLength,
+ TUint aDecryptHeaderLen,
+ TUint aDecryptTrailerLen,
+ TUint aHtControlLen,
+ TUint8* aCopyBuffer ) const
+ {
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::HandleProprietarySnapRxFrame"));
+
+ // prepare received frame with proprietary SNAP header for wlan mgmt client
+ // Remove the possibly existing security header & trailer before
+ // passing the frame up
+
+ const TUint8* frameBeginning = reinterpret_cast<const TUint8*>(aFrame);
+ const TUint KMacHdrLen( aQosData ?
+ sizeof( SQosDataFrameHeader ) + aHtControlLen :
+ sizeof( SDataFrameHeader ) );
+ // subframe header length is non-zero only if the frame is part of an
+ // A-MSDU, i.e. if aCopyBuffer is not NULL
+ const TUint KSubframeHdrLen (
+ aCopyBuffer ? sizeof( SAmsduSubframeHeader ) : 0 );
+ // determine subframe length
+ const TUint KSubframeLen (
+ aSubFrameHeader ? aSubFrameHeader->Length() : 0 );
+
+ if ( aCopyBuffer )
+ {
+ // the frame needs to be copied to the copy buffer, which means
+ // that it is part of an A-MSDU
+
+ // 1st copy the MAC header
+ os_memcpy( aCopyBuffer, frameBeginning, KMacHdrLen );
+
+ // then copy the subframe body following the subframe header
+ os_memcpy(
+ aCopyBuffer
+ + KMacHdrLen,
+ reinterpret_cast<const TUint8*>(aSubFrameHeader) + KSubframeHdrLen,
+ KSubframeLen );
+
+ // update to point to the new location
+ frameBeginning = aCopyBuffer;
+ }
+ else
+ {
+ // no copying to the copy buffer is required
+
+ if ( aDecryptHeaderLen )
+ {
+ // decrypt header exists. Shift the MAC header so that it
+ // overwrites the decrypt header, thus removing it
+
+ TUint8* dest( const_cast<TUint8*>(frameBeginning)
+ + aDecryptHeaderLen );
+
+ TUint copyBlockSize( aQosData ?
+ sizeof( SQosDataFrameHeader ) + aHtControlLen :
+ sizeof( SDataFrameHeader ) );
+
+ os_memcpy( dest, frameBeginning, copyBlockSize );
+
+ // update to point to the new location
+ frameBeginning = dest;
+ }
+ }
+
+#ifndef NDEBUG
+ OsTracePrint( KRxFrame, (TUint8*)
+ ("UMAC: WlanDot11Associated::HandleProprietarySnapRxFrame: MPDU header:"),
+ *(reinterpret_cast<const Sdot11MacHeader*>(
+ frameBeginning)));
+#endif
+
+ // set the frame length
+ if ( aCopyBuffer )
+ {
+ aBuffer.KeSetLength( KMacHdrLen + KSubframeLen );
+ }
+ else
+ {
+ aBuffer.KeSetLength(
+ aLength - aDecryptHeaderLen - aDecryptTrailerLen );
+ }
+ // set the frame type
+ aBuffer.FrameType( TDataBuffer::KDot11Frame );
+ // set the offset to the beginning of the actual frame within the
+ // Rx buffer
+ aBuffer.KeSetOffsetToFrameBeginning(
+ frameBeginning // frame beginning
+ - aBuffer.KeGetBufferStart() ); // buffer beginning
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::ConfigureTxRatePolicies(
+ WlanContextImpl& aCtxImpl,
+ const TTxRatePolicy& aRatePolicy,
+ const TQueue2RateClass& aQueue2RateClass,
+ const TInitialMaxTxRate4RateClass& aInitialMaxTxRate4RateClass,
+ const TTxAutoRatePolicy& aAutoRatePolicy,
+ const THtMcsPolicy& aHtMcsPolicy )
+ {
+ OsTracePrint( KTxRateAdapt, (TUint8*)
+ ("UMAC: WlanDot11Associated::ConfigureTxRatePolicies"));
+
+ TBool stateChange( EFalse );
+
+ if ( aCtxImpl.ProtocolStackTxDataAllowed() )
+ {
+ // store the provided information ...
+ StoreTxRatePolicyInfo(
+ aCtxImpl,
+ aRatePolicy,
+ aQueue2RateClass,
+ aInitialMaxTxRate4RateClass,
+ aAutoRatePolicy,
+ aHtMcsPolicy );
+
+ // ... take it into use; and specify that the mgmt client request needs
+ // to be completed when doing it
+ stateChange = WlanDot11State::ConfigureTxRatePolicies( aCtxImpl,
+ ETrue );
+ if ( !stateChange )
+ {
+ // a fatal error occurred. Simulate MAC Not Responding error
+ // Note that the Mgmt Client request will be completed when
+ // entering the dot11error state
+ stateChange = DoErrorIndication(
+ aCtxImpl,
+ WHA::KErrorMacNotResponding );
+ }
+ }
+ else
+ {
+ // as user data is not allowed currently, it means that WLAN Mgmt client
+ // will request us to connect to a new nw shortly and this policy is for
+ // that new nw. So we shouldn't take the new rate policy into use yet,
+ // as we don't know which rates the new nw will be supporting. We just
+ // store the provided information for later use
+ stateChange = WlanDot11State::ConfigureTxRatePolicies(
+ aCtxImpl,
+ aRatePolicy,
+ aQueue2RateClass,
+ aInitialMaxTxRate4RateClass,
+ aAutoRatePolicy,
+ aHtMcsPolicy );
+ }
+
+ return stateChange;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool WlanDot11Associated::ConfigurePwrModeMgmtTrafficOverride(
+ WlanContextImpl& aCtxImpl,
+ TBool aStayInPsDespiteUapsdVoiceTraffic,
+ TBool aStayInPsDespiteUapsdVideoTraffic,
+ TBool aStayInPsDespiteUapsdBestEffortTraffic,
+ TBool aStayInPsDespiteUapsdBackgroundTraffic,
+ TBool aStayInPsDespiteLegacyVoiceTraffic,
+ TBool aStayInPsDespiteLegacyVideoTraffic,
+ TBool aStayInPsDespiteLegacyBestEffortTraffic,
+ TBool aStayInPsDespiteLegacyBackgroundTraffic )
+ {
+ OsTracePrint( KUmacDetails, (TUint8*)
+ ("UMAC: WlanDot11Associated::ConfigurePwrModeMgmtTrafficOverride"));
+
+ aCtxImpl.ConfigurePwrModeMgmtTrafficOverride(
+ aStayInPsDespiteUapsdVoiceTraffic,
+ aStayInPsDespiteUapsdVideoTraffic,
+ aStayInPsDespiteUapsdBestEffortTraffic,
+ aStayInPsDespiteUapsdBackgroundTraffic,
+ aStayInPsDespiteLegacyVoiceTraffic,
+ aStayInPsDespiteLegacyVideoTraffic,
+ aStayInPsDespiteLegacyBestEffortTraffic,
+ aStayInPsDespiteLegacyBackgroundTraffic );
+
+ // as we are already connected and aware of the network capabilities, we
+ // also need to freeze the dynamic power mode mgmt traffic
+ // override/ignoration settings so that they become immediately effective
+ aCtxImpl.FreezePwrModeMgmtTrafficOverride();
+
+ OnOidComplete( aCtxImpl, KErrNone );
+
+ // signal caller that no state transition occurred
+ return EFalse;
+ }