wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacDot11AuthenticatePending.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 02:03:13 +0200
changeset 0 c40eb8fe8501
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* 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 WlanDot11AuthenticatePending class
*
*/

/*
* %version: 38 %
*/

#include "config.h"
#include "UmacDot11AuthenticatePending.h"
#include "UmacContextImpl.h"

#ifndef NDEBUG
const TUint8 WlanDot11AuthenticatePending::iStateName
    [ESTATEMAX][KMaxStateStringLength] = 
    {
        {"EINIT"}, 
        {"ETXAUTHFRAME"}, 
        {"EWAIT4AUTHRESPONSE"},
        {"EWAIT4PUSHPACKET"},
        {"ECONTINUEDOT11TRAVERSE"}
    };

const TUint8 WlanDot11AuthenticatePending::iEventName
    [EEVENTMAX][KMaxEventStringLength] = 
    {
        {"ESTATEENTRY"}, {"ECONTINUE"}, {"ERXAUTHRESPONSE"}, 
        {"ETX_AUTHFRAME_XFER"}, {"ETX_SCHEDULER_FULL"}, 
        {"ETIMEOUT"}, {"EPUSHPACKET"}
    };
#endif 
// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::Entry( 
    WlanContextImpl& aCtxImpl )
    {
    OsTracePrint( KUmacProtocolState | KUmacAuth, 
        (TUint8*)("UMAC * execute dot11 authenticate"));

    if ( aCtxImpl.WsaCmdActive() )
        {
        // sanity checking code
        OsAssert( (TUint8*)("UMAC * panic"), (TUint8*)(WLAN_FILE), __LINE__ );
        }

    // no need to do event dispatching as this
    // thing is triggered by the user and
    // is executed synchronously as we only do OID completion
    // at the end of authenticate + association process
    // for the same reason we don't execute any asynchronous WHA commands 
    // from here so authetication protocol does not include multiple 
    // this object entry method executions

    if ( iState == EINIT )
        {
        // this is the start of the the FSM actions
        Fsm( aCtxImpl, ESTATEENTRY );
        }
    else
        {
        // implementation error see comment block above why
#ifndef NDEBUG
        OsTracePrint( KErrorLevel, (TUint8*)("state:"));
        OsTracePrint( KErrorLevel, iStateName[iState] );
#endif
        OsAssert( (TUint8*)("UMAC * panic"), (TUint8*)(WLAN_FILE), __LINE__ );
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::Exit( 
    WlanContextImpl& /*aCtxImpl*/ )
    {
    // we are departing this dot11state to another dot11state,
    // which means we are either:
    // 1) proceeding to WlanDot11AssociationPending state
    // in case of authentication success
    // 2) proceeding to WlanDot11Idle state
    // in case of authentication failure
    // we simple reset our local FSM for the next time...
    iState = EINIT;
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::StateEntryActions( 
    WlanContextImpl& aCtxImpl )
    {
    iFlags = 0;

    if ( aCtxImpl.HtSupportedByNw() )
        {
        aCtxImpl.GetHtAuthenticationFrame().ResetSeqNmbr();
        aCtxImpl.GetHtAuthenticationFrame().ClearWepBit();        
        }
    else
        {
        aCtxImpl.GetAuthenticationFrame().ResetSeqNmbr();
        aCtxImpl.GetAuthenticationFrame().ClearWepBit();
        }

    aCtxImpl.ResetAuthSeqNmbrExpected();

    // its up to our sub states to fill this block
    OnSetAlgorithmNumber( aCtxImpl );
    }

// -----------------------------------------------------------------------------
// Start authentication frame response timer
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::StartAuthenticationFrameResponseTimer( 
    WlanContextImpl& aCtxImpl )
    {
    // start authentication frame response timeout timer 
    const TUint32 timeout( dot11AuthenticationResponseTimeOut * KTU );
    
    OsTracePrint( KUmacAuth, (
        TUint8*)("UMAC: WlanDot11AuthenticatePending::StartAuthenticationFrameResponseTimer:timeout in microseconds: %d"), 
        timeout );

    aCtxImpl.iUmac.RegisterTimeout( timeout );
    }

// -----------------------------------------------------------------------------
// Send authenticate seq.number 1 message
// -----------------------------------------------------------------------------
//
TBool WlanDot11AuthenticatePending::SendAuthSeqNbr1Frame( 
    WlanContextImpl& aCtxImpl ) const
    {
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::SendAuthSeqNbr1Frame") );

    TBool status ( EFalse );

    // client doesn't have to take care of the tx buffer header space
    // as the method below does that by itself
    TUint8* start_of_frame = aCtxImpl.TxBuffer( ETrue );

    if ( start_of_frame )
        {
        TUint32 frameLength ( 0 );

        if ( aCtxImpl.HtSupportedByNw() && aCtxImpl.QosEnabled() )
            {
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Algorithm number: %d"), 
                aCtxImpl.GetHtAuthenticationFrame().GetAlgorithmNumber());
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Sequence number: %d"), 
                aCtxImpl.GetHtAuthenticationFrame().GetSeqNmbr());
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Status code: %d"), 
                aCtxImpl.GetHtAuthenticationFrame().GetStatusCode());
        
            frameLength = sizeof( SHtAuthenticationFrame );
            
            os_memcpy( 
                start_of_frame,
                &(aCtxImpl.GetHtAuthenticationFrame()), 
                frameLength );
            }
        else
            {
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Algorithm number: %d"), 
                aCtxImpl.GetAuthenticationFrame().GetAlgorithmNumber());
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Sequence number: %d"), 
                aCtxImpl.GetAuthenticationFrame().GetSeqNmbr());
            OsTracePrint( KUmacAuth, (TUint8*)
                ("UMAC: Status code: %d"), 
                aCtxImpl.GetAuthenticationFrame().GetStatusCode());
        
            frameLength = sizeof( SAuthenticationFrame );
            
            os_memcpy( 
                start_of_frame,
                &(aCtxImpl.GetAuthenticationFrame()), 
                frameLength );
            }
    
        // trace the frame critter
        OsTracePrint( KUmacAuth, (TUint8*)("UMAC: dot11 authenticate frame tx:"),
            *(reinterpret_cast<const Sdot11MacHeader*>(start_of_frame)) );
    
        const WHA::TQueueId queue_id 
            = QueueId( aCtxImpl, start_of_frame );
    
        // push the frame to packet scheduler for transmission
        status = aCtxImpl.PushPacketToPacketScheduler(
                    start_of_frame,
                    frameLength,
                    queue_id,
                    E802Dot11FrameTypeAuthSeqNmbr1,
                    NULL,
                    EFalse,
                    EFalse,
                    ETrue );
    
        if ( !status )
            {
            // as we came here we did get an internal Tx buffer for the frame
            // but packet push to scheduler failed. In this case we need cancel
            // the internal Tx buffer reservation as we will request it again
            // when the Packet Scheduler is again ready for packet push
            aCtxImpl.MarkInternalTxBufFree();
            }
        }
    else
        {
        // we didn't get a Tx buffer. EFalse will be returned
        // to indicate that
        OsTracePrint( KUmacAuth, (TUint8*)
            ("UMAC: WlanDot11AuthenticatePending::SendAuthSeqNbr1Frame: no internal Tx buffer available") );
        }
        
    return status;
    }

