diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacDot11State.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanldd/wlan_common/umac_common/src/UmacDot11State.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,4758 @@ +/* +* Copyright (c) 2002-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 WlanDot11State class. +* +*/ + +/* +* %version: 85 % +*/ + +#include "config.h" +#include "UmacDot11State.h" +#include "UmacWsaAddKey.h" +#include "UmacWsaKeyIndexMapper.h" +#include "umacaddbroadcastwepkey.h" +#include "UmacWsaWriteMib.h" +#include "UmacWsaReadMib.h" +#include "umacwhaconfigurequeue.h" +#include "umacwhaconfigureac.h" +#include "umacconfiguretxautoratepolicy.h" +#include "UmacContextImpl.h" +#include "wha_mibDefaultvalues.h" +#include "FrameXferBlock.h" +#include "umacelementlocator.h" + +struct TRate2NwsaRate + { + TRate iTrate; + WHA::TRate iNwsaRate; + }; + +const TRate2NwsaRate KTRate2NwsaRateTable[] = + { + { E1Mbps, WHA::KRate1Mbits }, + { E2Mbps, WHA::KRate2Mbits }, + { E5_5Mbps, WHA::KRate5_5Mbits }, + { E11Mbps, WHA::KRate11Mbits }, + { E22Mbps, WHA::KRate22Mbits }, + }; + +class TRate2NwsaRatePredicate + { +public: + + explicit TRate2NwsaRatePredicate( const TRate aRate ) + : iKey( aRate ) {}; + + TBool operator() ( const TRate2NwsaRate& aEntry ) const + { + return aEntry.iTrate == iKey; + } + +private: + + // Prohibit copy constructor. + TRate2NwsaRatePredicate ( const TRate2NwsaRatePredicate & ); + // Prohibit assigment operator. + TRate2NwsaRatePredicate& operator= ( const TRate2NwsaRatePredicate & ); + + const TRate iKey; + }; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::Scan( + WlanContextImpl& aCtxImpl, + TScanMode aMode, + const TSSID& aSSID, + TRate aScanRate, + SChannels& aChannels, + TUint32 aMinChannelTime, + TUint32 aMaxChannelTime, + TBool aSplitScan ) + { + + WHA::TRate rate( 0 ); + ResolveScanRate( aCtxImpl, aScanRate, rate ); + + // call the "real scan" + return RealScan( aCtxImpl, aMode, aSSID, rate, aChannels, + aMinChannelTime, aMaxChannelTime, aSplitScan ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::StopScan( WlanContextImpl& aCtxImpl ) + { + // as we are here it means that we have received a stop scan request + // even though there is no scan ongoing. This should only happen if the + // mgmt client has been in the process of making a stop scan request and + // hasn't noticed that the scan has already completed. Anyhow in this + // case we just complete the request + OnOidComplete( aCtxImpl, KErrNone ); + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::SetPowerMode( + WlanContextImpl& aCtxImpl, + TPowerMode aPowerMode, + TBool aDisableDynamicPowerModeManagement, + TWlanWakeUpInterval aWakeupModeInLightPs, + TUint8 aListenIntervalInLightPs, + TWlanWakeUpInterval aWakeupModeInDeepPs, + TUint8 aListenIntervalInDeepPs ) + { + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: WlanDot11State::SetPowerMode: aPowerMode: %d"), aPowerMode ); + + TBool ret( EFalse ); + + // store desired new dot11 power management mode by WLAN Mgmt Client + aCtxImpl.ClientDot11PwrMgmtMode( aPowerMode ); + + aCtxImpl.DynamicPwrModeMgtDisabled( aDisableDynamicPowerModeManagement ); + if ( aDisableDynamicPowerModeManagement ) + { + aCtxImpl.StopPowerModeManagement(); + } + + aCtxImpl.SetClientLightPsModeConfig( + aWakeupModeInLightPs, + aListenIntervalInLightPs ); + + aCtxImpl.SetClientDeepPsModeConfig( + aWakeupModeInDeepPs, + aListenIntervalInDeepPs ); + + // in case WLAN Mgmt Client wishes to use PS mode, Light PS is the initial + // desired PS mode configuration + aCtxImpl.SetDesiredPsModeConfig( + aCtxImpl.ClientLightPsModeConfig() ); + + if ( aCtxImpl.CurrentDot11PwrMgmtMode() != + aCtxImpl.ClientDot11PwrMgmtMode() ) + { + // there is a difference in current dot11 power management mode and + // WLAN Mgmt Client's desired dot11 power management mode + + // So, WLAN Mgmt Client's desired dot11 power management mode becomes + // our new desired mode + aCtxImpl.DesiredDot11PwrMgmtMode( aCtxImpl.ClientDot11PwrMgmtMode() ); + + // callee will complete the mgmt command + ret = OnDot11PwrMgmtTransitRequired( aCtxImpl ); + } + else + { + // no dot11 power management mode transition required. + + // See if there is difference in desired vs. current wake-up setting, + // which we only need to worry about if the requested pwr mgmt + // mode is PS + if ( aPowerMode == EPowerModePs && + DifferenceInPsModeWakeupSettings( aCtxImpl ) ) + { + // callee shall complete the request + ret = OnWlanWakeUpIntervalChange( aCtxImpl ); + } + else + { + // no action required regarding the wake-up setting, either + + // one possibility is that the following has happened: WLAN Mgmt + // client has requested us to use PS mode when possible, but we + // have dynamically changed to CAM mode because of data traffic. + // If that is the case and now the WLAN Mgmt client wants us + // to stay in CAM mode, make sure that the dynamic power mode + // management is deactivated + if ( aPowerMode == EPowerModeCam ) + { + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: WlanDot11State::SetPowerMode: CAM requested when we already are in CAM. Make sure that dynamic pwr mode mgmt is not active") ); + + aCtxImpl.StopPowerModeManagement(); + } + else + { + if ( !aDisableDynamicPowerModeManagement ) + { + // in case the only change is that now dynamic pwr + // mode mgmt is again allowed, make sure it is active + aCtxImpl.StartPowerModeManagement(); + } + } + } + + // complete the mgmt command + OnOidComplete( aCtxImpl ); + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::EnableUserData( + WlanContextImpl& aCtxImpl ) + { + TBool stateChange( EFalse ); + aCtxImpl.iEnableUserData = ETrue; + OnOidComplete( aCtxImpl, KErrNone ); + aCtxImpl.iUmac.UserDataReEnabled(); + + // signal global state transition event + return stateChange; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::DisableUserData( + WlanContextImpl& aCtxImpl ) + { + aCtxImpl.iEnableUserData = EFalse; + OnOidComplete( aCtxImpl, KErrNone ); + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::OnConfigureUmacMib( + WlanContextImpl& aCtxImpl, + TUint16 aRTSThreshold, + TUint32 aMaxTxMSDULifetime ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnConfigureUmacMib") ); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnConfigureUmacMib: RTSThreshold: %d"), + aRTSThreshold ); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnConfigureUmacMib: maxTxMSDULifetime: %d"), + aMaxTxMSDULifetime ); + + aCtxImpl.iWlanMib.dot11RTSThreshold = aRTSThreshold; + + for ( TUint i = 0; i < WHA::EQueueIdMax; ++i ) + { + aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[i] = aMaxTxMSDULifetime; + } + + aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetimeDefault = aMaxTxMSDULifetime; + + for ( TUint i = 0; i < WHA::EQueueIdMax; ++i ) + { + aCtxImpl.iWlanMib.iMediumTime[i] = KDot11MediumTimeDefault; + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::AddDefaultBroadcastWepKeyComplete( + WlanContextImpl& aCtxImpl ) const + { + OnOidComplete( aCtxImpl ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ResolveScanRate( + WlanContextImpl& /*aCtxImpl*/, + const TRate aRate, + WHA::TRate& aScanRate ) + { + const TRate2NwsaRatePredicate unary_predicate( aRate ); + + const TRate2NwsaRate* const end + = KTRate2NwsaRateTable + + (sizeof(KTRate2NwsaRateTable) / sizeof(TRate2NwsaRate)); + const TRate2NwsaRate* pos + = find_if( KTRate2NwsaRateTable, end, unary_predicate ); + + if ( pos == end ) + { + // not found; an implementation error + OsAssert( (TUint8*)("UMAC: panic"),(TUint8*)(WLAN_FILE), __LINE__ ); + } + + aScanRate = pos->iNwsaRate; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::NetworkCapabilityInformationMet( + WlanContextImpl& aCtxImpl) + { + if ( // do this if channel agility bit is not set + ( !aCtxImpl.GetCapabilityInformation().IsChannelAgilityBitSet() )) + { + // mimic the preamble bit from AP + // as some APs might not let us in if not matched + if ( aCtxImpl.GetCapabilityInformation().IsShortPreambleBitSet() ) + { + (aCtxImpl.GetAssociationRequestFrame()) + .SetCapabilityShortPreamble(); + (aCtxImpl.GetHtAssociationRequestFrame()) + .SetCapabilityShortPreamble(); + (aCtxImpl.GetReassociationRequestFrame()) + .SetCapabilityShortPreamble(); + (aCtxImpl.GetHtReassociationRequestFrame()) + .SetCapabilityShortPreamble(); + + aCtxImpl.UseShortPreamble( ETrue ); + } + else + { + (aCtxImpl.GetAssociationRequestFrame()) + .ClearCapabilityShortPreamble(); + (aCtxImpl.GetHtAssociationRequestFrame()) + .ClearCapabilityShortPreamble(); + (aCtxImpl.GetReassociationRequestFrame()) + .ClearCapabilityShortPreamble(); + (aCtxImpl.GetHtReassociationRequestFrame()) + .ClearCapabilityShortPreamble(); + + aCtxImpl.UseShortPreamble( EFalse ); + } + + // clear both CF fields as we don't support PCF + aCtxImpl.GetAssociationRequestFrame().ClearCFfields(); + aCtxImpl.GetHtAssociationRequestFrame().ClearCFfields(); + aCtxImpl.GetReassociationRequestFrame().ClearCFfields(); + aCtxImpl.GetHtReassociationRequestFrame().ClearCFfields(); + + // clear also all the fields we don't understand + aCtxImpl.GetAssociationRequestFrame().ClearReservedFields(); + aCtxImpl.GetHtAssociationRequestFrame().ClearReservedFields(); + aCtxImpl.GetReassociationRequestFrame().ClearReservedFields(); + aCtxImpl.GetHtReassociationRequestFrame().ClearReservedFields(); + + // we don't do PBCC + aCtxImpl.GetAssociationRequestFrame().ClearCapabilityPbcc(); + aCtxImpl.GetHtAssociationRequestFrame().ClearCapabilityPbcc(); + aCtxImpl.GetReassociationRequestFrame().ClearCapabilityPbcc(); + aCtxImpl.GetHtReassociationRequestFrame().ClearCapabilityPbcc(); + + if ( aCtxImpl.EncryptionStatus() != EEncryptionDisabled ) + { + // privacy desired + aCtxImpl.GetAssociationRequestFrame().SetWepBit(); + aCtxImpl.GetHtAssociationRequestFrame().SetWepBit(); + aCtxImpl.GetReassociationRequestFrame().SetWepBit(); + aCtxImpl.GetHtReassociationRequestFrame().SetWepBit(); + } + else + { + aCtxImpl.GetAssociationRequestFrame().ClearWepBit(); + aCtxImpl.GetHtAssociationRequestFrame().ClearWepBit(); + aCtxImpl.GetReassociationRequestFrame().ClearWepBit(); + aCtxImpl.GetHtReassociationRequestFrame().ClearWepBit(); + } + if ( aCtxImpl.RadioMeasurement() != EFalse ) + { + // Radio measurements desired + OsTracePrint (KInfoLevel, (TUint8 *)("UMAC: Radio measurements enabled")); + aCtxImpl.GetAssociationRequestFrame().SetRMBit(); + aCtxImpl.GetHtAssociationRequestFrame().SetRMBit(); + aCtxImpl.GetReassociationRequestFrame().SetRMBit(); + aCtxImpl.GetHtReassociationRequestFrame().SetRMBit(); + } + else + { + OsTracePrint (KInfoLevel, (TUint8 *)("UMAC: Radio measurements disabled")); + aCtxImpl.GetAssociationRequestFrame().ClearRMBit(); + aCtxImpl.GetHtAssociationRequestFrame().ClearRMBit(); + aCtxImpl.GetReassociationRequestFrame().ClearRMBit(); + aCtxImpl.GetHtReassociationRequestFrame().ClearRMBit(); + } + return ETrue; + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AreSupportedRatesMet( + WlanContextImpl& aCtxImpl, + TBool aCheckAlsoExtendedRates ) + { + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::AreSupportedRatesMet") ); + + // make sure these critters are zeroed at the beginning + + aCtxImpl.GetMinBasicRate() = 0; + aCtxImpl.GetMaxBasicRate() = 0; + aCtxImpl.ClearBasicRateSet(); + + // clear our existing supported rates IE + aCtxImpl.GetOurSupportedRatesIE().Clear(); + // ... and our existing extended supported rates IE + aCtxImpl.GetOurExtendedSupportedRatesIE().Clear(); + + TUint32 tx_rates( 0 ); + TUint8 nwRate( 0 ); + + // go through all supported rate elements in the supported rates IE + // ( max 8 ). + // Remenber that basic rates are also always part of supported rates + // when building supported rates bitmask + for ( TUint32 outer_idx = 0 + // loop until element count in the IE is reached + ; ( outer_idx != aCtxImpl.GetApSupportedRatesIE().GetElementLength() ) + // OR maximum length allowed for the IE is reached + // NOTE! The 802.11 standard specifies that the max length of the + // information part of this IE is eight rates (eight bytes). + // However at least some APs seem to put all their supported rates + // into this element. In order to be able to associate with those + // APs we have allocated enough space for all 802.11b/g rates in this + // IE and hence the following constant in the loop end condition + && outer_idx < KMaxNumberOfDot11bAndgRates + ; ++outer_idx ) + { + nwRate = (aCtxImpl.GetApSupportedRatesIE())[outer_idx]; + + if ( !ProcessSingleSupportedRateElement( aCtxImpl, nwRate, tx_rates ) ) + { + // unknown supported rates element encountered + if ( nwRate & KBasicRateMask ) + { + // it is part of BSS Basic Rate Set + if ( aCtxImpl.BssMembershipFeatureSupported( nwRate ) ) + { + // it is a WLAN feature which we support, + // so we can continue. No action required here + } + else + { + // we can't cope with it and shall abort + + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: network has unsupported mandatory rate/feature -> abort") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: rate: 0x%02x"), + nwRate); + + return EFalse; + } + } + else + { + // unknown element is not part of BSS Basic Rate Set + // we can cope with that + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: init network connect") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: network has unsupported supported rate -> continue") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: rate: 0x%02x"), + nwRate); + } + } + } // end outer for + + if ( aCheckAlsoExtendedRates ) + { + // go through all supported rate elements in the extended supported + // rates IE ( max 255 ). + // Remember that basic rates are also always part of supported rates + // when building supported rates bitmask + for ( TUint32 outer_idx = 0; + // loop until max element count in the IE is reached + ( outer_idx != aCtxImpl.GetApExtendedSupportedRatesIE().GetElementLength() ) + // OR maximum length allowed for the IE is reached + && outer_idx < KMaxNumberOfExtendedRates; + ++outer_idx ) + { + nwRate = (aCtxImpl.GetApExtendedSupportedRatesIE())[outer_idx]; + + if ( !ProcessSingleSupportedRateElement( + aCtxImpl, + nwRate, + tx_rates ) ) + { + // unknown supported rates element encountered + + if ( nwRate & KBasicRateMask ) + { + // it is part of BSS Basic Rate Set + + if ( aCtxImpl.BssMembershipFeatureSupported( nwRate ) ) + { + // it is a WLAN feature which we support, + // so we can continue. No action required here + } + else + { + // we can't cope with it and shall abort + + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: network has unsupported mandatory rate/feature -> abort") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: rate: 0x%02x"), + nwRate); + + return EFalse; + } + } + else + { + // unknown element is not part of BSS Basic Rate Set + // we can cope with that + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: init network connect") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: network has unsupported supported rate -> continue") ); + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AreSupportedRatesMet: rate: 0x%02x"), + nwRate); + } + } + } // for + } // if + + if ( tx_rates ) + { + // store common rates (between us & the nw) in our connection context + aCtxImpl.RateBitMask( tx_rates ); + + return ETrue; + } + else + { + // we ended up with an empty rate mask, i.e. the intersection + // of network's supported rates and our supported rates is empty. + // We are not able to join the network under these circumstances + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ProcessSingleSupportedRateElement( + WlanContextImpl& aCtxImpl, + const TUint8 aApRate, + TUint32& aRateBitmask ) + { + OsTracePrint( KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::ProcessSingleSupportedRateElement: processing AP rate: 0x%02x"), aApRate); + + // match 4 elements in our rates lookup table + const TUint num_of_elems = + sizeof(aCtxImpl.iSupportedRatesLookUpTable) + / sizeof(WlanContextImpl::SupportedRateLookUp); + + for ( TUint32 inner_idx = 0; + inner_idx != ( num_of_elems + 1 ); + ++inner_idx ) + { + if ( inner_idx == num_of_elems) + { + // if this block is reached it means that we have encountered + // a supported rates element that is not in our lookup table + OsTracePrint( KWarningLevel | KUmacDetails , (TUint8*) + ("UMAC: unknown AP rate element found: 0x%02x"), aApRate); + + return EFalse; + } + if ( ( aApRate & (~KBasicRateMask) ) == + ( aCtxImpl.iSupportedRatesLookUpTable[inner_idx].iSupportedRate & + ( ~KBasicRateMask ) ) ) + { + // make a rate for the tx rate adaptation object + aRateBitmask |= + (aCtxImpl.iSupportedRatesLookUpTable[inner_idx].iWsaRate); + + // check if this critter is part of a mandatory rate set + if ( aApRate & KBasicRateMask ) + { + OsTracePrint( KUmacDetails, + (TUint8*)("UMAC: rate is part of Basic Rate Set") ); + + // yes it is + // construct basic rate set mask for Join NWSA command + aCtxImpl.BasicRateSetBitSet( + aCtxImpl.iSupportedRatesLookUpTable[inner_idx].iWsaRate ); + + // store min basic rate + if ( aCtxImpl.GetMinBasicRate() == 0 ) + { + aCtxImpl.GetMinBasicRate() = + (aCtxImpl.iSupportedRatesLookUpTable[inner_idx]).iWsaRate; + } + // and store max basic rate + if ( aCtxImpl.GetMaxBasicRate() < + (aCtxImpl.iSupportedRatesLookUpTable[inner_idx]).iWsaRate ) + { + aCtxImpl.GetMaxBasicRate() + = (aCtxImpl.iSupportedRatesLookUpTable[inner_idx]) + .iWsaRate; + } + } + + // set this rate to our supported rates IE + // which we will send in assoc-request frame. If there's no space any + // more in supported rates IE use the extended supported rates IE + // + if (aCtxImpl.GetOurSupportedRatesIE().GetElementLength() < KMaxNumberOfRates ) + { + aCtxImpl.GetOurSupportedRatesIE().Append( aApRate ); + } + else + { + aCtxImpl.GetOurExtendedSupportedRatesIE().Append( aApRate ); + } + + // break out of for loop, + // we got a match no need to traverse any longer + break; + } + } // end for + + return ETrue; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::SetArpIpAddressTableMib( + WlanContextImpl& aCtxImpl, + TBool aEnableFiltering, + TIpv4Address aIpv4Address ) + { + const TUint32 KMibLength( sizeof( WHA::SarpIpAddressTable ) ); + + OsTracePrint( KWlmCmdDetails, (TUint8*) + ("UMAC: WlanDot11State::SetArpIpAddressTableMib: mibLength: %d"), + KMibLength ); + + // allocate memory for the mib to write + WHA::SarpIpAddressTable* mib + = static_cast + (os_alloc( KMibLength )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::SetArpIpAddressTableMib: memory allocating failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + if ( aEnableFiltering ) + { + mib->iEnable = ETrue; + mib->iIpV4Addr = aIpv4Address; + + OsTracePrint( KWlmCmdDetails, (TUint8*) + ("UMAC: WlanDot11State::SetArpIpAddressTableMib: enable filtering using address: 0x%08x"), + aIpv4Address ); + } + else + { + mib->iEnable = EFalse; + mib->iIpV4Addr = aIpv4Address; // value not relevant in this case + + OsTracePrint( KWlmCmdDetails, (TUint8*) + ("UMAC: WlanDot11State::SetArpIpAddressTableMib: disable filtering") ); + } + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, + WHA::KMibArpIpAddressTable, + KMibLength, + 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 WlanDot11State::OnDot11PwrMgmtTransitRequired( + WlanContextImpl& aCtxImpl ) + { + // the specified power state will be taken into use later + // So nothing more to do at this point than completing the oid + OnOidComplete( aCtxImpl ); + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::TQueueId WlanDot11State::QueueId( + const WlanContextImpl& aCtxImpl, + const TUint8* aDot11MacHeader ) const + { + // this initial value is always returned if we have a non-QoS connection + WHA::TQueueId queue_id( WHA::ELegacy ); + + if ( aCtxImpl.QosEnabled() ) + { + // a QOS connection + SQosDataMpduHeader* dot11_hdr + = reinterpret_cast( + const_cast(aDot11MacHeader)); + + // determine frame type + const TUint8 KFrameType( dot11_hdr->iHdr.iHdr.GetFrameControl().iType ); + + if ( KFrameType == E802Dot11FrameTypeQosData ) + { + // this is a QoS data frame so assign it to + // the correct queue according to the priority + + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::QueueId: 802.1d priority: %d"), + dot11_hdr->iHdr.UserPriority() ); + + queue_id = Queue( dot11_hdr->iHdr.UserPriority() ); + } + else + { + // a non data type frame is put to voice queue + queue_id = WHA::EVoice; + } + } + + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::QueueId: use queue: %d"), + queue_id ); + + return queue_id; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::TxDeauthenticate( + WlanContextImpl& aCtxImpl, + T802Dot11ManagementReasonCode aReason, + TBool aWaitIfIntTxBufNotFree ) const + { + OsTracePrint( KUmacProtocolState | KUmacAuth, + (TUint8*)("UMAC: WlanDot11State::TxDeauthenticate") ); + + 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( aWaitIfIntTxBufNotFree ); + + if ( start_of_frame ) + { + TUint32 frameLength ( 0 ); + + // construct deauthenticate frame + // note that we don't have to set SA because we have already set it + // in the initialize phase of the state machine + + if ( aCtxImpl.HtSupportedByNw() ) + { + // set the BSSID + (aCtxImpl.GetHtDeauthenticateFrame()).iHeader.iBSSID = aCtxImpl.GetBssId(); + // set the DA + (aCtxImpl.GetHtDeauthenticateFrame()).iHeader.iDA = aCtxImpl.GetBssId(); + // set the reason code + (aCtxImpl.GetHtDeauthenticateFrame()).iReasonCode.SetReasonCode( + aReason ); + + frameLength = sizeof( SHtDeauthenticateFrame ); + + // copy deauthentication frame to tx-buffer to correct offset + os_memcpy( + start_of_frame, + &(aCtxImpl.GetHtDeauthenticateFrame()), + frameLength ); + } + else + { + // set the BSSID + (aCtxImpl.GetDeauthenticateFrame()).iHeader.iBSSID = aCtxImpl.GetBssId(); + // set the DA + (aCtxImpl.GetDeauthenticateFrame()).iHeader.iDA = aCtxImpl.GetBssId(); + // set the reason code + (aCtxImpl.GetDeauthenticateFrame()).iReasonCode.SetReasonCode( + aReason ); + + frameLength = sizeof( SDeauthenticateFrame ); + + // copy deauthentication frame to tx-buffer to correct offset + os_memcpy( + start_of_frame, + &(aCtxImpl.GetDeauthenticateFrame()), + frameLength ); + } + + const WHA::TQueueId queue_id( QueueId( aCtxImpl, start_of_frame ) ); + + // send deauthentication frame by pushing it to the packet scheduler + status = aCtxImpl.PushPacketToPacketScheduler( + start_of_frame, + frameLength, + queue_id, + E802Dot11FrameTypeDeauthentication, + NULL, + EFalse, + EFalse, + ETrue ); + } + else + { + // we didn't get a Tx buffer => frame not sent. EFalse will be returned + // to indicate that + + OsTracePrint( KUmacProtocolState | KUmacAuth, (TUint8*) + ("UMAC: no free internal tx buf => frame not sent") ); + } + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::TxDisassociate( + WlanContextImpl& aCtxImpl, + T802Dot11ManagementReasonCode aReason, + TBool aWaitIfIntTxBufNotFree ) const + { + OsTracePrint( KUmacProtocolState | KUmacAssoc, + (TUint8*)("UMAC: WlanDot11State::TxDisassociate") ); + + 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( aWaitIfIntTxBufNotFree ); + + if ( start_of_frame ) + { + TUint32 frameLength ( 0 ); + + // NOTE: We don't set the address fields to frame here like + // in the case of dot11-deauthenticate frame, because in the case of + // roaming we would use that BSS's information where we are roaming + // to - instead of the existing one + + if ( aCtxImpl.HtSupportedByNw() ) + { + (aCtxImpl.GetHtDisassociationFrame()).iReasonCode.SetReasonCode( + aReason ); + + frameLength = sizeof( SHtDisassociateFrame ); + + // copy disassociation frame to tx-buffer to correct offset + os_memcpy( + start_of_frame, + &(aCtxImpl.GetHtDisassociationFrame()), + frameLength ); + } + else + { + (aCtxImpl.GetDisassociationFrame()).iReasonCode.SetReasonCode( + aReason ); + + frameLength = sizeof( SDisassociateFrame ); + + // copy disassociation frame to tx-buffer to correct offset + os_memcpy( + start_of_frame, + &(aCtxImpl.GetDisassociationFrame()), + frameLength ); + } + + const WHA::TQueueId queue_id + = QueueId( aCtxImpl, start_of_frame ); + + // send disassociation frame to the current AP by pushing it to the packet + // scheduler + status = aCtxImpl.PushPacketToPacketScheduler( + start_of_frame, + frameLength, + queue_id, + E802Dot11FrameTypeDisassociation, + NULL, + EFalse, + EFalse, + ETrue ); + } + else + { + // we didn't get a Tx buffer => frame not sent. EFalse will be returned + // to indicate that + + OsTracePrint( KUmacProtocolState | KUmacAuth, (TUint8*) + ("UMAC: no free internal tx buf => frame not sent") ); + } + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::SAesPairwiseKey* WlanDot11State::CreateAesPtkCtx( + WlanContextImpl& aCtxImpl, + WlanWsaAddKey& aWhaAddKey, + const TUint8* aData, + const TMacAddress& aMacAddr ) + { + // store info of AES PTK insertion + aCtxImpl.PairWiseKeyType( WHA::EAesPairWiseKey ); + + // allocate memory for the key structure + WHA::SAesPairwiseKey* key = static_cast + ( os_alloc( sizeof( WHA::SAesPairwiseKey ) ) ); + + if ( key ) + { + os_memcpy( + key->iMacAddr.iMacAddress, + aMacAddr.iMacAddress, + WHA::TMacAddress::KMacAddressLength ); + os_memcpy( key->iAesKey, aData, WHA::KAesKeyLength ); + + aWhaAddKey.Set( + aCtxImpl, + WHA::EAesPairWiseKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EAesPairWiseKey ) ); + } + else + { + // left intentionally empty + } + + return key; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::STkipPairwiseKey* WlanDot11State::CreateTkipPtkCtx( + WlanContextImpl& aCtxImpl, + WlanWsaAddKey& aWhaAddKey, + const TUint8* aData, + T802Dot11WepKeyId aKeyIndex, + const TMacAddress& aMacAddr ) + { + // store info of TKIP PTK insertion + aCtxImpl.PairWiseKeyType( WHA::ETkipPairWiseKey ); + + // allocate memory for the key structure + // the caller of this method will deallocate the memory + WHA::STkipPairwiseKey* key = static_cast + (os_alloc( sizeof( WHA::STkipPairwiseKey ) )); + + if ( key ) + { + os_memcpy( + key->iMacAddr.iMacAddress, + aMacAddr.iMacAddress, + WHA::TMacAddress::KMacAddressLength ); + os_memcpy( key->iTkipKey, aData, WHA::KTKIPKeyLength ); + os_memcpy( + key->iRxMicKey, + aData + WHA::KTKIPKeyLength, + WHA::KMicLength ); + os_memcpy( + key->iTxMicKey, + aData + WHA::KTKIPKeyLength + WHA::KMicLength, + WHA::KMicLength); + key->iKeyId = static_cast(aKeyIndex); + + aWhaAddKey.Set( aCtxImpl, + WHA::ETkipPairWiseKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::ETkipPairWiseKey ) ); + } + else + { + // left intentionally empty + } + + return key; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::SWepPairwiseKey* WlanDot11State::CreateUnicastWepKeyCtx( + WlanContextImpl& aCtxImpl, + WlanWsaAddKey& aWhaAddKey, + const TMacAddress& aMacAddr, + TUint32 aKeyLength, + const TUint8* aKey ) + { + // store info of WEP PTK insertion + aCtxImpl.PairWiseKeyType( WHA::EWepPairWiseKey ); + + // allocate memory for the key structure + WHA::SWepPairwiseKey* key = static_cast + (os_alloc( WHA::SWepPairwiseKey::KHeaderSize + aKeyLength )); + + if ( key ) + { + os_memcpy( + &(key->iMacAddr), + aMacAddr.iMacAddress, + sizeof(key->iMacAddr) ); + key->iKeyLengthInBytes = static_cast(aKeyLength); + os_memcpy( key->iKey, aKey, key->iKeyLengthInBytes ); + + aWhaAddKey.Set( aCtxImpl, + WHA::EWepPairWiseKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EWepPairWiseKey ) ); + } + else + { + // intentionally left empty + } + + return key; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::SWapiPairwiseKey* WlanDot11State::CreateWapiPtkCtx( + WlanContextImpl& aCtxImpl, + WlanWsaAddKey& aWhaAddKey, + const TUint8* aData, + T802Dot11WepKeyId aKeyIndex, + const TMacAddress& aMacAddr ) + { + // store info of WAPI pairwise key insertion + aCtxImpl.PairWiseKeyType( WHA::EWapiPairWiseKey ); + + // allocate memory for the key structure + // the caller of this method will deallocate the memory + WHA::SWapiPairwiseKey* key = static_cast + (os_alloc( sizeof( WHA::SWapiPairwiseKey ) )); + + if ( key ) + { + os_memcpy( + key->iMacAddr.iMacAddress, + aMacAddr.iMacAddress, + WHA::TMacAddress::KMacAddressLength ); + + key->iKeyId = static_cast(aKeyIndex); + + os_memcpy( key->iWapiKey, aData, WHA::KWapiKeyLength ); + + os_memcpy( + key->iMicKey, + aData + WHA::KWapiKeyLength, + WHA::KWapiMicKeyLength ); + + aWhaAddKey.Set( aCtxImpl, + WHA::EWapiPairWiseKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EWapiPairWiseKey ) ); + } + else + { + // left intentionally empty + } + + return key; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::TRate WlanDot11State::InitialSpecialFrameTxRate( + const WlanContextImpl& aCtxImpl ) const + { + WHA::TRate rateToUse ( WHA::KRate1Mbits ); + + const TUint32 basicRateSet = aCtxImpl.BasicRateSet(); + + if ( basicRateSet ) + { + // there is at least one supported basic rate (which is the way things + // are supposed to be if the network is correctly configured) + + if ( basicRateSet & WHA::KRate1Mbits ) + { + rateToUse = WHA::KRate1Mbits; + } + else if ( basicRateSet & WHA::KRate6Mbits ) + { + rateToUse = WHA::KRate6Mbits; + } + else if ( basicRateSet & WHA::KRate2Mbits ) + { + rateToUse = WHA::KRate2Mbits; + } + else if ( basicRateSet & WHA::KRate9Mbits ) + { + rateToUse = WHA::KRate9Mbits; + } + else + { + // none of the rates above is a supported basic rate, which is + // rather odd. + // Anyhow, figure out the lowest supported basic rate and use that + + WHA::TRate rateCandidate = WHA::KRate1Mbits; + + do + { + if ( basicRateSet & rateCandidate ) + { + rateToUse = rateCandidate; + // break the loop as we found what we are looking for + break; + } + else + { + rateCandidate <<= 1; + } + + } while ( rateCandidate <= WHA::KRate54Mbits ); + } + } + else + { + // there are no supported basic rates; which is actually a network + // configuration error. + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::InitialSpecialFrameTxRate: Warning: no basic rates configured in nw")); + + // But as we don't absolutely have to find a + // basic rate here, just stay with 1Mbps (set above) + } + + OsTracePrint( KWsaTxDetails, + (TUint8*)("UMAC: WlanDot11State::InitialSpecialFrameTxRate: use rate: 0x%08x"), + rateToUse ); + + return rateToUse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::DoErrorIndication( + WlanContextImpl& aCtxImpl, + WHA::TStatus /*aStatus*/ ) + { + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC * handle an error indication!") ); + + // this is the one and only global error handler + ChangeState( aCtxImpl, *this, aCtxImpl.iStates.iMacError ); + + // signal with return value that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::DoConsecutiveBeaconsLostIndication( + WlanContextImpl& /*aCtxImpl*/ ) + { + // not supported in default handler + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::DoRegainedBSSIndication( + WlanContextImpl& /*aCtxImpl*/ ) + { + // not supported in default handler + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::DoRadarIndication( + WlanContextImpl& /*aCtxImpl*/ ) + { + // not supported in default handler + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::DoRcpiIndication( + WlanContextImpl& /*aCtxImpl*/, + WHA::TRcpi /*aRcpi*/ ) + { + // not supported in default handler + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void WlanDot11State::DoPsModeErrorIndication( + WlanContextImpl& /*aCtxImpl*/ ) + { + // not supported in default handler + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::TxData( + WlanContextImpl& aCtxImpl, + TDataBuffer& aDataBuffer, + TBool /*aMore*/ ) + { + OsTracePrint( KErrorLevel, (TUint8*) + ("UMAC: Tx attempted when it's not allowed; frame ignored") ); + + aCtxImpl.iUmac.OnTxProtocolStackDataComplete( + KErrNone, + &aDataBuffer ); + + // no state change occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::TxMgmtData( + WlanContextImpl& aCtxImpl, + TDataBuffer& /*aDataBuffer*/ ) + { + // as we are not connected to network, this frame cannot be sent. + // Just complete the frame send request without error status; as + // the WLAN Mgmt Client doesn't care about the status + OnMgmtPathWriteComplete( aCtxImpl ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TAny* WlanDot11State::RequestForBuffer( + WlanContextImpl& /*aCtxImpl*/, + TUint16 /*aLength*/ ) + { + // no functionality in default handler + return NULL; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ReceivePacket( + WlanContextImpl& aCtxImpl, + WHA::TStatus /*aStatus*/, + const void* /*aFrame*/, + TUint16 /*aLength*/, + WHA::TRate /*aRate*/, + WHA::TRcpi /*aRcpi*/, + WHA::TChannelNumber /*aChannel*/, + TUint8* aBuffer, + TUint32 /*aFlags*/ ) + { + // release the Rx buffer + aCtxImpl.iUmac.MarkRxBufFree( aBuffer ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::OnWhaCommandResponse( + WlanContextImpl& aCtxImpl, + WHA::TCommandId aCommandId, + WHA::TStatus /*aStatus*/, + const WHA::UCommandResponseParams& aCommandResponseParams, + TUint32 aAct ) + { + // this command response method is supposed to be called + // when a concrete dot11 state object does not care about + // the command response parameters + + if ( aAct == KCompleteManagementRequest ) + { + // this must be a response to a command that was generated + // by this this dot11 state object default layer + if ( aCommandId != WHA::EReadMIBResponse ) + { + OnOidComplete( aCtxImpl ); + } + else + { + // as this is a MIB read request, we must supply the + // response to the Mgmt Client + if ( aCommandResponseParams.iReadMibResponse.iMib + == WHA::KMibStatisticsTable ) + { + // convert to a 32bit value before forwarding + TInt32 rcpi = reinterpret_cast + + (aCommandResponseParams.iReadMibResponse.iData)->iRcpi; + + OsTracePrint( + KUmacDetails, + (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse(): last rcpi: %d"), + rcpi ); + + OnOidComplete( aCtxImpl, + KErrNone, + reinterpret_cast(&rcpi), + sizeof(rcpi) ); + } + else if ( aCommandResponseParams.iReadMibResponse.iMib + == WHA::KMibCountersTable ) + { + const WHA::ScountersTable* countersTable = reinterpret_cast + + (aCommandResponseParams.iReadMibResponse.iData); + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: countersTableMib: nbr of FCS errors in received MPDUs: %d"), + countersTable->iFcsError ); + + aCtxImpl.StoreFcsErrorCount( countersTable->iFcsError ); + + // as we are about to report the frame statistics results, + // it's the time to perform also the necessary calculations + + aCtxImpl.CalculateAverageTxMediaDelays(); + aCtxImpl.CalculateAverageTotalTxDelays(); + + const TStatisticsResponse& frameStatistics ( aCtxImpl.FrameStatistics() ); + +#ifndef NDEBUG + // trace frame statistics + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: *** reported frame statistics ***:") ); + + for ( TUint i = 0; i < EQueueIdMax; ++i ) + { + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: * Access Category: %d *"), + i ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: successfully received unicast data frames: %d"), + frameStatistics.acSpecific[i].rxUnicastDataFrameCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: successfully transmitted unicast data frames: %d"), + frameStatistics.acSpecific[i].txUnicastDataFrameCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: successfully received multicast data frames: %d"), + frameStatistics.acSpecific[i].rxMulticastDataFrameCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: successfully transmitted multicast data frames: %d"), + frameStatistics.acSpecific[i].txMulticastDataFrameCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: nbr of data frame transmit retries: %d"), + frameStatistics.acSpecific[i].txRetryCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: nbr of data frame WLAN delivery failures: %d"), + frameStatistics.acSpecific[i].txErrorCount ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: average data frame Tx media delay in microsecs: %d"), + frameStatistics.acSpecific[i].txMediaDelay ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: average data frame total Tx delay in microsecs: %d"), + frameStatistics.acSpecific[i].totalTxDelay ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: data frame total Tx delay bin 0 count: %d"), + frameStatistics.acSpecific[i].totalTxDelayBin0 ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: data frame total Tx delay bin 1 count: %d"), + frameStatistics.acSpecific[i].totalTxDelayBin1 ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: data frame total Tx delay bin 2 count: %d"), + frameStatistics.acSpecific[i].totalTxDelayBin2 ); + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: data frame total Tx delay bin 3 count: %d"), + frameStatistics.acSpecific[i].totalTxDelayBin3 ); + } + + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::OnWhaCommandResponse: all ACs: nbr of FCS errors in received MPDUs: %d"), + frameStatistics.fcsErrorCount ); + +#endif + + OnOidComplete( aCtxImpl, + KErrNone, + reinterpret_cast(&frameStatistics), + sizeof( frameStatistics ) ); + + // the statistics are cleared after reporting them. It is safe + // to do it here as the information has already been copied + aCtxImpl.ResetFrameStatistics(); + } + // -- == WHA::KMibStatisticsTable -- + else + { + // this thing should never happen as we are not reading any + // other MIBs; an implementation error + OsAssert( (TUint8*)("UMAC: panic"),(TUint8*)(WLAN_FILE), __LINE__ ); + // well exclusion to this is the dot11stationId MIB that + // is read by dot11initphase object, but it overrides this + // method so this code is not executed in that case. + } + } + } + // -- aAct == KCompleteManagementRequest -- + else + { + // this is not a response to a command that was generated by this + // dot11 state object. + // which means that the originator of this command does not care + // about the response parameters. + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::OnWlanWakeUpIntervalChange( + WlanContextImpl& aCtxImpl ) + { + OnOidComplete( aCtxImpl ); + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +WHA::TQueueId WlanDot11State::Queue( TUint8 aPriority ) + { + // Mapping of 802.1d priorities to WMM Access Categories, and hence to + // WHA queue (id)s, as specified in WiFi WMM Specification v1.1 + const WHA::TQueueId K802Dot1dPriority2WhaQueueTable[] = + { WHA::ELegacy, // for priority 0 + WHA::EBackGround, // for priority 1 + WHA::EBackGround, // for priority 2 + WHA::ELegacy, // for priority 3 + WHA::EVideo, // for priority 4 + WHA::EVideo, // for priority 5 + WHA::EVoice, // for priority 6 + WHA::EVoice }; // for priority 7 + + return ( aPriority > 7 ) ? + WHA::ELegacy : + K802Dot1dPriority2WhaQueueTable[aPriority]; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::UapsdEnabledInNetwork( const SRxWmmIeData& aRxWmmIE ) + { + return ( aRxWmmIE.IsUapsdBitSet() ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::UapsdEnabledInNetwork( const SWmmParamElemData& aWmmParamElem ) + { + return ( aWmmParamElem.IsUapsdBitSet() ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::EnableQos( WlanContextImpl& aCtxImpl, + TBool aUapsdEnabledInNw ) + { + // enable QoS + aCtxImpl.QosEnabled( ETrue ); + + // first clear our WMM IE so that U-APSD flags will be set only when + // they are supposed to be set + aCtxImpl.OurWmmIe().Clear(); + + if ( aUapsdEnabledInNw ) + { + OsTracePrint( + KQos, (TUint8*) + ("UMAC: WlanDot11State::EnableQos(): u-apsd is supported by nw")); + + // make a note that U-APSD is supported/enabled in the nw + aCtxImpl.UapsdEnabled( ETrue ); + + // make a WMM AC both trigger & delivery enabled + // if U-APSD is supported by the nw (this we already know to be true) + // and + // if U-APSD usage has been requested by WLAN mgmt client for the AC + // in question + aCtxImpl.OurWmmIe().SetUapsdFlags( static_cast( + ( aCtxImpl.UapsdRequestedForVoice() ? EAcVoUapsdFlag : 0 ) | + ( aCtxImpl.UapsdRequestedForVideo() ? EAcViUapsdFlag : 0 ) | + ( aCtxImpl.UapsdRequestedForBackground() ? EAcBkUapsdFlag : 0 ) | + ( aCtxImpl.UapsdRequestedForBestEffort() ? EAcBeUapsdFlag : 0 )) ); + + // set max service period length for the ACs as requested by WLAN + // mgmt client + aCtxImpl.OurWmmIe().SetMaxSpLen( aCtxImpl.UapsdMaxSpLen() ); + } + else + { + OsTracePrint( + KQos, (TUint8*) + ("UMAC: WlanDot11State::EnableQos(): u-apsd not supported in nw")); + + aCtxImpl.UapsdEnabled( EFalse ); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::DetermineAcUapsdUsage( WlanContextImpl& aCtxImpl ) + { + if ( aCtxImpl.UapsdEnabled() ) + { + if ( aCtxImpl.UapsdRequestedForVoice() ) + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd used for Voice")); + aCtxImpl.UapsdUsedForVoice( ETrue ); + } + else + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd NOT used for Voice")); + aCtxImpl.UapsdUsedForVoice( EFalse ); + } + + if ( aCtxImpl.UapsdRequestedForVideo() ) + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd used for Video")); + aCtxImpl.UapsdUsedForVideo( ETrue ); + } + else + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd NOT used for Video")); + aCtxImpl.UapsdUsedForVideo( EFalse ); + } + + if ( aCtxImpl.UapsdRequestedForBestEffort() ) + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd used for Best Effort")); + aCtxImpl.UapsdUsedForBestEffort( ETrue ); + } + else + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd NOT used for Best Effort")); + aCtxImpl.UapsdUsedForBestEffort( EFalse ); + } + + if ( aCtxImpl.UapsdRequestedForBackground() ) + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd used for Background")); + aCtxImpl.UapsdUsedForBackground( ETrue ); + } + else + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd NOT used for Background")); + aCtxImpl.UapsdUsedForBackground( EFalse ); + } + } + else + { + OsTracePrint( KQos, (TUint8*) + ("UMAC: WlanDot11State::DetermineAcUapsdUsage: u-apsd NOT used for any AC")); + aCtxImpl.UapsdUsedForVoice( EFalse ); + aCtxImpl.UapsdUsedForVideo( EFalse ); + aCtxImpl.UapsdUsedForBestEffort( EFalse ); + aCtxImpl.UapsdUsedForBackground( EFalse ); + } + + // now when U-APSD usage per AC has been determined, freeze the dynamic + // power mode mgmt traffic override/ignoration settings + aCtxImpl.FreezePwrModeMgmtTrafficOverride(); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ResetAcParameters( + WlanContextImpl& aCtxImpl, + WHA::TQueueId aAccessCategory, + TBool aUseAandGvalues ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ResetAcParameters: Reset parameters of AC: %d"), + aAccessCategory ); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ResetAcParameters: aUseAandGvalues: %d"), + aUseAandGvalues ); + + switch ( aAccessCategory ) + { + case WHA::ELegacy: + aCtxImpl.CwMinVector()[WHA::ELegacy] = + aUseAandGvalues ? KDot11BeCwMinAandG : KDot11BeCwMinB; + aCtxImpl.CwMaxVector()[WHA::ELegacy] = KDot11BeCwMax; + aCtxImpl.AifsVector()[WHA::ELegacy] = KDot11BeAifsn; + aCtxImpl.TxOplimitVector()[WHA::ELegacy] = KDot11BeTxopLimit; + break; + case WHA::EBackGround: + aCtxImpl.CwMinVector()[WHA::EBackGround] = + aUseAandGvalues ? KDot11BgCwMinAandG : KDot11BgCwMinB; + aCtxImpl.CwMaxVector()[WHA::EBackGround] = KDot11BgCwMax; + aCtxImpl.AifsVector()[WHA::EBackGround] = KDot11BgAifsn; + aCtxImpl.TxOplimitVector()[WHA::EBackGround] = KDot11BgTxopLimit; + break; + case WHA::EVideo: + aCtxImpl.CwMinVector()[WHA::EVideo] = + aUseAandGvalues ? KDot11ViCwMinAandG : KDot11ViCwMinB; + aCtxImpl.CwMaxVector()[WHA::EVideo] = + aUseAandGvalues ? KDot11ViCwMaxAandG : KDot11ViCwMaxB; + aCtxImpl.AifsVector()[WHA::EVideo] = KDot11ViAifsn; + aCtxImpl.TxOplimitVector()[WHA::EVideo] = + aUseAandGvalues ? KDot11ViTxopLimitAandG : KDot11ViTxopLimitB; + break; + case WHA::EVoice: + aCtxImpl.CwMinVector()[WHA::EVoice] = + aUseAandGvalues ? KDot11VoCwMinAandG : KDot11VoCwMinB; + aCtxImpl.CwMaxVector()[WHA::EVoice] = + aUseAandGvalues ? KDot11VoCwMaxAandG : KDot11VoCwMaxB; + aCtxImpl.AifsVector()[WHA::EVoice] = KDot11VoAifsn; + aCtxImpl.TxOplimitVector()[WHA::EVoice] = + aUseAandGvalues ? KDot11VoTxopLimitAandG : KDot11VoTxopLimitB; + break; + default: + { + // catch implementation error + + OsTracePrint( KErrorLevel, + (TUint8*)("UMAC: WlanDot11State::ResetAcParameters: unsupported access category: %d"), + aAccessCategory ); + OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + } + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ResetAcParameters( + WlanContextImpl& aCtxImpl, + TBool aUseAandGvalues ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ResetAcParameters: Reset parameters of all ACs. aUseAandGvalues: %d"), + aUseAandGvalues ); + + // Set the default values for a QoS connection for every AC + + ResetAcParameters( aCtxImpl, WHA::ELegacy, aUseAandGvalues ); + ResetAcParameters( aCtxImpl, WHA::EBackGround, aUseAandGvalues ); + ResetAcParameters( aCtxImpl, WHA::EVideo, aUseAandGvalues ); + ResetAcParameters( aCtxImpl, WHA::EVoice, aUseAandGvalues ); + + // reset also the WMM Parameter Set Count to initial (not defined) value + aCtxImpl.WmmParameterSetCount( KWmmParamSetNotDefined ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AcParametersValid( + WlanContextImpl& aCtxImpl, + WHA::TQueueId aAccessCategory ) + { + TBool status ( ETrue ); + + if ( aAccessCategory < WHA::EHcca ) + { + if ( // AIFSN validity per the WMM specification + (aCtxImpl.AifsVector())[aAccessCategory] < KDot11AifsnMin || + // CwMin & CwMax sanity check + (aCtxImpl.CwMinVector())[aAccessCategory] >= + (aCtxImpl.CwMaxVector())[aAccessCategory] ) + { + status = EFalse; + } + else + { + // parameters are reasonable. No action needed + } + } + else + { + // catch implementation error + + OsTracePrint( KErrorLevel, + (TUint8*)("UMAC: WlanDot11State::AcParametersValid: unsupported aAccessCategory: %d"), + aAccessCategory ); + OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + } + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ParseAcParameters( + WlanContextImpl& aCtxImpl, + const SWmmParamElemData& aWmmParamElem ) + { + for( TUint8 i = 0; i < KNumOfWmmACs; i++ ) + { + switch ( aWmmParamElem.iAcParams[i].AccessCategory() ) + { + case EAcBestEffort: + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: parsing best effort AC parameters")); + (aCtxImpl.CwMinVector())[WHA::ELegacy] = + aWmmParamElem.iAcParams[i].CwMin(); + (aCtxImpl.CwMaxVector())[WHA::ELegacy] = + aWmmParamElem.iAcParams[i].CwMax(); + (aCtxImpl.AifsVector())[WHA::ELegacy] = + aWmmParamElem.iAcParams[i].Aifsn(); + (aCtxImpl.TxOplimitVector())[WHA::ELegacy] = + aWmmParamElem.iAcParams[i].TxOpLimit(); + (aCtxImpl.AcmVector())[WHA::ELegacy] = + ( aWmmParamElem.iAcParams[i].AdmissionControlMandatory() )? + ETrue : EFalse; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aCntrl mandatory: %d"), + aWmmParamElem.iAcParams[i].AdmissionControlMandatory()); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmin: %d"), (aCtxImpl.CwMinVector())[WHA::ELegacy]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmax: %d"), (aCtxImpl.CwMaxVector())[WHA::ELegacy]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aifsn: %d"), (aCtxImpl.AifsVector())[WHA::ELegacy]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: txOpLimit: %d"), (aCtxImpl.TxOplimitVector())[WHA::ELegacy]); + + if ( !AcParametersValid( aCtxImpl, WHA::ELegacy ) ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: BE parameters not reasonble. Resetting to defaults") ); + ResetAcParameters( + aCtxImpl, + WHA::ELegacy, + aCtxImpl.ErpIePresent() ); + } + break; + case EAcBackground: + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: parsing background AC parameters")); + (aCtxImpl.CwMinVector())[WHA::EBackGround] = + aWmmParamElem.iAcParams[i].CwMin(); + (aCtxImpl.CwMaxVector())[WHA::EBackGround] = + aWmmParamElem.iAcParams[i].CwMax(); + (aCtxImpl.AifsVector())[WHA::EBackGround] = + aWmmParamElem.iAcParams[i].Aifsn(); + (aCtxImpl.TxOplimitVector())[WHA::EBackGround] = + aWmmParamElem.iAcParams[i].TxOpLimit(); + (aCtxImpl.AcmVector())[WHA::EBackGround] = + ( aWmmParamElem.iAcParams[i].AdmissionControlMandatory() )? + ETrue : EFalse; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aCntrl mandatory: %d"), + aWmmParamElem.iAcParams[i].AdmissionControlMandatory()); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmin: %d"), (aCtxImpl.CwMinVector())[WHA::EBackGround]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmax: %d"), (aCtxImpl.CwMaxVector())[WHA::EBackGround]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aifsn: %d"), (aCtxImpl.AifsVector())[WHA::EBackGround]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: txOpLimit: %d"), (aCtxImpl.TxOplimitVector())[WHA::EBackGround]); + + if ( !AcParametersValid( aCtxImpl, WHA::EBackGround ) ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: BG parameters not reasonble. Resetting to defaults") ); + ResetAcParameters( + aCtxImpl, + WHA::EBackGround, + aCtxImpl.ErpIePresent() ); + } + break; + case EAcVideo: + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: parsing video AC parameters")); + (aCtxImpl.CwMinVector())[WHA::EVideo] = + aWmmParamElem.iAcParams[i].CwMin(); + (aCtxImpl.CwMaxVector())[WHA::EVideo] = + aWmmParamElem.iAcParams[i].CwMax(); + (aCtxImpl.AifsVector())[WHA::EVideo] = + aWmmParamElem.iAcParams[i].Aifsn(); + (aCtxImpl.TxOplimitVector())[WHA::EVideo] = + aWmmParamElem.iAcParams[i].TxOpLimit(); + (aCtxImpl.AcmVector())[WHA::EVideo] = + ( aWmmParamElem.iAcParams[i].AdmissionControlMandatory() )? + ETrue : EFalse; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aCntrl mandatory: %d"), + aWmmParamElem.iAcParams[i].AdmissionControlMandatory()); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmin: %d"), (aCtxImpl.CwMinVector())[WHA::EVideo]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmax: %d"), (aCtxImpl.CwMaxVector())[WHA::EVideo]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aifsn: %d"), (aCtxImpl.AifsVector())[WHA::EVideo]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: txOpLimit: %d"), (aCtxImpl.TxOplimitVector())[WHA::EVideo]); + + if ( !AcParametersValid( aCtxImpl, WHA::EVideo ) ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: VI parameters not reasonble. Resetting to defaults") ); + ResetAcParameters( + aCtxImpl, + WHA::EVideo, + aCtxImpl.ErpIePresent() ); + } + break; + case EAcVoice: + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: parsing voice AC parameters")); + (aCtxImpl.CwMinVector())[WHA::EVoice] = + aWmmParamElem.iAcParams[i].CwMin(); + (aCtxImpl.CwMaxVector())[WHA::EVoice] = + aWmmParamElem.iAcParams[i].CwMax(); + (aCtxImpl.AifsVector())[WHA::EVoice] = + aWmmParamElem.iAcParams[i].Aifsn(); + (aCtxImpl.TxOplimitVector())[WHA::EVoice] = + aWmmParamElem.iAcParams[i].TxOpLimit(); + (aCtxImpl.AcmVector())[WHA::EVoice] = + ( aWmmParamElem.iAcParams[i].AdmissionControlMandatory() )? + ETrue : EFalse; + + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aCntrl mandatory: %d"), + aWmmParamElem.iAcParams[i].AdmissionControlMandatory()); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmin: %d"), (aCtxImpl.CwMinVector())[WHA::EVoice]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: cwmax: %d"), (aCtxImpl.CwMaxVector())[WHA::EVoice]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: aifsn: %d"), (aCtxImpl.AifsVector())[WHA::EVoice]); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: txOpLimit: %d"), (aCtxImpl.TxOplimitVector())[WHA::EVoice]); + + if ( !AcParametersValid( aCtxImpl, WHA::EVoice ) ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: VO parameters not reasonble. Resetting to defaults") ); + ResetAcParameters( + aCtxImpl, + WHA::EVoice, + aCtxImpl.ErpIePresent() ); + } + break; + default: + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WARNING: Unknown AC: %d => parameters ignored"), + aWmmParamElem.iAcParams[i].AccessCategory() ); + } + } + + // store the current Parameter Set Count. + aCtxImpl.WmmParameterSetCount( aWmmParamElem.ParameterSetCount() ); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ParseAcParameters: param set cnt: %d"), + aCtxImpl.WmmParameterSetCount() ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddTkIPKey( + WlanContextImpl& aCtxImpl, + const TUint8* aData, + TUint32 /*aLength*/, + T802Dot11WepKeyId aKeyIndex, + const TMacAddress& aMacAddr ) + { + TBool ret( EFalse ); + WlanWsaAddKey& wsa_cmd( aCtxImpl.WsaAddKey() ); + WHA::STkipPairwiseKey* key( CreateTkipPtkCtx( + aCtxImpl, + wsa_cmd, + aData, + aKeyIndex, + aMacAddr ) + ); + + if ( key ) + { + ret = ETrue; + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // allways remember to release the memory + } + else + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddTkIPKey(): memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::StoreTxRatePolicyInfo( + WlanContextImpl& aCtxImpl, + const TTxRatePolicy& aRatePolicy, + const TQueue2RateClass& aQueue2RateClass, + const TInitialMaxTxRate4RateClass& aInitialMaxTxRate4RateClass, + const TTxAutoRatePolicy& aAutoRatePolicy, + const THtMcsPolicy& aHtMcsPolicy ) + { + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::StoreTxRatePolicyInfo: store provided Tx rate policy configuration data for later use")); + + TTxRatePolicy& ratePolicy = aCtxImpl.RatePolicy(); + os_memcpy( &ratePolicy, &aRatePolicy, sizeof( TTxRatePolicy ) ); + + TQueue2RateClass& queue2RateClass = aCtxImpl.Queue2RateClass(); + os_memcpy( &queue2RateClass, &aQueue2RateClass, sizeof( TQueue2RateClass ) ); + + TInitialMaxTxRate4RateClass& initialMaxTxRate4RateClass = + aCtxImpl.InitialMaxTxRate4RateClass(); + os_memcpy( + &initialMaxTxRate4RateClass, + &aInitialMaxTxRate4RateClass, + sizeof( TInitialMaxTxRate4RateClass ) ); + + TTxAutoRatePolicy& autoRatePolicy = aCtxImpl.AutoRatePolicy(); + os_memcpy( &autoRatePolicy, &aAutoRatePolicy, sizeof( TTxAutoRatePolicy ) ); + + THtMcsPolicy& htMcsPolicy = aCtxImpl.HtMcsPolicy(); + os_memcpy( &htMcsPolicy, &aHtMcsPolicy, sizeof( THtMcsPolicy ) ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureTxRatePolicies( + WlanContextImpl& aCtxImpl, + TBool aCompleteMgmtRequest ) + { + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ConfigureTxRatePolicies: rate bitmask (intersection of AP and our supported rates): 0x%08x"), + aCtxImpl.RateBitMask() ); + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ConfigureTxRatePolicies: aCompleteMgmtRequest: %d"), + aCompleteMgmtRequest ); + + TBool status ( ETrue ); + // retrieve reference to the stored rate policy + TTxRatePolicy& ratePolicy ( aCtxImpl.RatePolicy() ); + // retrieve reference to the stored Tx queue 2 Rate Class mapping + TQueue2RateClass& queue2RateClass ( aCtxImpl.Queue2RateClass() ); + // retrieve reference to the stored initial max Tx rate per rate class - + // information + TInitialMaxTxRate4RateClass& initialMaxTxRate4RateClass( + aCtxImpl.InitialMaxTxRate4RateClass() ); + // retrieve reference to the stored auto rate policy + TTxAutoRatePolicy& autoRatePolicy ( aCtxImpl.AutoRatePolicy() ); + // retrieve reference to the stored HT MCS policy + THtMcsPolicy& htMcsPolicy ( aCtxImpl.HtMcsPolicy() ); + + if ( aCtxImpl.WHASettings().iNumOfTxRateClasses < + ratePolicy.numOfPolicyObjects ) + { + // WHA layer doesn't support as many rate classes as has been + // provided to us. + + ResortToSingleTxRatePolicy( + aCtxImpl, + ratePolicy, + queue2RateClass ); + } + + TWhaRateMasks rateMasks; + os_memset( rateMasks, 0, sizeof( rateMasks ) ); + + FinalizeTxRatePolicy( + aCtxImpl, + ratePolicy, + rateMasks, + initialMaxTxRate4RateClass ); + + if ( aCtxImpl.WHASettings().iCapability & + WHA::SSettings::KAutonomousRateAdapt ) + { + //===================================================================== + // lower layer supports autonomous rate adaptation so we will let it + // handle the rate adaptation. + //===================================================================== + + FinalizeTxAutoratePolicy( + aCtxImpl, + ratePolicy, + autoRatePolicy ); + + SpecialTxAutoratePolicy( + aCtxImpl, + ratePolicy, + autoRatePolicy, + htMcsPolicy ); + + ConfigureForTxAutoratePolicy( + aCtxImpl, + ratePolicy, + queue2RateClass, + htMcsPolicy, + aCompleteMgmtRequest ); + } + else + { + //===================================================================== + // WHA layer doesn't support autonomous rate adaptation so we need to + // take care of rate adaption. Perform the relevant configuration + //===================================================================== + + status = ConfigureForTxRatePolicy( + aCtxImpl, + ratePolicy, + rateMasks, + queue2RateClass, + initialMaxTxRate4RateClass, + aCompleteMgmtRequest ); + } // else + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::DifferenceInPsModeWakeupSettings( + const WlanContextImpl& aCtxImpl ) const + { + TBool difference( EFalse ); + + // 1st determine the current PS mode wake-up setting + + const WHA::TWlanWakeUpInterval currentWakeupMode ( + aCtxImpl.iWlanMib.iWlanWakeupInterval ); + const TUint8 currentListenInterval ( + aCtxImpl.iWlanMib.iWlanListenInterval ); + + // and the desired wake-up setting + const TDot11PsModeWakeupSetting KDesiredPsModeConfig ( + aCtxImpl.DesiredPsModeConfig() ); + + if ( currentWakeupMode != + static_cast( + KDesiredPsModeConfig.iWakeupMode) ) + { + // difference in wake-up mode + difference = ETrue; + + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: WlanDot11State::DifferenceInPsModeWakeupSettings: difference in wake-up mode") ); + } + else + { + // wake-up mode is unchanged + + if ( KDesiredPsModeConfig.iWakeupMode + == EWakeUpIntervalEveryNthBeacon || + KDesiredPsModeConfig.iWakeupMode + == EWakeUpIntervalEveryNthDtim ) + { + // for these wake-up modes there can be a + // difference in the listen interval. Check that + if ( currentListenInterval != KDesiredPsModeConfig.iListenInterval ) + { + difference = ETrue; + + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: WlanDot11State::DifferenceInPsModeWakeupSettings: difference in listen interval") ); + } + else + { + // no difference in listen interval either + // (return value is already correct) + } + } + else + { + // for these wake-up modes a possible difference in listen + // interval is not meaningful => no difference (return + // value is already correct) + } + } + + OsTracePrint( KPwrStateTransition, (TUint8*) + ("UMAC: WlanDot11State::DifferenceInPsModeWakeupSettings: difference: %d"), + difference ); + + return difference; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureHtCapabilities( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureHtCapabilities") ); + + // allocate memory for the mib to write + WHA::ShtCapabilities* mib + = static_cast + (os_alloc( sizeof( WHA::ShtCapabilities ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::ConfigureHtCapabilities: abort") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + // reset MIB before starting to set the values + os_memset( mib, 0, sizeof( WHA::ShtCapabilities ) ); + + //===================== + // Set the MIB contents + //===================== + + mib->iHtSupport = aCtxImpl.HtSupportedByNw(); + + // currently HT is supported only in infrastructure networks + mib->iPeerMac = WHA::KBroadcastMacAddr; + + mib->iRxStbc = aCtxImpl.GetNwHtCapabilitiesIe().iData.StbcRx(); + + mib->iMaxAmpduLength = + aCtxImpl.GetNwHtCapabilitiesIe().iData.MaxAmpduLenExponent(); + + // if a feature is supported by the nw, set it in the capabilities bit + // mask. Otherwise it is left unset + + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.LdpcRx() ) + { + mib->iPeerFeatures |= WHA::KLdpcRx; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.FortyMhzOperation() ) + { + mib->iPeerFeatures |= WHA::K40MhzChannel; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.GreenfieldFormat() ) + { + mib->iPeerFeatures |= WHA::KGreenfieldFormat; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.ShortGiFor20Mhz() ) + { + mib->iPeerFeatures |= WHA::KShortGiFor20Mhz; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.ShortGiFor40Mhz() ) + { + mib->iPeerFeatures |= WHA::KShortGiFor40Mhz; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.StbcTx() ) + { + mib->iPeerFeatures |= WHA::KStbcTx; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.DelayedBlockAck() ) + { + mib->iPeerFeatures |= WHA::KDelayedBlockAck; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.DsssCckIn40Mhz() ) + { + mib->iPeerFeatures |= WHA::KDsssCckIn40Mhz; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.Psmp() ) + { + mib->iPeerFeatures |= WHA::KPsmp; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.LsigTxopProtection() ) + { + mib->iPeerFeatures |= WHA::KLsigTxopProtection; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.Pco() ) + { + mib->iPeerFeatures |= WHA::KPco; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.Htc() ) + { + mib->iPeerFeatures |= WHA::KHtcField; + } + if ( aCtxImpl.GetNwHtCapabilitiesIe().iData.RdResponder() ) + { + mib->iPeerFeatures |= WHA::KReverseDirectionResp; + } + + os_memcpy( + mib->iMcsSet, + aCtxImpl.GetNwHtCapabilitiesIe().iData.iRxMcsBitmask, + sizeof( mib->iMcsSet ) ); + + mib->iAmpduSpacing = + aCtxImpl.GetNwHtCapabilitiesIe().iData.MinMpduStartSpacing(); + + mib->iMcsFeedback = aCtxImpl.GetNwHtCapabilitiesIe().iData.McsFeedback(); + + mib->iTxBeamFormingCapab = + aCtxImpl.GetNwHtCapabilitiesIe().iData.TransmitBeamformingCapabilities(); + + mib->iAntennaSelCapab = + aCtxImpl.GetNwHtCapabilitiesIe().iData.AselCapabilities(); + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, + WHA::KMibHtCapabilities, + sizeof(*mib), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + + os_free( mib ); // release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// --------------------------------------------------------- +// +// --------------------------------------------------------- +// +void WlanDot11State::ResetHtCapabilitiesMib( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ResetHtCapabilitiesMib") ); + + // allocate memory for the mib to write + WHA::ShtCapabilities* mib + = static_cast + (os_alloc( sizeof( WHA::ShtCapabilities ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::ResetHtCapabilitiesMib: abort") ); + DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + // reset the MIB to its default value + *mib = WHA::KHtCapabilitiesMibDefault; + + WlanWsaWriteMib& wsa_cmd = aCtxImpl.WsaWriteMib(); + + wsa_cmd.Set( + aCtxImpl, WHA::KMibHtCapabilities, sizeof( *mib ), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd // next state + ); + + os_free( mib ); // release the memory + } + +// --------------------------------------------------------- +// +// --------------------------------------------------------- +// +void WlanDot11State::ResetHtBlockAckConfigureMib( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ResetHtBlockAckConfigureMib") ); + + // allocate memory for the mib to write + WHA::ShtBlockAckConfigure* mib + = static_cast + (os_alloc( sizeof( WHA::ShtBlockAckConfigure ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::ResetHtBlockAckConfigureMib: abort") ); + DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + // reset the MIB to its default value + *mib = WHA::KHtBlockAckConfigureMibDefault; + + WlanWsaWriteMib& wsa_cmd = aCtxImpl.WsaWriteMib(); + + wsa_cmd.Set( + aCtxImpl, WHA::KMibHtBlockAckConfigure, sizeof( *mib ), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd // next state + ); + + os_free( mib ); // release the memory + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureHtBssOperation( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureHtBssOperation") ); + + // allocate memory for the mib to write + WHA::ShtBssOperation* mib + = static_cast + (os_alloc( sizeof( WHA::ShtBssOperation ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::ConfigureHtBssOperation: abort") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + // reset MIB before starting to set the values + os_memset( mib, 0, sizeof( WHA::ShtBssOperation ) ); + + //===================== + // Set the MIB contents + //===================== + + if ( aCtxImpl.GetNwHtOperationIe().iData.NonGreenfieldPresent() ) + { + mib->iInfo |= WHA::ShtBssOperation::KNonGreenfieldPresent; + } + if ( aCtxImpl.GetNwHtOperationIe().iData.PcoActive() ) + { + mib->iInfo |= WHA::ShtBssOperation::KPcoActive; + } + if ( aCtxImpl.GetNwHtOperationIe().iData.RifsMode() ) + { + mib->iInfo |= WHA::ShtBssOperation::KRifsPermitted; + } + if ( aCtxImpl.GetNwHtOperationIe().iData.DualCtsProtection() ) + { + mib->iInfo |= WHA::ShtBssOperation::KDualCtsProtReq; + } + if ( aCtxImpl.GetNwHtOperationIe().iData.DualBeacon() ) + { + mib->iInfo |= WHA::ShtBssOperation::KSecondaryBeaconTx; + } + if ( aCtxImpl.GetNwHtOperationIe().iData.LsigTxopProtection() ) + { + mib->iInfo |= WHA::ShtBssOperation::KLsigTxopProtection; + } + + os_memcpy( + mib->iMcsSet, + aCtxImpl.GetNwHtOperationIe().iData.iBasicMcsSet, + sizeof( mib->iMcsSet ) ); + + mib->iOpMode = + aCtxImpl.GetNwHtOperationIe().iData.HtProtection(); + + mib->iSecChOffset = + aCtxImpl.GetNwHtOperationIe().iData.SecondaryChOffset(); + + mib->iApChWidth = + aCtxImpl.GetNwHtOperationIe().iData.ChWidth(); + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, + WHA::KMibHtBssOperation, + sizeof(*mib), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + + os_free( mib ); // release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::HtcFieldPresent( + WlanContextImpl& aCtxImpl, + const TAny* aFrame, + TUint32 aFlags ) + { + TBool status ( EFalse ); + + if ( aCtxImpl.WHASettings().iCapability & WHA::SSettings::KHtOperation ) + { + // we can interpret the frame to have this header even if it would + // be a 802.11 mgmt frame as the header content that is relevant in + // this method is the same + const SDataFrameHeader* frameHdr + = reinterpret_cast(aFrame); + + if ( aFlags & WHA::KHtPacket && frameHdr->IsOrderBitSet() ) + { + status = ETrue; + OsTracePrint( KRxFrame, (TUint8*) + ("UMAC: WlanDot11State::HtcFieldPresent: yes") ); + } + } + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::OutgoingMulticastDataFrame( + const SDataFrameHeader* aDataFrameHdr ) + { + if ( aDataFrameHdr->IsToDsBitSet() ) + { + // frame to infrastructure nw. Address 3 == DA + + return IsGroupBitSet( aDataFrameHdr->iAddress3 ); + } + else + { + // frame to IBSS. Address 1 == DA + + return IsGroupBitSet( aDataFrameHdr->iAddress1 ); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::UpdateTxDataFrameStatistics( + WlanContextImpl& aCtxImpl, + WHA::TQueueId aAccessCategory, + WHA::TStatus aStatus, + TBool aMulticastData, + TUint aAckFailures, + TUint32 aMediaDelay, + TUint aTotalTxDelay ) + { + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: aAccessCategory: %d"), + aAccessCategory ); + + if ( aStatus == WHA::KSuccess ) + { + if ( aMulticastData ) + { + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: inc tx mcast cnt") ); + + aCtxImpl.IncrementTxMulticastDataFrameCount( aAccessCategory ); + } + else + { + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: inc tx unicast cnt") ); + + aCtxImpl.IncrementTxUnicastDataFrameCount( aAccessCategory ); + } + + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: ack failures: %d"), + aAckFailures ); + + aCtxImpl.IncrementTxRetryCount( aAccessCategory, aAckFailures ); + + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: aMediaDelay: %d"), + aMediaDelay ); + + aCtxImpl.IncrementTxMediaDelay( aAccessCategory, aMediaDelay ); + + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: aTotalTxDelay: %d"), + aTotalTxDelay ); + + aCtxImpl.IncrementTotalTxDelay( aAccessCategory, aTotalTxDelay ); + + aCtxImpl.UpdateTotalTxDelayHistogram( aAccessCategory, aTotalTxDelay ); + } + else + { + OsTracePrint( KWsaTxDetails, (TUint8*) + ("UMAC: WlanDot11State::UpdateTxDataFrameStatistics: inc tx error cnt") ); + aCtxImpl.IncrementTxErrorCount( aAccessCategory ); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::XferDot11FrameToMgmtClient( + WlanContextImpl& aCtxImpl, + const void* aFrame, + TUint32 aLength, + const WHA::TRcpi aRcpi, + TUint8* aBuffer ) const + { + OsTracePrint( KRxFrame, (TUint8*) + ("UMAC: WlanDot11State::XferDot11FrameToMgmtClient: aRcpi: %d"), + aRcpi); + + TBool status ( ETrue ); + + TDataBuffer* metaHdr ( aCtxImpl.GetRxFrameMetaHeader() ); + + if ( metaHdr ) + { + // set frame length + metaHdr->KeSetLength( aLength ); + + // set frame type + metaHdr->FrameType( TDataBuffer::KDot11Frame ); + + // set RCPI for every frame transferred to the mgmt client + 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(metaHdr) ); + + // set the offset to the beginning of the actual frame within the + // Rx buffer + metaHdr->KeSetOffsetToFrameBeginning( + reinterpret_cast(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 ); + // inform the caller about the situation + status = EFalse; + OsTracePrint( KWarningLevel | KRxFrame, (TUint8*) + ("UMAC: WlanDot11State::XferDot11FrameToMgmtClient: WARNING: no memory for meta hdr => abort rx") ); + } + + return status; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddMulticastTKIPKey( + WlanContextImpl& aCtxImpl, + T802Dot11WepKeyId aKeyIndex, + TUint32 /*aLength*/, + const TUint8* aData ) + { + // store info of TKIP GTK insertion + aCtxImpl.GroupKeyType( WHA::ETkipGroupKey ); + + // allocate memory for the key structure + WHA::STkipGroupKey* key = static_cast + (os_alloc( sizeof(WHA::STkipGroupKey) )); + + if ( !key ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::AddMulticastTKIPKey: memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + os_memcpy( key->iTkipKey, aData, WHA::KTKIPKeyLength ); + os_memcpy( key->iRxMicKey, aData + WHA::KTKIPKeyLength, KMicLength ); + key->iKeyId = static_cast(aKeyIndex); + // for now we fill this field with zeroes + os_memset( key->iRxSequenceCounter, 0, WHA::KRxSequenceCounterLength ); + + WlanWsaAddKey& wsa_cmd = aCtxImpl.WsaAddKey(); + + wsa_cmd.Set( aCtxImpl, + WHA::ETkipGroupKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::ETkipGroupKey ) ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // allways remember to release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddAesKey( + WlanContextImpl& aCtxImpl, + const TUint8* aData, + TUint32 /*aLength*/, + const TMacAddress& aMacAddr ) + { + TBool ret( EFalse ); + WlanWsaAddKey& wsa_cmd( aCtxImpl.WsaAddKey() ); + WHA::SAesPairwiseKey* key( CreateAesPtkCtx( + aCtxImpl, + wsa_cmd, + aData, + aMacAddr ) + ); + + if ( key ) + { + ret = ETrue; + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // allways remember to release the memory + } + else + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddAesKey(): memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddMulticastAesKey( + WlanContextImpl& aCtxImpl, + T802Dot11WepKeyId aKeyIndex, + TUint32 /*aLength*/, + const TUint8* aData ) + { + // store info of AES GTK insertion + aCtxImpl.GroupKeyType( WHA::EAesGroupKey ); + + // allocate memory for the key structure + WHA::SAesGroupKey* key = static_cast + ( os_alloc( sizeof( WHA::SAesGroupKey ) ) ); + + if ( !key ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddMulticastAesKey(): memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + os_memcpy( key->iAesKey, aData, WHA::KAesKeyLength ); + key->iKeyId = static_cast(aKeyIndex); + // for now we fill this field with zeroes + os_memset( key->iRxSequenceCounter, 0, WHA::KRxSequenceCounterLength ); + + WlanWsaAddKey& wsa_cmd = aCtxImpl.WsaAddKey(); + + wsa_cmd.Set( aCtxImpl, + WHA::EAesGroupKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EAesGroupKey ) ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // allways remember to release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddUnicastWepKey( + WlanContextImpl& aCtxImpl, + const TMacAddress& aMacAddr, + TUint32 aKeyLength, + const TUint8 aKey[KMaxWEPKeyLength]) + { + // store info of WEP PTK insertion + aCtxImpl.PairWiseKeyType( WHA::EWepPairWiseKey ); + + // allocate memory for the key structure + WHA::SWepPairwiseKey* key = static_cast + (os_alloc( WHA::SWepPairwiseKey::KHeaderSize + aKeyLength )); + + if ( !key ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddUnicastWepKey(): memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + os_memcpy( + &(key->iMacAddr), + aMacAddr.iMacAddress, + sizeof(key->iMacAddr) ); + key->iKeyLengthInBytes = static_cast(aKeyLength); + os_memcpy( key->iKey, aKey, key->iKeyLengthInBytes ); + + WlanWsaAddKey& wsa_cmd = aCtxImpl.WsaAddKey(); + wsa_cmd.Set( aCtxImpl, + WHA::EWepPairWiseKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EWepPairWiseKey ) ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // allways remember to release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::OnAddBroadcastWepKey( + WlanContextImpl& aCtxImpl, + TUint32 aKeyIndex, + TBool aUseAsDefaulKey, + TBool aUseAsPairwiseKey, + TUint32 aKeyLength, + const TUint8 aKey[KMaxWEPKeyLength], + const TMacAddress& aMac ) + { + WlanAddBroadcastWepKey& complex_wha_cmd( + aCtxImpl.AddBroadcastWepKey() ); + + complex_wha_cmd.Set( aMac, aKeyIndex, aUseAsDefaulKey, + aUseAsPairwiseKey, aKeyLength, aKey ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + complex_wha_cmd // next state + ); + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddMulticastWapiKey( + WlanContextImpl& aCtxImpl, + T802Dot11WepKeyId aKeyIndex, + TUint32 /*aLength*/, + const TUint8* aData ) + { + if ( !(aCtxImpl.WHASettings().iCapability & WHA::SSettings::KWapi) ) + { + // WAPI not supported by wlanpdd => abort key setting + + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddMulticastWapiKey: WAPI not supported by wlanpdd -> abort") ); + + OnOidComplete( aCtxImpl, KErrNotSupported ); + return EFalse; + } + + // store info of WAPI group key insertion + aCtxImpl.GroupKeyType( WHA::EWapiGroupKey ); + + // allocate memory for the key structure + WHA::SWapiGroupKey* key = static_cast + (os_alloc( sizeof(WHA::SWapiGroupKey) )); + + if ( !key ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::AddMulticastWapiKey: memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + os_memcpy( key->iWapiKey, aData, WHA::KWapiKeyLength ); + + os_memcpy( + key->iMicKey, + aData + WHA::KWapiKeyLength, + WHA::KWapiMicKeyLength ); + + key->iKeyId = static_cast(aKeyIndex); + + WlanWsaAddKey& wsa_cmd = aCtxImpl.WsaAddKey(); + + wsa_cmd.Set( aCtxImpl, + WHA::EWapiGroupKey, + key, + WlanWsaKeyIndexMapper::Extract( WHA::EWapiGroupKey ) ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // release the memory + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::AddUnicastWapiKey( + WlanContextImpl& aCtxImpl, + const TUint8* aData, + TUint32 /*aLength*/, + T802Dot11WepKeyId aKeyIndex, + const TMacAddress& aMacAddr ) + { + TBool ret( EFalse ); + + if ( !(aCtxImpl.WHASettings().iCapability & WHA::SSettings::KWapi) ) + { + // WAPI not supported by wlanpdd => abort key setting + + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddUnicastWapiKey: WAPI not supported by wlanpdd -> abort") ); + + OnOidComplete( aCtxImpl, KErrNotSupported ); + return ret; + } + + WlanWsaAddKey& wsa_cmd( aCtxImpl.WsaAddKey() ); + + WHA::SWapiPairwiseKey* key( CreateWapiPtkCtx( + aCtxImpl, + wsa_cmd, + aData, + aKeyIndex, + aMacAddr ) + ); + + if ( key ) + { + ret = ETrue; + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( key ); // release the memory + } + else + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::AddUnicastWapiKey: memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + return ret; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::InitNetworkConnect( + WlanContextImpl& aCtxImpl, + TUint16 aScanResponseFrameBodyLength, + const TUint8* aScanResponseFrameBody ) const + { + OsTracePrint( KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::InitNetworkConnect") ); + + const SScanResponseFixedFields* scanResponseFixedFields = + reinterpret_cast( + aScanResponseFrameBody ); + + // store capability info from scan response frame body to our context + aCtxImpl.GetCapabilityInformation() + = scanResponseFixedFields->iCapability.CapabilityInformationField(); + + // and set it also as the initial value to our association request frame + // templates + aCtxImpl.GetAssociationRequestFrame().iFixedFields.iCapabilityInfo + = aCtxImpl.GetCapabilityInformation(); + aCtxImpl.GetHtAssociationRequestFrame().iFixedFields.iCapabilityInfo + = aCtxImpl.GetCapabilityInformation(); + + // ... and to to our reassociation request frame templates + aCtxImpl.GetReassociationRequestFrame().iFixedFields.iCapabilityInfo + = aCtxImpl.GetCapabilityInformation(); + aCtxImpl.GetHtReassociationRequestFrame().iFixedFields.iCapabilityInfo + = aCtxImpl.GetCapabilityInformation(); + + // use short slot time if supported by the network + aCtxImpl.UseShortSlotTime( + aCtxImpl.GetCapabilityInformation().IsShortSlotTimeBitSet() ); + + //============================================= + // check for WAPI + //============================================= + if ( aCtxImpl.EncryptionStatus() == EEncryptionWAPI && + !(aCtxImpl.WHASettings().iCapability & WHA::SSettings::KWapi) ) + { + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: WAPI requested but not supported by wlanpdd -> abort") ); + + return EFalse; + } + + //============================================= + // do we meet network capability requirements + //============================================= + + if ( !NetworkCapabilityInformationMet( aCtxImpl ) ) + { + // requirements not met + + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: network capabilities not met -> abort") ); + + return EFalse; + } + + // network capabilities are met -> proceed + + + // initialize element locator for locating IEs from the scan response + // frame body + WlanElementLocator elementLocator( + reinterpret_cast( scanResponseFixedFields + 1 ), + aScanResponseFrameBodyLength - + sizeof( SScanResponseFixedFields ) ); + + TUint8 elementDatalength( 0 ); + const TUint8* elementData( NULL ); + + //============================================= + // do we meet mandatory network rates + //============================================= + + // locate supported rates IE + if ( elementLocator.InformationElement( + E802Dot11SupportedRatesIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // ...and store it to our context + aCtxImpl.GetApSupportedRatesIE().SetIeData( + elementData, + elementDatalength ); + } + else + { + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: supported rates IE not found -> abort") ); + + return EFalse; + } + + // locate extended supported rates information element + if ( elementLocator.InformationElement( + E802Dot11ExtendedRatesIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: E802Dot11ExtendedRatesIE present") ); + + // ...and store it to our context + aCtxImpl.GetApExtendedSupportedRatesIE().SetIeData( elementData, elementDatalength ); + + // check if we meet mandatory rates; in this case check also extended supported rates + if ( !AreSupportedRatesMet( aCtxImpl, ETrue ) ) + { + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: rates not met -> abort") ); + + return EFalse; + } + } + else + { + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: E802Dot11ExtendedRatesIE not present") ); + + // check if we meet mandatory rates; in this case extended supported rates + // don't need to be checked + if ( !AreSupportedRatesMet( aCtxImpl, EFalse ) ) + { + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::InitNetworkConnect: rates not met -> abort") ); + + return EFalse; + } + } + + // mandatory network rates are met -> proceed + + //============================================= + // determine the channel of the network + //============================================= + + // locate DS parameter set information element + if ( elementLocator.InformationElement( + E802Dot11DsParameterSetIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // ...and store it to our context + aCtxImpl.NetworkChannelNumeber( *elementData ); + } + else + { + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: 802Dot11DsParameterSetIE not found -> abort") ); + + return EFalse; + } + + //============================================= + // determine the beacon interval of the network + //============================================= + + const TUint32 beacon_interval = scanResponseFixedFields->BeaconInterval(); + + if ( beacon_interval ) + { + // ...and store it to our context + aCtxImpl.NetworkBeaconInterval( beacon_interval ); + } + else + { + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::InitNetworkConnect: zero beacon interval -> abort") ); + + return EFalse; + } + + //============================================= + // determine the need to use protection + //============================================= + + // locate ERP information element + if ( elementLocator.InformationElement( + E802Dot11ErpInformationIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // ERP IE present -> set the protection level according to the Use + // Protection bit + aCtxImpl.ProtectionBitSet( *elementData & KUseProtectionMask ); + // make also a note of ERP IE presence, which means that the nw in + // question is a 802.11a/g nw (instead of a 802.11b nw) + aCtxImpl.ErpIePresent( ETrue ); + } + else + { + // ERP IE not present + aCtxImpl.ProtectionBitSet( EFalse ); + } + + if ( aCtxImpl.NetworkOperationMode() == WHA::EBSS ) + { + //============================================= + // + // only for infrastructure mode connections + // + //============================================= + + //============================================= + // determine WMM / QoS information + //============================================= + + // locate WMM information element + if ( elementLocator.InformationElement( + E802Dot11VendorSpecificIE, + KWmmElemOui, + KWmmElemOuiType, + KWmmInfoElemOuiSubType, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // WMM IE present + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: WMM IE present")); + + EnableQos( aCtxImpl, UapsdEnabledInNetwork( + reinterpret_cast( *elementData ) ) ); + + // as there are no WMM parameter values available in the WMM IE + // use the default AC parameter values until we get the values + // in (re)association response + ResetAcParameters( aCtxImpl, aCtxImpl.ErpIePresent() ); + } + else + { + // WMM IE not present. Check if WMM Parameter Element exists instead + if ( elementLocator.InformationElement( + E802Dot11VendorSpecificIE, + KWmmElemOui, + KWmmElemOuiType, + KWmmParamElemOuiSubtype, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // WMM Parameter Element present + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: WMM param elem present")); + + EnableQos( aCtxImpl, UapsdEnabledInNetwork( + reinterpret_cast( *elementData ) ) ); + + // as the parameter element is present, use the opportunity to + // parse the AC (QoS) parameters. + // However, reset them 1st to their default values in case + // the nw would provide values for some AC multiple times and + // leave the parameters for some AC unspecified + // + ResetAcParameters( aCtxImpl, aCtxImpl.ErpIePresent() ); + ParseAcParameters( aCtxImpl, + reinterpret_cast( *elementData ) ); + } + else + { + // WMM Parameter Element not present either => no QoS, no U-APSD + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: neither WMM IE nor WMM param elem present")); + + aCtxImpl.QosEnabled( EFalse ); + aCtxImpl.UapsdEnabled( EFalse ); + } + } + + //================================================================= + // perform 802.11n related actions & checks if lower layer supports + // HT operation + //================================================================= + + if ( aCtxImpl.WHASettings().iCapability & WHA::SSettings::KHtOperation ) + { + if ( !HandleDot11n( aCtxImpl,elementLocator ) ) + { + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: Nw's 802.11n requirements not met -> abort") ); + + return EFalse; + } + } + else + { + // lower layer doesn't support HT, so we must handle the network + // as a non-HT network + aCtxImpl.HtSupportedByNw( EFalse ); + } + } + else + { + //============================================= + // + // only for IBSS mode connections + // + // ============================================ + + //============================================= + // determine ATIM window + //============================================= + + // locate IBSS Parameter Set element + if ( elementLocator.InformationElement( + E802Dot11IbssParameterSetIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // store it to our context + + // note that elementData points to the IE data and not the + // preceding IE header. That's why we need to back up the pointer + // by SInformationElementHeader length before doing the cast + aCtxImpl.AtimWindow( + ( reinterpret_cast( + elementData - sizeof( SInformationElementHeader ) ) + )->AtimWindow() ); + } + else + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::InitNetworkConnect: atim not present, PS not used")); + + // as IBSS Parameter Set element is not present, power saving + // is not used in the IBSS network we are going to join. So we + // will set the ATIM window to zero (to denote that PS is not used) + aCtxImpl.AtimWindow( 0 ); + } + } + + //============================================= + // determine U-APSD usage for the ACs/Tx queues + //============================================= + DetermineAcUapsdUsage( aCtxImpl ); + + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::SetTxPowerLevel( + WlanContextImpl& aCtxImpl, + TUint32 aLevel) + { + OsTracePrint( + KUmacDetails, + (TUint8*) + ("UMAC: WlanDot11State::SetTxPowerLevel(): aLevel: %d"), + aLevel ); + + // allocate memory for the mib to write + WHA::Sdot11CurrentTxPowerLevel* mib + = static_cast + (os_alloc( sizeof(WHA::Sdot11CurrentTxPowerLevel) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC * SetRcpiTriggerLevel * abort") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + mib->iDot11CurrentTxPowerLevel = aLevel; + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, + WHA::KMibDot11CurrentTxPowerLevel, + sizeof(*mib), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( mib ); // always remember to release the memory + + // store the new power level also to our soft mib + aCtxImpl.iWlanMib.dot11CurrentTxPowerLevel = aLevel; + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::GetLastRcpi( + WlanContextImpl& aCtxImpl ) + { + TBool statechange ( EFalse ); + WHA::TRcpi whaRcpi( 0 ); + + if ( aCtxImpl.GetLatestMedianRcpiFromPredictor( os_systemTime(), whaRcpi ) ) + { + // we have a median filtered RCPI value available so we can return that + // directly to WLAN Mgmt Client + + // convert to a 32bit value before returning + const TInt32 rcpi ( whaRcpi ); + + OnOidComplete( aCtxImpl, + KErrNone, + reinterpret_cast(&rcpi), + sizeof( rcpi ) ); + } + else + { + // we need to get the RCPI from lower layers + + WlanWsaReadMib& wha_cmd = aCtxImpl.WsaReadMib(); + wha_cmd.Set( aCtxImpl, WHA::KMibStatisticsTable ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // previous state + wha_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + // signal caller that a state transition occurred + statechange = ETrue; + } + + return statechange; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::OnPacketTransferComplete( + WlanContextImpl& aCtxImpl, + TUint32 aPacketId, + TDataBuffer* aMetaHeader ) + { + // complete the transfer + if ( aPacketId == E802Dot11FrameTypeData ) + { + OnTxProtocolStackDataComplete( aCtxImpl, aMetaHeader ); + } + else if ( aPacketId == E802Dot11FrameTypeDataEapol || + aPacketId == E802Dot11FrameTypeManagementAction || + aPacketId == E802Dot11FrameTypeTestFrame ) + { + OnMgmtPathWriteComplete( aCtxImpl ); + + aCtxImpl.iUmac.OnOtherTxDataComplete(); + } + 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(); + + aCtxImpl.iUmac.OnOtherTxDataComplete(); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::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*/ ) + { + aCtxImpl.OnTxCompleted( aRate, + static_cast(aStatus == WHA::KSuccess), + aQueueId, + aRequestedRate ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::CallPacketSchedule( + WlanContextImpl& aCtxImpl, + TBool aMore ) + { + aCtxImpl.SchedulePackets( aMore ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::OnPacketFlushEvent( + WlanContextImpl& aCtxImpl, + TUint32 aPacketId, + TDataBuffer* aMetaHeader ) + { + if ( aPacketId == E802Dot11FrameTypeData ) + { + OnTxProtocolStackDataComplete( aCtxImpl, aMetaHeader ); + } + else if ( aPacketId == E802Dot11FrameTypeDataEapol || + aPacketId == E802Dot11FrameTypeManagementAction || + aPacketId == E802Dot11FrameTypeTestFrame ) + { + // complete with an error code if WLAN Mgmt Client frame + // transmit fails + OnMgmtPathWriteComplete( aCtxImpl, KErrGeneral ); + } + 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 there's + // nothing to complete upwards. But we need to mark the internal + // Tx buffer free again + aCtxImpl.MarkInternalTxBufFree(); + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::OnPacketPushPossible( + WlanContextImpl& /*aCtxImpl*/ ) + { + // intentionally left empty + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::Indication( + WlanContextImpl& aCtxImpl, + WHA::TIndicationId aIndicationId, + const WHA::UIndicationParams& aIndicationParams ) + { + switch ( aIndicationId ) + { + case WHA::EError: + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WHA error indication received!") ); + DoErrorIndication( aCtxImpl, aIndicationParams.iError.iStatus ); + break; + case WHA::EBssLost: + DoConsecutiveBeaconsLostIndication( aCtxImpl ); + break; + case WHA::EBSSRegained: + DoRegainedBSSIndication( aCtxImpl ); + break; + case WHA::ERadar: + DoRadarIndication( aCtxImpl ); + break; + case WHA::ERcpi: + DoRcpiIndication( aCtxImpl, aIndicationParams.iRcpi.iRcpi ); + break; + case WHA::EPsModeError: + DoPsModeErrorIndication( aCtxImpl ); + break; + default: + // implementation error + OsTracePrint( KErrorLevel, + (TUint8*)("UMAC: aIndicationId: %d"), aIndicationId ); + OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + break; + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureTxQueue( + WlanContextImpl& aCtxImpl, + WHA::TQueueId aQueueId, + TBool aCompleteManagementRequest ) + { + OsTracePrint( KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::ConfigureTxQueue: aQueueId: %d"), + aQueueId ); + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureTxQueue: aCompleteManagementRequest: %d"), + aCompleteManagementRequest ); + + WHA::TPsScheme psScheme( WHA::ERegularPs ); + + // enable U-APSD for the AC/Queue in question when necessary. + // Otherwise stick to regular PS + switch ( aQueueId ) + { + case WHA::ELegacy: + if ( aCtxImpl.UapsdUsedForBestEffort() ) + { + psScheme = WHA::EUapsd; + } + break; + case WHA::EBackGround: + if ( aCtxImpl.UapsdUsedForBackground() ) + { + psScheme = WHA::EUapsd; + } + break; + case WHA::EVideo: + if ( aCtxImpl.UapsdUsedForVideo() ) + { + psScheme = WHA::EUapsd; + } + break; + case WHA::EVoice: + if ( aCtxImpl.UapsdUsedForVoice() ) + { + psScheme = WHA::EUapsd; + } + break; + default: + // catch programming error + OsTracePrint( KErrorLevel, (TUint8*) + ("UMAC: ERROR: unsupported queue, aQueueId: %d"), aQueueId ); + OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); + } + + WlanWhaConfigureQueue& wha_command = aCtxImpl.WhaConfigureQueue(); + + wha_command.Set( + aQueueId, + aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[aQueueId], + psScheme, + WHA::ENormal, + aCtxImpl.iWlanMib.iMediumTime[aQueueId] ); + + const TUint32 KNoNeedToCompleteManagementRequest = 0; + + // change global state: entry procedure triggers action + ChangeState( + aCtxImpl, + *this, // prev state + wha_command, // next state + aCompleteManagementRequest ? KCompleteManagementRequest : + KNoNeedToCompleteManagementRequest ); + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureAcParams( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( + KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::ConfigureAcParams") ); + + WlanWhaConfigureAc& wha_command = aCtxImpl.WhaConfigureAc(); + + wha_command.Set( + aCtxImpl.CwMinVector(), + aCtxImpl.CwMaxVector(), + aCtxImpl.AifsVector(), + aCtxImpl.TxOplimitVector() ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_command // next state + ); + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::SetCtsToSelfMib( + WlanContextImpl& aCtxImpl ) + { + WHA::SctsToSelf* mib + = static_cast + (os_alloc( sizeof( WHA::SctsToSelf ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, (TUint8*) + ("UMAC: WlanDot11State::SetCtsToSelfMib(): memory allocation failed") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + if ( aCtxImpl.ProtectionBitSet() ) + { + OsTracePrint( + KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::SetCtsToSelfMib(): enable CTS to self") ); + + mib->iCtsToSelf = ETrue; + } + else + { + OsTracePrint( + KUmacDetails, + (TUint8*)("UMAC: WlanDot11State::SetCtsToSelfMib(): disable CTS to self") ); + + mib->iCtsToSelf = EFalse; + } + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + wha_cmd.Set( + aCtxImpl, WHA::KMibCtsToSelf, sizeof(*mib), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd // next state + ); + + // as the parameters have been supplied we can now deallocate + os_free( mib ); + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureBssLost( + WlanContextImpl& aCtxImpl, + TUint32 aBeaconLostCount, + TUint8 aFailedTxPacketCount ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureBssLost") ); + + // store & take the new failed Tx packet count threshold into use + aCtxImpl.iWlanMib.iFailedTxPacketCountThreshold = aFailedTxPacketCount; + // set the beacon lost count mib + return SetBeaconLostCountMib( aCtxImpl, aBeaconLostCount ); + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::SetTxRateAdaptParams( + WlanContextImpl& aCtxImpl, + TUint8 aMinStepUpCheckpoint, + TUint8 aMaxStepUpCheckpoint, + TUint8 aStepUpCheckpointFactor, + TUint8 aStepDownCheckpoint, + TUint8 aMinStepUpThreshold, + TUint8 aMaxStepUpThreshold, + TUint8 aStepUpThresholdIncrement, + TUint8 aStepDownThreshold, + TBool aDisableProbeHandling ) + { + aCtxImpl.SetTxRateAdaptationAlgorithmParams( + aMinStepUpCheckpoint, + aMaxStepUpCheckpoint, + aStepUpCheckpointFactor, + aStepDownCheckpoint, + aMinStepUpThreshold, + aMaxStepUpThreshold, + aStepUpThresholdIncrement, + aStepDownThreshold, + aDisableProbeHandling ); + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// --------------------------------------------------------------------------- +// At this point we only store the provided configuration data. It will be +// taken into use when we know the nw we are going to join - i.e. just prior +// actually joining that nw +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureTxRatePolicies( + WlanContextImpl& aCtxImpl, + const TTxRatePolicy& aRatePolicy, + const TQueue2RateClass& aQueue2RateClass, + const TInitialMaxTxRate4RateClass& aInitialMaxTxRate4RateClass, + const TTxAutoRatePolicy& aAutoRatePolicy, + const THtMcsPolicy& aHtMcsPolicy ) + { + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ConfigureTxRatePolicies")); + + StoreTxRatePolicyInfo( + aCtxImpl, + aRatePolicy, + aQueue2RateClass, + aInitialMaxTxRate4RateClass, + aAutoRatePolicy, + aHtMcsPolicy ); + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::SetPowerModeManagementParameters( + WlanContextImpl& aCtxImpl, + TUint32 aToLightPsTimeout, + TUint16 aToLightPsFrameThreshold, + TUint32 aToActiveTimeout, + TUint16 aToActiveFrameThreshold, + TUint32 aToDeepPsTimeout, + TUint16 aToDeepPsFrameThreshold, + TUint16 aUapsdRxFrameLengthThreshold ) + { + aCtxImpl.SetPowerModeManagementParameters( + aToLightPsTimeout, + aToLightPsFrameThreshold, + aToActiveTimeout, + aToActiveFrameThreshold, + aToDeepPsTimeout, + aToDeepPsFrameThreshold, + aUapsdRxFrameLengthThreshold ); + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigurePwrModeMgmtTrafficOverride( + WlanContextImpl& aCtxImpl, + TBool aStayInPsDespiteUapsdVoiceTraffic, + TBool aStayInPsDespiteUapsdVideoTraffic, + TBool aStayInPsDespiteUapsdBestEffortTraffic, + TBool aStayInPsDespiteUapsdBackgroundTraffic, + TBool aStayInPsDespiteLegacyVoiceTraffic, + TBool aStayInPsDespiteLegacyVideoTraffic, + TBool aStayInPsDespiteLegacyBestEffortTraffic, + TBool aStayInPsDespiteLegacyBackgroundTraffic ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigurePwrModeMgmtTrafficOverride")); + + aCtxImpl.ConfigurePwrModeMgmtTrafficOverride( + aStayInPsDespiteUapsdVoiceTraffic, + aStayInPsDespiteUapsdVideoTraffic, + aStayInPsDespiteUapsdBestEffortTraffic, + aStayInPsDespiteUapsdBackgroundTraffic, + aStayInPsDespiteLegacyVoiceTraffic, + aStayInPsDespiteLegacyVideoTraffic, + aStayInPsDespiteLegacyBestEffortTraffic, + aStayInPsDespiteLegacyBackgroundTraffic ); + + // Note, that in this case the dynamic power mode mgmt traffic + // override/ignoration settings will be frozen later (during connect + // operation, once we know the network capabilites) so that they become + // effective + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::GetFrameStatistics( WlanContextImpl& aCtxImpl ) + { + WlanWsaReadMib& wha_cmd = aCtxImpl.WsaReadMib(); + wha_cmd.Set( aCtxImpl, WHA::KMibCountersTable ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // previous state + wha_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + // signal caller that state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// At this point we only store the values provided by WLAN mgmt client. They +// will be used later when we (re-)associate to an AP. +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureUapsd( + WlanContextImpl& aCtxImpl, + TMaxServicePeriodLength aMaxServicePeriodLength, + TBool aUapsdForVoice, + TBool aUapsdForVideo, + TBool aUapsdForBestEffort, + TBool aUapsdForBackground ) + { + // this cast is safe as the types are effectively the same + aCtxImpl.UapsdMaxSpLen() = + static_cast(aMaxServicePeriodLength); + + aCtxImpl.UapsdRequestedForVoice( aUapsdForVoice ); + aCtxImpl.UapsdRequestedForVideo( aUapsdForVideo ); + aCtxImpl.UapsdRequestedForBestEffort( aUapsdForBestEffort ); + aCtxImpl.UapsdRequestedForBackground( aUapsdForBackground ); + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::GetMacAddress( + WlanContextImpl& aCtxImpl ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::GetMacAddress: mac address:"), + aCtxImpl.iWlanMib.dot11StationId ); + + OnOidComplete( + aCtxImpl, + KErrNone, + &(aCtxImpl.iWlanMib.dot11StationId), + sizeof(aCtxImpl.iWlanMib.dot11StationId) ); + + // signal caller that no state transition occurred + return EFalse; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureArpIpAddressFiltering( + WlanContextImpl& aCtxImpl, + TBool aEnableFiltering, + TIpv4Address aIpv4Address ) + { + return SetArpIpAddressTableMib( + aCtxImpl, + aEnableFiltering, + aIpv4Address ); + } + +// ----------------------------------------------------------------------------- +// At this point we only store the provided configuration. +// It will be passed to the lower layers when connecting to a HT network +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureHtBlockAck( + WlanContextImpl& aCtxImpl, + TUint8 aTxBlockAckUsage, + TUint8 aRxBlockAckUsage ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureHtBlockAck()") ); + + WHA::ShtBlockAckConfigure& blockAckConf ( + aCtxImpl.GetHtBlockAckConfigure() ); + blockAckConf.iTxBlockAckUsage = aTxBlockAckUsage; + blockAckConf.iRxBlockAckUsage = aRxBlockAckUsage; + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureProprietarySnapHdr( + WlanContextImpl& aCtxImpl, + const TSnapHeader& aSnapHeader ) + { + OsTracePrint( KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::ConfigureProprietarySnapHdr") ); + + // store the provided SNAP header for later use + os_memcpy( + reinterpret_cast(&(aCtxImpl.GetProprietarySnapHeader())), + reinterpret_cast(&aSnapHeader), + sizeof( SSnapHeader ) ); + + OnOidComplete( aCtxImpl, KErrNone ); + + // signal caller that no state transition occurred + return EFalse; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::SetBeaconLostCountMib( + WlanContextImpl& aCtxImpl, + TUint32 aBeaconLostCount ) + { + OsTracePrint( + KUmacDetails, (TUint8*) + ("UMAC: WlanDot11State::SetBeaconLostCountMib(): aBeaconLostCount: %d"), + aBeaconLostCount ); + + // allocate memory for the mib to write + WHA::SbeaconLostCount* mib + = static_cast + (os_alloc( sizeof( WHA::SbeaconLostCount ) )); + + if ( !mib ) + { + // allocation failed + // simulate macnotresponding error + OsTracePrint( KWarningLevel, + (TUint8*)("UMAC: WlanDot11State::SetBeaconLostCountMib: abort") ); + return DoErrorIndication( aCtxImpl, WHA::KErrorMacNotResponding ); + } + + mib->iLostCount = aBeaconLostCount; + + WlanWsaWriteMib& wha_cmd = aCtxImpl.WsaWriteMib(); + + wha_cmd.Set( + aCtxImpl, + WHA::KMibBeaconLostCount, + sizeof(*mib), mib ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wha_cmd, // next state + // the ACT + KCompleteManagementRequest + ); + + os_free( mib ); // always remember to release the memory + + // store the new beacon lost count also to our soft mib + aCtxImpl.iWlanMib.iBeaconLostCount = aBeaconLostCount; + + // signal caller that a state transition occurred + return ETrue; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ResortToSingleTxRatePolicy( + WlanContextImpl& aCtxImpl, + TTxRatePolicy& aRatePolicy, + TQueue2RateClass& aQueue2RateClass ) const + { + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ResortToSingleTxRatePolicy: WARNING: PDD " + "supports only %d policy objects ... "), + aCtxImpl.WHASettings().iNumOfTxRateClasses ); + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: ... and %d objects have been provided to us"), + aRatePolicy.numOfPolicyObjects ); + + // In this case - from the rate classes / autorate policies provided to + // us by WLAN Mgmt client - we will use only the rate class / autorate + // policy specified for legacy Tx Queue / AC, i.e. the 1st one at index 0 + + aRatePolicy.numOfPolicyObjects = 1; + for ( TUint queueId = ELegacy; queueId < EQueueIdMax; ++queueId ) + { + aQueue2RateClass[queueId] = 0; + } + +#ifndef NDEBUG + if ( (aCtxImpl.Queue2RateClass())[ELegacy] != 0 ) + { + OsTracePrint( KErrorLevel | KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ResortToSingleTxRatePolicy: ERROR: policy " + "for legacy not specified as the 1st in the policy array") ); + OsAssert( (TUint8*)("UMAC: panic"), + (TUint8*)(WLAN_FILE), __LINE__ ); + } +#endif + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::FinalizeTxRatePolicy( + WlanContextImpl& aCtxImpl, + TTxRatePolicy& aRatePolicy, + TWhaRateMasks& aRateMasks, + TInitialMaxTxRate4RateClass& aInitialMaxTxRate4RateClass ) const + { + for ( TUint rateClassInd = 0; + rateClassInd < aRatePolicy.numOfPolicyObjects; + ++rateClassInd ) + { + // build a rate mask as an "intersection" of + // rates in the provided rate class AND + // rates supported by the nw and AND + // rates supported by WHA layer. + // Also keep the nbr of tx attempts in the rate class for a particular + // rate if that rate is supported by both the nw and WHA layer. + // Otherwise set the nbr of tx attemps to zero for that rate + + HandleRates( + aCtxImpl, + aRatePolicy.txRateClass[rateClassInd], + aRateMasks[rateClassInd] ); + + if ( !( aRateMasks[rateClassInd] ) ) + { + // the provided rate class was such that we ended up with an empty + // rate mask. To recover from this situation we will update the + // rate class definition on the fly to contain the rates which both + // the WHA layer and the nw support + RecoverRatePolicy( + aCtxImpl, + aRatePolicy, + rateClassInd, + aRateMasks[rateClassInd] ); + // adjust also the Max Tx Rate for this rate class so that the + // highest possible rate will be used initially + aInitialMaxTxRate4RateClass[rateClassInd] = WHA::KRate54Mbits; + } + } // for + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::HandleRate( + WlanContextImpl& aCtxImpl, + WHA::TRate aRate, + TUint8& aTxAttempts, + WHA::TRate& aRateMask ) const + { + if ( aCtxImpl.RateBitMask() & aRate ) + { + // rate is supported both by us and by the nw. + + if ( aTxAttempts ) + { + // non-zero Tx attempts defined => include the rate in dynamic Tx + // rate adaptation rates + aRateMask |= aRate; + } + } + else + { + // rate is not supported either by us or by the nw. Set zero Tx attempts + aTxAttempts = 0; + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::HandleRates( + WlanContextImpl& aCtxImpl, + TTxRateClass& aRateClass, + WHA::TRate& aRateMask ) const + { + HandleRate( aCtxImpl, WHA::KRate54Mbits, aRateClass.txPolicy54, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate48Mbits, aRateClass.txPolicy48, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate36Mbits, aRateClass.txPolicy36, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate33Mbits, aRateClass.txPolicy33, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate24Mbits, aRateClass.txPolicy24, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate22Mbits, aRateClass.txPolicy22, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate18Mbits, aRateClass.txPolicy18, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate12Mbits, aRateClass.txPolicy12, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate11Mbits, aRateClass.txPolicy11, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate9Mbits, aRateClass.txPolicy9, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate6Mbits, aRateClass.txPolicy6, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate5_5Mbits, aRateClass.txPolicy5_5, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate2Mbits, aRateClass.txPolicy2, + aRateMask ); + + HandleRate( aCtxImpl, WHA::KRate1Mbits, aRateClass.txPolicy1, + aRateMask ); + + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::HandleRates: resulting rate mask: 0x%08x"), + aRateMask ); + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::RecoverRatePolicy( + WlanContextImpl& aCtxImpl, + TTxRatePolicy& aRatePolicy, + TUint aRateClassInd, + WHA::TRate& aRateMask ) const + { + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::RecoverRatePolicy: aRateClassInd: %d"), + aRateClassInd ); + + const TUint8 KTxAttempts = 1; + + // start with Tx attempts == 1 for all Tx rates + os_memset( + &aRatePolicy.txRateClass[aRateClassInd], + KTxAttempts, + sizeof( TUint8 ) * KMaxNumberOfDot11bAndgRates ); + + HandleRates( aCtxImpl, aRatePolicy.txRateClass[aRateClassInd], aRateMask ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::FinalizeTxAutoratePolicy( + WlanContextImpl& aCtxImpl, + const TTxRatePolicy& aRatePolicy, + TTxAutoRatePolicy& aAutoRatePolicy ) const + { + for ( TUint rateClassInd = 0; + rateClassInd < aRatePolicy.numOfPolicyObjects; + ++rateClassInd ) + { + // build a rate mask as an "intersection" of + // rates in the provided auto rate class AND + // rates supported by the nw and AND + // rates supported by WHA layer. + aAutoRatePolicy[rateClassInd] = + aAutoRatePolicy[rateClassInd] & aCtxImpl.RateBitMask(); + + if ( !( aAutoRatePolicy[rateClassInd] ) ) + { + // the provided rate class was such that we ended up with an + // empty rate mask. To recover from this situation we will + // update the rate class definition on the fly to contain + // the rates which both the WHA layer and the nw support + aAutoRatePolicy[rateClassInd] = aCtxImpl.RateBitMask(); + } + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::SpecialTxAutoratePolicy( + WlanContextImpl& aCtxImpl, + TTxRatePolicy& aRatePolicy, + TTxAutoRatePolicy& aAutoRatePolicy, + THtMcsPolicy& aHtMcsPolicy ) const + { + if ( aRatePolicy.numOfPolicyObjects >= + aCtxImpl.WHASettings().iNumOfTxRateClasses ) + { + // there's no room in the lower layers for a special policy + // disable special policy use + aCtxImpl.SpecialTxAutoRatePolicy( 0 ); + + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::SpecialTxAutoratePolicy: no room") ); + + return; + } + + const TUint KMaxNbrOfItemsToPick(1); + + // start with an empty rate mask + aAutoRatePolicy[aRatePolicy.numOfPolicyObjects] = 0; + + const WHA::TRate commonRates( aCtxImpl.RateBitMask() ); + + // pick the 802.11b/g rate(s) for the special policy + + WHA::TRate rate( WHA::KRate1Mbits ); + TUint cntPicked(0); + do + { + if ( rate & commonRates ) + { + aAutoRatePolicy[aRatePolicy.numOfPolicyObjects] |= rate; + ++cntPicked; + } + + rate <<= 1; + } while ( ( cntPicked < KMaxNbrOfItemsToPick ) && + ( rate <= KRate54Mbits ) ); + + // start with an empty MCS set + for ( TUint mcsBucket = 0; + mcsBucket < WHA::KHtMcsSetLength; + ++mcsBucket ) + { + aHtMcsPolicy[aRatePolicy.numOfPolicyObjects][mcsBucket] = 0; + } + + // pick the 802.11n MCS(s) for the special policy + + const SHtCapabilitiesIE& htCapabilitiesIe( + aCtxImpl.GetNwHtCapabilitiesIe() ); + const TUint KLastMcsBucket = WHA::KHtMcsSetLength - 1; + const TUint8 KMcsCountInLastBucket( 5 ); + TUint8 mcsCount( 8 ); + + cntPicked = 0; + TUint mcsBucket = 0; + do + { + if ( mcsBucket == KLastMcsBucket ) + { + // there are only 5 MCSs in the last "bucket" per 802.11n std. + mcsCount = KMcsCountInLastBucket; + } + + TUint8 mcs(1); + TUint mcsCounter( 0 ); + do + { + if ( mcs & + ( aCtxImpl.WHASettings().iHtCapabilities.iTxMcs[mcsBucket] ) & + ( htCapabilitiesIe.iData.iRxMcsBitmask[mcsBucket] ) ) + { + aHtMcsPolicy[aRatePolicy.numOfPolicyObjects][mcsBucket] |= mcs; + ++cntPicked; + } + + mcs <<= 1; + ++mcsCounter; + } while ( ( cntPicked < KMaxNbrOfItemsToPick ) && + ( mcsCounter < mcsCount ) ); + + ++mcsBucket; + } while ( ( cntPicked < KMaxNbrOfItemsToPick ) && + ( mcsBucket < WHA::KHtMcsSetLength ) ); + + // set the retry counts + // + const TUint8 KSpecialShortRetryLimit = 10; + const TUint8 KSpecialLongRetryLimit = 4; + aRatePolicy.txRateClass[aRatePolicy.numOfPolicyObjects].shortRetryLimit = + KSpecialShortRetryLimit; + aRatePolicy.txRateClass[aRatePolicy.numOfPolicyObjects].longRetryLimit = + KSpecialLongRetryLimit; + + // now we have an additional policy + ++(aRatePolicy.numOfPolicyObjects); + // enable special policy use + aCtxImpl.SpecialTxAutoRatePolicy( aRatePolicy.numOfPolicyObjects ); + + OsTracePrint( KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::SpecialTxAutoratePolicy: policy id: %d"), + aRatePolicy.numOfPolicyObjects ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::ConfigureForTxAutoratePolicy( + WlanContextImpl& aCtxImpl, + const TTxRatePolicy& aRatePolicy, + const TQueue2RateClass& aQueue2RateClass, + THtMcsPolicy& aHtMcsPolicy, + TBool aCompleteMgmtRequest ) + { + // store the Tx queue to rate class mapping + for ( TUint queueId = ELegacy; queueId < EQueueIdMax; ++queueId ) + { + aCtxImpl.SetTxRatePolicy( + static_cast(queueId), + // rate class ids start from 1, hence the + 1 + aQueue2RateClass[queueId] + 1 ); + } + + // make sure that our MCS policy contains only MCSs that both the NW + // and the lower layers support + HandleHtMcsPolicy( + aCtxImpl, + aHtMcsPolicy, + aRatePolicy.numOfPolicyObjects ); + + // change to the state which performs the rest of the configuration + + WlanConfigureTxAutoRatePolicy& complexWhaCmd( + aCtxImpl.ConfigureTxAutoRatePolicy() ); + + complexWhaCmd.Set( aCompleteMgmtRequest ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + complexWhaCmd // next state + ); + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void WlanDot11State::HandleHtMcsPolicy( + WlanContextImpl& aCtxImpl, + THtMcsPolicy& aHtMcsPolicy, + TUint aNbrOfMcsSets ) const + { + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleHtMcsPolicy") ); + + const SHtCapabilitiesIE& htCapabilitiesIe( + aCtxImpl.GetNwHtCapabilitiesIe() ); + + for ( TUint mcsSet = 0; mcsSet < aNbrOfMcsSets; ++mcsSet ) + { + for ( TUint mcsBucket = 0; + mcsBucket < WHA::KHtMcsSetLength; + ++mcsBucket ) + { + aHtMcsPolicy[mcsSet][mcsBucket] = + aCtxImpl.WHASettings().iHtCapabilities.iTxMcs[mcsBucket] & + htCapabilitiesIe.iData.iRxMcsBitmask[mcsBucket] & + aHtMcsPolicy[mcsSet][mcsBucket]; + } + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool WlanDot11State::ConfigureForTxRatePolicy( + WlanContextImpl& aCtxImpl, + const TTxRatePolicy& aRatePolicy, + const TWhaRateMasks& aRateMasks, + const TQueue2RateClass& aQueue2RateClass, + const TInitialMaxTxRate4RateClass& aInitialMaxTxRate4RateClass, + TBool aCompleteMgmtRequest ) + { + for ( TUint rateClassInd = 0; + rateClassInd < aRatePolicy.numOfPolicyObjects; + ++rateClassInd ) + { + // provide the ratemask for this rate class to rate adaptation. + // Rate class ids start from 1, hence the + 1 + if ( !aCtxImpl.SetTxRateAdaptationRates( + rateClassInd + 1, + aRateMasks[rateClassInd] ) ) + { + // alloc failure; we cannot continue + OsTracePrint( KWarningLevel | KTxRateAdapt, (TUint8*) + ("UMAC: WlanDot11State::ConfigureForTxRatePolicy: WARNING: " + "alloc failure in rate adaptation")); + + return EFalse; // indicate fatal error + } + + // set the initial max Tx rate for this rate class + + aCtxImpl.SetCurrentMaxTxRate( + // rate class ids start from 1, hence the + 1 + rateClassInd + 1, + aInitialMaxTxRate4RateClass[rateClassInd] ); + } + + // inform rate adaptation about the Tx queue to rate class mapping + for ( TUint queueId = ELegacy; queueId < EQueueIdMax; ++queueId ) + { + aCtxImpl.SetTxRatePolicy( + static_cast(queueId), + // rate class ids start from 1, hence the + 1 + aQueue2RateClass[queueId] + 1 ); + } + + // update the Rate Policy MIB + + WlanWsaWriteMib& wsa_cmd = aCtxImpl.WsaWriteMib(); + + const TUint16 mibLength = sizeof( WHA::StxRatePolicy ) + // there is space for one policy object (rate class) in the + // StxRatePolicy struct, so space for any additional objects needs to + // be allocated in addition to that + + sizeof( WHA::StxRateClass ) * + ( aRatePolicy.numOfPolicyObjects - 1 ); + + wsa_cmd.Set( + aCtxImpl, + WHA::KMibTxRatePolicy, + mibLength, + // note that the types WHA::StxRatePolicy and TTxRatePolicy are + // effectively equivalent, so this is ok + &aRatePolicy ); + + const TUint32 KNotNecessary2Complete ( 0 ); + + // change global state: entry procedure triggers action + ChangeState( aCtxImpl, + *this, // prev state + wsa_cmd, // next state + aCompleteMgmtRequest ? KCompleteManagementRequest : + KNotNecessary2Complete + ); + + return ETrue; // indicate success & state change + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::HandleHtCapabilities( + WlanContextImpl& aCtxImpl, + WlanElementLocator& aElementLocator ) const + { + TBool status ( ETrue ); + TUint8 elementDatalength( 0 ); + const TUint8* elementData( NULL ); + + // try to locate HT capabilities element + if ( aElementLocator.InformationElement( + E802Dot11HtCapabilitiesIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // found, so store it to our context + aCtxImpl.GetNwHtCapabilitiesIe().SetIeData( + elementData, + elementDatalength ); + + // this also means that the target nw supports HT + aCtxImpl.HtSupportedByNw( ETrue ); + + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleHtCapabilities: HT capabilities element present => HT supported by nw") ); + } + else + { + // not found => target nw doesn't support HT + aCtxImpl.HtSupportedByNw( EFalse ); + + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleHtCapabilities: HT capabilities element not found") ); + } + + return status; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::HandleHtOperation( + WlanContextImpl& aCtxImpl, + WlanElementLocator& aElementLocator ) const + { + TBool status ( ETrue ); + TUint8 elementDatalength( 0 ); + const TUint8* elementData( NULL ); + + // try to locate HT Operation element + if ( aElementLocator.InformationElement( + E802Dot11HtOperationIE, + elementDatalength, + &elementData ) == WlanElementLocator::EWlanLocateOk ) + { + // found, so store it to our context + aCtxImpl.GetNwHtOperationIe().SetIeData( + elementData, + elementDatalength ); + + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleHtOperation: element present") ); + } + else + { + // not found even though HT capabilities element is present => + // protocol error + status = EFalse; + + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleHtOperation: element not found => protocol error") ); + } + + return status; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +TBool WlanDot11State::HandleDot11n( + WlanContextImpl& aCtxImpl, + WlanElementLocator& aElementLocator ) const + { + TBool status ( ETrue ); + + if ( ( aCtxImpl.PairwiseCipher() == EWlanCipherSuiteTkip ) || + !( aCtxImpl.QosEnabled() ) ) + { + // as the control is here it means that + // - the WLAN vendor implementation + // supports HT AND EITHER + // - TKIP will be used as the pairwise cipher OR + // - the target nw doesn't support WMM + // In these cases we must not use HT functionality, even if the target + // nw supported it. We achieve that by handling the target nw as + // a non-HT nw + aCtxImpl.HtSupportedByNw( EFalse ); + + OsTracePrint( KInfoLevel, (TUint8*) + ("UMAC: WlanDot11State::HandleDot11n: TKIP as pairwise cipher " + "or WMM not supported => HT disabled") ); + } + else + { + status = HandleHtCapabilities( aCtxImpl, aElementLocator ) ; + + // if HT capabilities element is present and ok + if ( aCtxImpl.HtSupportedByNw() && status ) + { + // check also HT Operation element + status = HandleHtOperation( aCtxImpl, aElementLocator ); + } + } + + return status; + }