// -----------------------------------------------------------------------------
// completion method called when packet has been xferred to the WLAN device
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnPacketTransferComplete( 
    WlanContextImpl& aCtxImpl, 
    TUint32 aPacketId,
    TDataBuffer* aMetaHeader )
    {
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::OnPacketTransferComplete"));

    if ( aPacketId == E802Dot11FrameTypeData )
        {
        OnTxProtocolStackDataComplete( aCtxImpl, aMetaHeader );
        }
    else if ( aPacketId == E802Dot11FrameTypeDataEapol || 
              aPacketId == E802Dot11FrameTypeManagementAction ||
              aPacketId == E802Dot11FrameTypeTestFrame )
        {
        OnMgmtPathWriteComplete( aCtxImpl );
        }
    else
        {
        // this frame Tx request didn't come from above us (i.e. neither 
        // through the user data nor the management data API) but is
        // related to a frame Tx we have done internally. So we need to mark
        // the internal Tx buffer free again
        aCtxImpl.MarkInternalTxBufFree();
        }

    if ( aPacketId == E802Dot11FrameTypeAuthSeqNmbr1 
        || aPacketId == E802Dot11FrameTypeAuthSeqNmbr3 )
        {
        // authenticate tx message has been xferred to the WLAN device
        
        // so feed an event critter to the fsm
        Fsm( aCtxImpl, ETX_AUTHFRAME_XFER );
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
TBool WlanDot11AuthenticatePending::ResolveAuthMessage( 
    WlanContextImpl& aCtxImpl,
    TUint16 aAuthModeDesired,
    const void* aFrame,
    TUint32 aFlags )
    {
    TBool ret( EFalse );
    const SAuthenticationFixedFields* auth_fields = 
        HtcFieldPresent( aCtxImpl, aFrame, aFlags ) ?
            reinterpret_cast<const SAuthenticationFixedFields*>
              (reinterpret_cast<const TUint8*>(aFrame) + 
               sizeof( SHtManagementFrameHeader )) :
            reinterpret_cast<const SAuthenticationFixedFields*>
              (reinterpret_cast<const TUint8*>(aFrame) + 
               sizeof( SManagementFrameHeader ));

    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::ResolveAuthMessage: auth message sequence number expected: %d"), 
        aCtxImpl.GetAuthSeqNmbrExpected() );
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::ResolveAuthMessage: auth message sequence number: %d"), 
        auth_fields->SequenceNumber() );
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::ResolveAuthMessage: algorithm number expected: %d"), 
        aAuthModeDesired );
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::ResolveAuthMessage: algorithm number: %d"), 
        auth_fields->AlgorithmNumber() );
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: WlanDot11AuthenticatePending::ResolveAuthMessage: status code: %d"), 
        auth_fields->StatusCode() );

    if ( // is desired mode authentication
        ( auth_fields->AlgorithmNumber() == aAuthModeDesired )
        // AND is authentication transaction sequence number expected
        && ( auth_fields->SequenceNumber() == aCtxImpl.GetAuthSeqNmbrExpected() )
        // AND the status code is successful
        && ( auth_fields->StatusCode() == E802Dot11StatusSuccess ))
        {
        ret = ETrue;
        }

    return ret;
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::ChangeInternalState( 
    WlanContextImpl& aCtxImpl, 
    TState aNewState )
    {
    iState = aNewState;
    Fsm( aCtxImpl, ESTATEENTRY );
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::Fsm( 
    WlanContextImpl& aCtxImpl, 
    TEvent aEvent )
    {
    OsTracePrint( KUmacAuth, 
        (TUint8*)("UMAC * dot11-authenticatepending * FSM EVENT") );
#ifndef NDEBUG
    OsTracePrint( KUmacAuth, (TUint8*)("event:"));
    OsTracePrint( KUmacAuth, iEventName[aEvent] );
    OsTracePrint( KUmacAuth, (TUint8*)("state:"));
    OsTracePrint( KUmacAuth, iStateName[iState] );
#endif

    switch ( aEvent )
        {
        case ESTATEENTRY:
            OnStateEntryEvent( aCtxImpl );
            break;
        case ECONTINUE:
            OnContinueEvent( aCtxImpl );
            break;
        case ERXAUTHRESPONSE:
            OnRxAuthResponseEvent( aCtxImpl );
            break;
        case ETX_AUTHFRAME_XFER:
            OnTxAuthFrameXferEvent( aCtxImpl );
            break;
        case ETX_SCHEDULER_FULL:
            OnTxSchedulerFullEvent( aCtxImpl );
            break;
        case ETIMEOUT:
            OnTimeoutEvent( aCtxImpl );
            break;
        case EPUSHPACKET:
            OnPushPacketEvent( aCtxImpl );
            break;
        default:
            // cath internal FSM programming error
#ifndef NDEBUG
            OsTracePrint( KErrorLevel, (TUint8*)("event:"));
            OsTracePrint( KErrorLevel, iEventName[aEvent] );                
#endif
            OsAssert( (TUint8*)("* UMAC * panic"), 
                (TUint8*)(WLAN_FILE), __LINE__ );
            break;
        }
    }

// -----------------------------------------------------------------------------
// Handler for generic continue event.
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnContinueEvent( 
    WlanContextImpl& aCtxImpl )
    {
    switch ( iState )
        {
        case EINIT:
            ChangeInternalState( aCtxImpl, ETXAUTHFRAME );
            break;
        default:
            // catch internal FSM programming error
#ifndef NDEBUG
            OsTracePrint( KErrorLevel, (TUint8*)("state:"));
            OsTracePrint( KErrorLevel, iStateName[iState] );
#endif
            OsAssert( (TUint8*)("* UMAC * panic"), 
                (TUint8*)(WLAN_FILE), __LINE__ );
            break;
        }
    }

// -----------------------------------------------------------------------------
// Handler for authentication response timeout event.
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnTimeoutEvent( 
    WlanContextImpl& aCtxImpl )
    {
    // set completion code
    // as dot11idle state does the OID completion
    aCtxImpl.iStates.iIdleState.Set( KErrTimedOut );
    // authentication was not successful
    iFlags &= ~KAuthSuccess;
    ChangeInternalState( aCtxImpl, ECONTINUEDOT11TRAVERSE );
    }

// -----------------------------------------------------------------------------
// Handler for push packet to packet scheduler possible event
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnPushPacketEvent( 
    WlanContextImpl& aCtxImpl )
    {
    if ( iState == EWAIT4PUSHPACKET )
        {
        ChangeInternalState( aCtxImpl, ETXAUTHFRAME );
        }
    }

// -----------------------------------------------------------------------------
// Handler for authenticate request frame 
// has been xferred to the WLAN device event
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnTxAuthFrameXferEvent( 
    WlanContextImpl& aCtxImpl )
    {
    // change state
    ChangeInternalState( aCtxImpl, EWAIT4AUTHRESPONSE );
    }

// -----------------------------------------------------------------------------
// Handler for scheduler full event upon trying to tx dot11-authenticate frame
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnTxSchedulerFullEvent( 
    WlanContextImpl& aCtxImpl )
    {
    // change state
    OsTracePrint( KWarningLevel | KUmacAuth, (TUint8*)
        ("UMAC: packet scheduler full during authentication process") );

    ChangeInternalState( aCtxImpl, EWAIT4PUSHPACKET );
    }

// -----------------------------------------------------------------------------
// continue dot11 protocol statemachine traversal
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::ContinueDot11StateTraversal( 
    WlanContextImpl& aCtxImpl )
    {
    if ( iFlags & KAuthSuccess )
        {
        // authentication was a success
        // so we proceed to reassociation state - if this happens to be a 
        // roaming case - or to association state
        //
        if ( aCtxImpl.Reassociate() )
            {
            ChangeState( aCtxImpl, 
                *this,                                       // prev state
                aCtxImpl.iStates.iReassociationPendingState  // next state            
                );                                   
            }
        else
            {
            ChangeState( aCtxImpl, 
                *this,                                      // prev state
                aCtxImpl.iStates.iAssociationPendingState   // next state
                );                                   
            }
        }
    else
        {
        // authentication was a failure
        // either due AP denial or by timeout
        // the reason does not really intrest us here
        // as the procedure is the same...
        ChangeState( aCtxImpl, 
            *this,                          // prev state
            aCtxImpl.iStates.iIdleState     // next state
            );                                     
        }
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
TBool WlanDot11AuthenticatePending::OnTimeout( 
    WlanContextImpl& aCtxImpl )
    {
    TBool stateChange ( ETrue );
    
    switch ( iState )
        {
        case EWAIT4AUTHRESPONSE:
            // authentication response timeout
            
            OsTracePrint( KWarningLevel | KUmacAssoc, (TUint8*)
                ("UMAC: WlanDot11AuthenticatePending::OnTimeout: authentication resp. timeout => authenication failed!") );

            Fsm( aCtxImpl, ETIMEOUT );
            
            // in this case we return ETrue, i.e. signal the caller that a 
            // state change occurred
            
            break;
        default:
            // a timeout occurred when we weren't expecting it (yet). This 
            // means that a timeout callback had already been registered when
            // we tried to cancel this timer the previous time (regarding
            // the previous authentication frame). So this callback is not 
            // relevant and can be ignored. 
            
            OsTracePrint( KWarningLevel | KUmacAssoc, (TUint8*)
                ("UMAC: WlanDot11AuthenticatePending::OnTimeout: irrelevant timeout; ignored") );

            // Signal the caller that no state change occurred
            stateChange = EFalse;
        }
        
    return stateChange;
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::ReceivePacket( 
    WlanContextImpl& aCtxImpl,
    WHA::TStatus aStatus,
    const void* aFrame,
    TUint16 aLength,
    WHA::TRate /*aRate*/,
    WHA::TRcpi aRcpi,
    WHA::TChannelNumber /*aChannel*/,
    TUint8* aBuffer,
    TUint32 aFlags )
    {
    OsTracePrint( KUmacAuth, (TUint8*)
        ("UMAC: dot11-authenticatepending::ReceivePacket()") );

    if ( aStatus == WHA::KSuccess )
        {
        // receive success
        const Sdot11MacHeader* dot11_hdr( 
            static_cast<const Sdot11MacHeader*>(aFrame) );

        // we accept only frames with ToDS bit cleared
        if ( dot11_hdr->IsToDsBitSet() )
            {
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("UMAC: authenticating to BSS:") );
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("UMAC: rx-frame: ToDs bit set, discard frame") );

            // release the Rx buffer & abort
            aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
            return;
            }

        const TBool class2_frame( IsClass2Frame( dot11_hdr->iFrameControl.iType ) );
        const TBool class3_frame( IsClass3Frame( dot11_hdr->iFrameControl.iType ) );
        const TBool unicast_addr( !IsGroupBitSet( dot11_hdr->iAddress1 ) );

        if ( class2_frame && unicast_addr )
            {
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("UMAC: authenticating to BSS:") );
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("rx class2 frame with unicast DA address") );

            // class 2 frame rx and unicast address in address1 field
            // That's not the frame we are expecting. 
            // Note that we release the Rx buffer at the end of this method

            if ( !Authenticated() )
                {
                // we do not have a valid authentication with the 
                // BSS where the frame came
                OsTracePrint( KWarningLevel | KUmacAuth, 
                    (TUint8*)("TxDeauthenticate") );
                if ( !TxDeauthenticate( 
                        aCtxImpl, 
                        E802Dot11ReasonClass2FrameWhenNotAuth ) )
                    {
                    // frame was not sent because either packet scheduler was 
                    // full or because we didn't get a Tx buffer. In any case
                    // we won't try to send it again. 
                    }
                }
            }
        else if ( class3_frame && unicast_addr )
            {
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("UMAC: authenticating to BSS:") );
            OsTracePrint( KWarningLevel | KUmacAuth, 
                (TUint8*)("rx class3 frame with unicast DA address") );

            // class 3 frame rx and unicast address in address1 field
            // That's not the frame we are expecting
            // Note that we release the Rx buffer at the end of this method

            if ( !Authenticated() )
                {
                // we do not have a valid authentication with the 
                // BSS where the frame came
                OsTracePrint( KWarningLevel | KUmacAuth, 
                    (TUint8*)("TxDeauthenticate") );
                if ( !TxDeauthenticate( 
                        aCtxImpl, 
                        E802Dot11ReasonClass3FrameWhenNotAssoc ) )
                    {
                    // frame was not sent because either packet scheduler was 
                    // full or because we didn't get a Tx buffer. In any case
                    // we won't try to send it again. 
                    }                        
                }
            else
                {
                // we do have a valid authentication with the 
                // STA that sent the frame
                OsTracePrint( KWarningLevel | KUmacAuth, 
                    (TUint8*)("UMAC: TxDisassociate") );
                
                // set the BSSID of the existing network; and the DA
                if ( aCtxImpl.HtSupportedByNw() )
                    {
                    (aCtxImpl.GetHtDisassociationFrame()).iHeader.iBSSID = 
                        aCtxImpl.GetBssId();
                    (aCtxImpl.GetHtDisassociationFrame()).iHeader.iDA = 
                        aCtxImpl.GetBssId();                    
                    }
                else
                    {
                    (aCtxImpl.GetDisassociationFrame()).iHeader.iBSSID = 
                        aCtxImpl.GetBssId();
                    (aCtxImpl.GetDisassociationFrame()).iHeader.iDA = 
                        aCtxImpl.GetBssId();
                    }
                if ( !TxDisassociate( 
                        aCtxImpl, 
                        E802Dot11ReasonClass3FrameWhenNotAssoc ) )
                    {
                    // frame was not sent because either packet scheduler was 
                    // full or because we didn't get a Tx buffer. In any case
                    // we won't try to send it again. 
                    }                    
                }
            }
        else
            {
            // default handler
            OnReceiveFrameSuccess( 
                aCtxImpl, 
                aFrame, 
                aLength, 
                aRcpi, 
                aFlags, 
                aBuffer );
            }
        }
    else    // aStatus == WHA::KSuccess 
        {
        // receive failed, so no action here
        }

    // release the Rx buffer
    aCtxImpl.iUmac.MarkRxBufFree( aBuffer );
    }

// -----------------------------------------------------------------------------
// packet sceduler notification that a packet push is guaranteed to succeed 
// -----------------------------------------------------------------------------
//
void WlanDot11AuthenticatePending::OnPacketPushPossible( 
    WlanContextImpl& aCtxImpl )
    {
    // feed a critter to the fsm
    Fsm( aCtxImpl, EPUSHPACKET );
    }