diff -r 6b1d113cdff3 -r 6638e7f4bd8f telephonyprotocols/rawipnif/rawipnif2/src/RawIP2Flow.cpp --- a/telephonyprotocols/rawipnif/rawipnif2/src/RawIP2Flow.cpp Mon May 03 13:37:20 2010 +0300 +++ b/telephonyprotocols/rawipnif/rawipnif2/src/RawIP2Flow.cpp Thu May 06 15:10:38 2010 +0100 @@ -1,676 +1,676 @@ -// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of "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: -// Implements the CRawIPFlow class, which provides a central point for the NIF -// to communicate with NifMan and the BCA controllers. This class creates an interface -// to the IPv4 protocol when it is required. -// -// - -/** - @file -*/ - -#include -#include -#include -#include -#include -#include "IPv4Binder.h" -#include "IPv6Binder.h" -#include "RawIP2Flow.h" -#include "BcaController.h" -#include -#include -#include // for SAccessPointConfig -#include -#include -#include - -using namespace Messages; -using namespace MeshMachine; - -#ifdef __FLOG_ACTIVE -//These variables are used only if flog is active. -_LIT8(KTcpDumpFirstTag,"TcpDump"); -static const TUint16 KTcpDumpLinkType = 12; -#endif - -CRawIP2Flow::CRawIP2Flow(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf, CBttLogger* aTheLogger) -/** - * Constructor. - * - * @param aFactory Reference to the factory which created this object. - * @param aSubConnId Reference to the node id for sub connection. - * @param aProtocolIntf pointer to the CProtocolIntfBase - * @param aTheLogger The logging object, ownership is passed to this object - */ - : CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), - iTheLogger(aTheLogger), - iInitError(KErrNone), - iStarted(EFalse), - iStopping(EFalse) - { - LOG_NODE_CREATE(KNifSubDir, CRawIP2Flow); - } - -void CRawIP2Flow::ConstructL() -/** - * Second-phase constructor. Creates the Etel - * control engine - * - * @param aName The name of the NIF (unused) - */ - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tConstructL()"), this); - - iBinderControl = new (ELeave) TBinderControlProxy(*this); - iBcaController = CBcaController::NewL(*this, iTheLogger); - } - -CRawIP2Flow::~CRawIP2Flow() -/** - * Destructor. Cancels and deletes all owned active objects. - */ - { - // Note that we don't delete iBinder because it's not owned by us. - delete iBcaController; - // This class also deletes the logging object - delete iTheLogger; - - ASSERT(iBinder == NULL); - - delete iBinderControl; - LOG_NODE_DESTROY(KNifSubDir, CRawIP2Flow); - // Cleanup when stop was not called - harmless as it null's the pointer - __PACKETLOG_DELETE; - } - -void CRawIP2Flow::StartFlowL() -/** - * Starts the Flow up. This process involves connecting to the BCA. - * - * Called in response to corresponding SCPR message. - * - * @return Allways KErrNone - */ - { - ASSERT(iStarting==EFalse); - iStarting = ETrue; - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tStartFlowL()"), this); - - // If there were any errors during earlier processing of the ProvisionConfig message - // then send an Error message in response to the StartFlow (because ProvisionConfig - // does not have a response code). - if (iProvisionError != KErrNone) - { - User::Leave(iProvisionError); - } - - // Retrieve Agent provisioned information only available at StartFlow time - DynamicProvisionConfigL(); - InitialiseL(); - - // associate the binder object with the lowersender - iBinder->SetSender(&(iBcaController->Bca()->GetSender())); - //the name calculation should be done only if logging is enabled -#ifdef __FLOG_ACTIVE - const TUint KModemNameLen = KCommsDbSvrMaxColumnNameLength + 10; // need enough for ppp-XXX.txt - e.g. ppp-comm-1.txt, ppp-btcomm-10.txt etc - TBuf8 modemName; - - _LIT8(KDoubleColon, "::"); - - modemName.Copy(iBCAProvisionConfig->GetPortName()); - const TInt pos = modemName.FindC((const TDesC8&)KDoubleColon); - if(pos != KErrNotFound) - { - modemName.Delete(pos, 2); - } - - //append time stamp - const TUint KTimeStampLen = 8; - TBuf8 logFileName; - - _LIT8(KTimeFormat, "%08X"); - TUint32 counter = User::FastCounter(); - logFileName.Format(KTimeFormat, counter); - - TRAPD(err,__PACKETLOG_NEWL(KTcpDumpFirstTag, logFileName, CPacketLogger::ETcpDump, KTcpDumpLinkType)); - if (err) - { - _LOG_L1C1(_L8("Trapped leave from __PACKETLOG_NEWL")); - } - - const TUint KLogTextLen = KModemNameLen+KTimeStampLen+30; - TBuf8 logText; - _LIT8(KLogTimeText, "TcpDump log file time stamp:"); - _LIT8(KLogModemText, " for modem:"); - logText.Append(KLogTimeText); - logText.Append(logFileName); - logText.Append(KLogModemText); - logText.Append(modemName); - _LOG_L1C1(logText); -#endif - } - - -void CRawIP2Flow::LinkLayerUp() -/** - * This function is called when initialisation is complete and the Flow is - * ready to send/receive data. It notifies NifMan and the IP interface that it's - * ready to go. - */ - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tLinkLayerUp()"), this); - - iLastRequestOriginator.ReplyTo(Id(), ESock::TCFDataClient::TStarted().CRef()); - - iStarted = ETrue; - iStarting = EFalse; - } - -void CRawIP2Flow::LinkLayerDown(TInt aError) -/** - * This function is called when the context has been deactivated and the NIF - * is ready to be deleted, or if there is an error on startup. Its job is to - * notify NifMan that the link has gone down, so it can delete the NIF. - * - * @param aError An error code to propagate to NifMan - */ - { - _LOG_L1C3(_L8("CRawIP2Flow %08x:\tLinkLayerDown(aError %d)"), this, aError); - __PACKETLOG_DELETE; - - if (iStopping) - { - iLastRequestOriginator.ReplyTo(Id(), ESock::TCFDataClient::TStopped(aError).CRef()); - } - else if (iStarting) - { - iSubConnectionProvider.PostMessage(Id(), TEBase::TError(ESock::TCFServiceProvider::TStart::Id(), aError).CRef()); - } - else - { - iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef()); - } - - iStarted = EFalse; - iStarting = EFalse; - iStopping = EFalse; - } - -void CRawIP2Flow::StopFlow(TInt aError) -/** - * This function is called by NifMan to bring down the link. It starts - * the asynchronous context deactivation process; LinkLayerDown() will be - * called when the context has been deactivated. - * - * @param aError A code specifying why the link is to be brought down - * @param aAction The action to take: disconnect or reconnect - */ - { - _LOG_L1C3(_L8("CRawIP2Flow %08x:\tStopFlow(aError %d)"), this, aError); - __PACKETLOG_DELETE; - iStopping = ETrue; - ShutDown(aError); - } - - -void CRawIP2Flow::InitialiseL() -/** - * This method controls the initialisation sequence of the different modules - * in the Flow. When a module completes all the initialisation tasks it will - * call again this method with the new state. If an error occurs then the - * ShutDown() method will be called. - * - * @param aState The current initialisation step - * @param aError A possible error - */ - { - _LOG_L1C2(_L8("CRawIPFlow %08x:\tInitialiseL"),this); - - // Update local state from TSY information originally from Agent. - GetBinder()->UpdateContextConfigL(*iAgentProvision->iGprsConfig); - GetBinder()->UpdateConnectionSpeed(iAgentProvision->iConnectionSpeed); - - UpdateContextState(RPacketContext::EStatusActive, KErrNone); - - iBcaController->StartLoadL(iBCAProvisionConfig,iBinder,iBinder); - } - -void CRawIP2Flow::ShutDown(TInt aError) -/** - * This method controls the shutdown sequence of the different modules - * in the Flow. When a module completes all the shutdown tasks it will - * call again this method with the new state. - * - * @param aState The current state - * @param aError A possible error (only during initialisation) - */ - { - _LOG_L1C3(_L8("CRawIPFlow %08x:\tShutDown(aError %d)"),this, aError); - - if (aError != KErrNone) - { - // Flow is shutting down due to an error. - // The error code must be stored in order to call linklayer down - // passing that value - iInitError = aError; - } - - iBcaController->Stop(aError); - LinkLayerDown(iInitError); - } - -CBinderBase* CRawIP2Flow::GetBinder() -/** - * Returns a pointer to the Binder class - * - * @return a pointer to a CBinderBase derived class - */ - { - return iBinder; - } - -CBcaController* CRawIP2Flow::GetBcaController() -/** - * Returns a pointer to the CBcaIoController class - * - * @return a pointer to CBcaIoController - */ - { - return iBcaController; - } - -void CRawIP2Flow::UpdateContextState( - RPacketContext::TContextStatus aState, TInt /*aError*/) -/** - * Updates the state of the iContextState variable - * - * @param aState The new state - * @param aError A possible error - */ - { - _LOG_L1C3(_L8("CRawIP2Flow %08x:\tUpdateContextState(aState %d)"), this, aState); - - // Note that we do not need to close the Flow down if there's been an - // error, as the context state machine will do this for us. - - iContextStatus = aState; - } - -// ===================================================================================== -// -// CSubConnectionFlowBase -// - -ESock::MFlowBinderControl* CRawIP2Flow::DoGetBinderControlL() - { - return iBinderControl; - } - -// ===================================================================================== -// -// MFlowBinderControl methods -// - -ESock::MLowerControl* CRawIP2Flow::GetControlL(const TDesC8& aProtocol) - { -#ifdef __BTT_LOGGING__ - //TBuf8<256> debugBuffer; - //debugBuffer.Copy(aProtocol); - _LOG_L1C3(_L8("CRawIP2Flow %08x:\tGetControlL(aProtocol %S)"), this, &aProtocol); -#endif - - // IPv4 and ICMP Protocols - if (aProtocol.CompareF(KDescIp()) == 0 || aProtocol.CompareF(KDescIcmp()) == 0) - { - if (!iBinder) - { - iBinder = new (ELeave) CIPv4Binder(*this, iTheLogger); -#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS - iBinder->SetType(KIp4FrameType); -#endif // RAWIP_HEADER_APPENDED_TO_PACKETS - } - else - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tGetControlL(): IPv4 binder already exists"), this); - } - } - // IPv6 Protocol - else if (aProtocol.CompareF(KDescIp6()) == 0) - { - if (!iBinder) - { - iBinder = new (ELeave) CIPv6Binder(*this, iTheLogger); -#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS - iBinder->SetType(KIp6FrameType); -#endif // RAWIP_HEADER_APPENDED_TO_PACKETS - } - else - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tGetControlL(): IPv6 binder already exists"), this); - } - } - else - { - User::Leave(KErrNotSupported); - } - - return iBinder; - } - -ESock::MLowerDataSender* CRawIP2Flow::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) -/** - * Binds upper CFProtocol to this CFProtocol - * - * @param aUpperReceiver A pointer to Upper layer Receive class - * @param aUpperControl A pointer to Upper layer control class - */ - { -#ifndef _DEBUG - (void) aProtocol; -#endif - - ASSERT (aProtocol.CompareF(KDescIp()) == 0 || aProtocol.CompareF(KDescIcmp()) == 0 - || aProtocol.CompareF(KDescIp6()) == 0); - ASSERT(iBinder); - - iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TActive().CRef()); - return iBinder->Bind(aReceiver, aControl); - } - -void CRawIP2Flow::Unbind(ESock::MUpperDataReceiver* aUpperReceiver, ESock::MUpperControl* aUpperControl) - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tUnbind()"), this); - - ASSERT(iBinder); - iBinder->Unbind(aUpperReceiver, aUpperControl); - - delete iBinder; - iBinder = NULL; - - SendDataClientIdleIfNoClients(); - } - - -void CRawIP2Flow::SendDataClientIdleIfNoClients() - { - if (iBinder == NULL) - { - iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TIdle().CRef()); - } - } - -ESock::CSubConnectionFlowBase* CRawIP2Flow::Flow() -/** -Return the Flow corresponding to the MFlowBinderControl -*/ - { - return this; - } - -// ===================================================================================== -// -// MCFNode -// - -void CRawIP2Flow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage) - { - CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage); - - if (aMessage.IsMessage()) - { - SubConnectionError(static_cast(aMessage).iValue); - } - else if (TEChild::ERealmId == aMessage.MessageId().Realm()) - { - switch (aMessage.MessageId().MessageId()) - { - case TEChild::TDestroy::EId : - Destroy(); - break; - default: -//TODO - logging - ASSERT(EFalse); - } - } - else if (ESock::TCFDataClient::ERealmId == aMessage.MessageId().Realm()) - { - switch (aMessage.MessageId().MessageId()) - { - case ESock::TCFDataClient::TStart::EId : - StartFlowL(); - break; - case ESock::TCFDataClient::TStop::EId : - StopFlow(static_cast(aMessage).iValue); - break; - case ESock::TCFDataClient::TProvisionConfig::EId: - ProvisionConfig(static_cast(aMessage).iConfig); - break; - case ESock::TCFDataClient::TBindTo::EId: - { - ESock::TCFDataClient::TBindTo& bindToReq = message_cast(aMessage); - if (!bindToReq.iNodeId.IsNull()) - { - User::Leave(KErrNotSupported); - } - RClientInterface::OpenPostMessageClose(Id(), aSender, ESock::TCFDataClient::TBindToComplete().CRef()); - } - break; - default: -//TODO - logging - ASSERT(EFalse); - } - } - else if (ESock::TCFFlow::ERealmId == aMessage.MessageId().Realm()) - { - switch (aMessage.MessageId().MessageId()) - { - case ESock::TCFFlow::TBlock::EId : - iBlocked = ETrue; - break; - case ESock::TCFFlow::TUnBlock::EId : - iBlocked = EFalse; - if (iBinder) - { - iBinder->StartSending(); - } - break; - case ESock::TCFFlow::TRejoin::EId: - { - ESock::TCFFlow::TRejoin& rejoinMsg = message_cast(aMessage); - ESock::TDefaultFlowFactoryQuery query(rejoinMsg.iNodeId); - CRawIP2Flow* otherFlow = static_cast(Factory().Find(query)); - ASSERT(otherFlow); - - //This rather ugly looking snipped of code implements - //the scenario whereat the network tears down the default - //scpr and the default scpr selects a new default amongst - //the non-default and subsequently performs a transparant - //swap - i.e.: the upper layer perceives this as a - //non-default going down. Since the datapath is pre-bound - //to the flow representing the default, the datapath needs - //to perform a transparent swap too, so that the upper layer - //doesn't notice anything. It does that by swapping the - //flows below the binders. - CBinderBase* localBinder = iBinder; - CBttLogger* logger = localBinder->iTheLogger; - - TBinderControlProxy* localBinderControl = iBinderControl; - iBinder = otherFlow->iBinder; - otherFlow->iBinder->ChangeFlow(*this); - localBinder->ChangeFlow(*otherFlow); - otherFlow->iBinder = localBinder; - iBinderControl = otherFlow->iBinderControl; - otherFlow->iBinderControl = localBinderControl; - otherFlow->iBinderControl->iFlow = otherFlow; - iBinderControl->iFlow = this; - - iBinder->iTheLogger = logger; - - iSubConnectionProvider.Close(); - iSubConnectionProvider.Open(address_cast(rejoinMsg.iNodeId)); - } - break; - default: -//TODO - logging - ASSERT(EFalse); - } - } - else // not a recognised realm or message - { - ASSERT(EFalse); - } - } - - -// ===================================================================================== -// -// Methods for handling incoming SCPR messages -// - -void CRawIP2Flow::SubConnectionGoingDown() - { - } - -void CRawIP2Flow::SubConnectionError(TInt /*aError*/) - { - } - -/* -Provisioning description for RawIp CFProtocol Flow: - -- on receipt of the ProvisionConfig message, the pointer contained within is stored - in iAccessPointConfig and the provisioning information contained within it is validated: - - CBCAProvision must be present. It is added by the RawIpMCPr and populated from CommsDat. A pointer to it - is stored in iProvision. - if any are missing, an error is stored in iProvisionError and sent in response to the StartFlow - message later on (ProvisionConfig has no response). - -- on receipt of the StartFlow message, further provisioning information is retrieved: - - CIPConfig must be present. It is added by the RawIpMCPr and populated from CommsDat. The binder retrieves - individual fields from it. - - CRawIpAgentConfig must be present. It is added by the RawIpAgentHandler and populated via calls - to the Agent. A pointer to it is stored in iAgentProvision. Note that the iGprsConfig field - is a pointer to a (large) structure in the Agent (see CRawIpAgentHandler). - if any of the above are missing, an Error message is signalled back to the SCPr in response - to the StartFlow. -*/ - -void CRawIP2Flow::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData) -/** -Handle ProvisionConfig message from SCPR. - -Just save the pointer for now - validate it later on StartFlow. - -@param aData provisioning pointer from message -*/ - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tProvisionConfig()"), this); - iProvisionError = KErrNone; - - AccessPointConfig().Close(); - AccessPointConfig().Open(aConfigData); - - ASSERT(iBCAProvisionConfig == NULL); - iBCAProvisionConfig = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId))); - - if (iBCAProvisionConfig == NULL) - { - _LOG_L1C1(_L8("CRawIP2Flow:\tProvisionConfigL() - CBCAProvision config incomplete")); - iProvisionError = KErrCorrupt; - return; - } - } - -void CRawIP2Flow::DynamicProvisionConfigL() -/** -Retrieve provisioning information available only at StartFlow time. -*/ - { - ASSERT(iAgentProvision == NULL); - iAgentProvision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CRawIpAgentConfig::EUid, CRawIpAgentConfig::ETypeId))); - - if (iAgentProvision == NULL) - { - User::Leave(KErrCorrupt); - } - - const CIPConfig* wcdmaIpProvision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId))); - if (wcdmaIpProvision == NULL) - { - _LOG_L1C2(_L8("CRawIP2Flow %08x:\tDynamicProvisionConfigL() - WCDMA config incomplete"), this); - iProvisionError = KErrCorrupt; - return; - } - // Pass pointer to binder specific provisioning information to binder - if (iBinder) - { - iBinder->SetProvision(*wcdmaIpProvision); - } - } - - -void CRawIP2Flow::Destroy() -/** -Handle Destroy message from SCPR. -*/ - { - DeleteThisFlow(); - } - -ESock::MLowerControl* CRawIP2Flow::TBinderControlProxy::GetControlL(const TDesC8& aProtocol) - { - return RawIP2Flow().GetControlL(aProtocol); - } - -ESock::MLowerDataSender* CRawIP2Flow::TBinderControlProxy::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) - { - return RawIP2Flow().BindL(aProtocol, aReceiver, aControl); - } - -void CRawIP2Flow::TBinderControlProxy::Unbind(ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) - { - return RawIP2Flow().Unbind(aReceiver, aControl); - } - -ESock::CSubConnectionFlowBase* CRawIP2Flow::TBinderControlProxy::Flow() - { - return iFlow; - } - -// ===================================================================================== -// -// Utility functions -// - -void CRawIP2Flow::PostProgressMessage(TInt aStage, TInt aError) - { - iSubConnectionProvider.PostMessage(Id(), ESock::TCFMessage::TStateChange(Elements::TStateChange( aStage, aError)).CRef()); - } - -// -// NOTE: -// Attribute table should be in the control side module that instantiates CRawIpProvision. -// RawIP CFProtocol does not instantiate the CRawIpProvision object, so does not need to -// define the attribute tables. The attribute table can therefore be placed directly into -// the control side module. -// -// The reason for this is to save splitting RawIP CFProtocol into two DLL's - ECOM and Main - -// just for control side module to link against Main DLL to retrieve the attribute table. -// In fact, it can be placed into control side module as "START_ATTRIBUTE_TABLE" rather -// than "EXPORT_START_ATTRIBUTE_TABLE". In fact, do we just need "TYPEID_TABLE" ? -// -// EXPORT_START_ATTRIBUTE_TABLE(CRawIpProvision, KRawIpConfigUid, KRawIpConfigType) -// END_ATTRIBUTE_TABLE() +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// Implements the CRawIPFlow class, which provides a central point for the NIF +// to communicate with NifMan and the BCA controllers. This class creates an interface +// to the IPv4 protocol when it is required. +// +// + +/** + @file +*/ + +#include +#include +#include +#include +#include +#include "IPv4Binder.h" +#include "IPv6Binder.h" +#include "RawIP2Flow.h" +#include "BcaController.h" +#include +#include +#include // for SAccessPointConfig +#include +#include +#include + +using namespace Messages; +using namespace MeshMachine; + +#ifdef __FLOG_ACTIVE +//These variables are used only if flog is active. +_LIT8(KTcpDumpFirstTag,"TcpDump"); +static const TUint16 KTcpDumpLinkType = 12; +#endif + +CRawIP2Flow::CRawIP2Flow(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf, CBttLogger* aTheLogger) +/** + * Constructor. + * + * @param aFactory Reference to the factory which created this object. + * @param aSubConnId Reference to the node id for sub connection. + * @param aProtocolIntf pointer to the CProtocolIntfBase + * @param aTheLogger The logging object, ownership is passed to this object + */ + : CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), + iTheLogger(aTheLogger), + iInitError(KErrNone), + iStarted(EFalse), + iStopping(EFalse) + { + LOG_NODE_CREATE(KNifSubDir, CRawIP2Flow); + } + +void CRawIP2Flow::ConstructL() +/** + * Second-phase constructor. Creates the Etel + * control engine + * + * @param aName The name of the NIF (unused) + */ + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tConstructL()"), this); + + iBinderControl = new (ELeave) TBinderControlProxy(*this); + iBcaController = CBcaController::NewL(*this, iTheLogger); + } + +CRawIP2Flow::~CRawIP2Flow() +/** + * Destructor. Cancels and deletes all owned active objects. + */ + { + // Note that we don't delete iBinder because it's not owned by us. + delete iBcaController; + // This class also deletes the logging object + delete iTheLogger; + + ASSERT(iBinder == NULL); + + delete iBinderControl; + LOG_NODE_DESTROY(KNifSubDir, CRawIP2Flow); + // Cleanup when stop was not called - harmless as it null's the pointer + __PACKETLOG_DELETE; + } + +void CRawIP2Flow::StartFlowL() +/** + * Starts the Flow up. This process involves connecting to the BCA. + * + * Called in response to corresponding SCPR message. + * + * @return Allways KErrNone + */ + { + ASSERT(iStarting==EFalse); + iStarting = ETrue; + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tStartFlowL()"), this); + + // If there were any errors during earlier processing of the ProvisionConfig message + // then send an Error message in response to the StartFlow (because ProvisionConfig + // does not have a response code). + if (iProvisionError != KErrNone) + { + User::Leave(iProvisionError); + } + + // Retrieve Agent provisioned information only available at StartFlow time + DynamicProvisionConfigL(); + InitialiseL(); + + // associate the binder object with the lowersender + iBinder->SetSender(&(iBcaController->Bca()->GetSender())); + //the name calculation should be done only if logging is enabled +#ifdef __FLOG_ACTIVE + const TUint KModemNameLen = KCommsDbSvrMaxColumnNameLength + 10; // need enough for ppp-XXX.txt - e.g. ppp-comm-1.txt, ppp-btcomm-10.txt etc + TBuf8 modemName; + + _LIT8(KDoubleColon, "::"); + + modemName.Copy(iBCAProvisionConfig->GetPortName()); + const TInt pos = modemName.FindC((const TDesC8&)KDoubleColon); + if(pos != KErrNotFound) + { + modemName.Delete(pos, 2); + } + + //append time stamp + const TUint KTimeStampLen = 8; + TBuf8 logFileName; + + _LIT8(KTimeFormat, "%08X"); + TUint32 counter = User::FastCounter(); + logFileName.Format(KTimeFormat, counter); + + TRAPD(err,__PACKETLOG_NEWL(KTcpDumpFirstTag, logFileName, CPacketLogger::ETcpDump, KTcpDumpLinkType)); + if (err) + { + _LOG_L1C1(_L8("Trapped leave from __PACKETLOG_NEWL")); + } + + const TUint KLogTextLen = KModemNameLen+KTimeStampLen+30; + TBuf8 logText; + _LIT8(KLogTimeText, "TcpDump log file time stamp:"); + _LIT8(KLogModemText, " for modem:"); + logText.Append(KLogTimeText); + logText.Append(logFileName); + logText.Append(KLogModemText); + logText.Append(modemName); + _LOG_L1C1(logText); +#endif + } + + +void CRawIP2Flow::LinkLayerUp() +/** + * This function is called when initialisation is complete and the Flow is + * ready to send/receive data. It notifies NifMan and the IP interface that it's + * ready to go. + */ + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tLinkLayerUp()"), this); + + iLastRequestOriginator.ReplyTo(Id(), ESock::TCFDataClient::TStarted().CRef()); + + iStarted = ETrue; + iStarting = EFalse; + } + +void CRawIP2Flow::LinkLayerDown(TInt aError) +/** + * This function is called when the context has been deactivated and the NIF + * is ready to be deleted, or if there is an error on startup. Its job is to + * notify NifMan that the link has gone down, so it can delete the NIF. + * + * @param aError An error code to propagate to NifMan + */ + { + _LOG_L1C3(_L8("CRawIP2Flow %08x:\tLinkLayerDown(aError %d)"), this, aError); + __PACKETLOG_DELETE; + + if (iStopping) + { + iLastRequestOriginator.ReplyTo(Id(), ESock::TCFDataClient::TStopped(aError).CRef()); + } + else if (iStarting) + { + iSubConnectionProvider.PostMessage(Id(), TEBase::TError(ESock::TCFServiceProvider::TStart::Id(), aError).CRef()); + } + else + { + iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef()); + } + + iStarted = EFalse; + iStarting = EFalse; + iStopping = EFalse; + } + +void CRawIP2Flow::StopFlow(TInt aError) +/** + * This function is called by NifMan to bring down the link. It starts + * the asynchronous context deactivation process; LinkLayerDown() will be + * called when the context has been deactivated. + * + * @param aError A code specifying why the link is to be brought down + * @param aAction The action to take: disconnect or reconnect + */ + { + _LOG_L1C3(_L8("CRawIP2Flow %08x:\tStopFlow(aError %d)"), this, aError); + __PACKETLOG_DELETE; + iStopping = ETrue; + ShutDown(aError); + } + + +void CRawIP2Flow::InitialiseL() +/** + * This method controls the initialisation sequence of the different modules + * in the Flow. When a module completes all the initialisation tasks it will + * call again this method with the new state. If an error occurs then the + * ShutDown() method will be called. + * + * @param aState The current initialisation step + * @param aError A possible error + */ + { + _LOG_L1C2(_L8("CRawIPFlow %08x:\tInitialiseL"),this); + + // Update local state from TSY information originally from Agent. + GetBinder()->UpdateContextConfigL(*iAgentProvision->iGprsConfig); + GetBinder()->UpdateConnectionSpeed(iAgentProvision->iConnectionSpeed); + + UpdateContextState(RPacketContext::EStatusActive, KErrNone); + + iBcaController->StartLoadL(iBCAProvisionConfig,iBinder,iBinder); + } + +void CRawIP2Flow::ShutDown(TInt aError) +/** + * This method controls the shutdown sequence of the different modules + * in the Flow. When a module completes all the shutdown tasks it will + * call again this method with the new state. + * + * @param aState The current state + * @param aError A possible error (only during initialisation) + */ + { + _LOG_L1C3(_L8("CRawIPFlow %08x:\tShutDown(aError %d)"),this, aError); + + if (aError != KErrNone) + { + // Flow is shutting down due to an error. + // The error code must be stored in order to call linklayer down + // passing that value + iInitError = aError; + } + + iBcaController->Stop(aError); + LinkLayerDown(iInitError); + } + +CBinderBase* CRawIP2Flow::GetBinder() +/** + * Returns a pointer to the Binder class + * + * @return a pointer to a CBinderBase derived class + */ + { + return iBinder; + } + +CBcaController* CRawIP2Flow::GetBcaController() +/** + * Returns a pointer to the CBcaIoController class + * + * @return a pointer to CBcaIoController + */ + { + return iBcaController; + } + +void CRawIP2Flow::UpdateContextState( + RPacketContext::TContextStatus aState, TInt /*aError*/) +/** + * Updates the state of the iContextState variable + * + * @param aState The new state + * @param aError A possible error + */ + { + _LOG_L1C3(_L8("CRawIP2Flow %08x:\tUpdateContextState(aState %d)"), this, aState); + + // Note that we do not need to close the Flow down if there's been an + // error, as the context state machine will do this for us. + + iContextStatus = aState; + } + +// ===================================================================================== +// +// CSubConnectionFlowBase +// + +ESock::MFlowBinderControl* CRawIP2Flow::DoGetBinderControlL() + { + return iBinderControl; + } + +// ===================================================================================== +// +// MFlowBinderControl methods +// + +ESock::MLowerControl* CRawIP2Flow::GetControlL(const TDesC8& aProtocol) + { +#ifdef __BTT_LOGGING__ + //TBuf8<256> debugBuffer; + //debugBuffer.Copy(aProtocol); + _LOG_L1C3(_L8("CRawIP2Flow %08x:\tGetControlL(aProtocol %S)"), this, &aProtocol); +#endif + + // IPv4 and ICMP Protocols + if (aProtocol.CompareF(KDescIp()) == 0 || aProtocol.CompareF(KDescIcmp()) == 0) + { + if (!iBinder) + { + iBinder = new (ELeave) CIPv4Binder(*this, iTheLogger); +#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS + iBinder->SetType(KIp4FrameType); +#endif // RAWIP_HEADER_APPENDED_TO_PACKETS + } + else + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tGetControlL(): IPv4 binder already exists"), this); + } + } + // IPv6 Protocol + else if (aProtocol.CompareF(KDescIp6()) == 0) + { + if (!iBinder) + { + iBinder = new (ELeave) CIPv6Binder(*this, iTheLogger); +#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS + iBinder->SetType(KIp6FrameType); +#endif // RAWIP_HEADER_APPENDED_TO_PACKETS + } + else + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tGetControlL(): IPv6 binder already exists"), this); + } + } + else + { + User::Leave(KErrNotSupported); + } + + return iBinder; + } + +ESock::MLowerDataSender* CRawIP2Flow::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) +/** + * Binds upper CFProtocol to this CFProtocol + * + * @param aUpperReceiver A pointer to Upper layer Receive class + * @param aUpperControl A pointer to Upper layer control class + */ + { +#ifndef _DEBUG + (void) aProtocol; +#endif + + ASSERT (aProtocol.CompareF(KDescIp()) == 0 || aProtocol.CompareF(KDescIcmp()) == 0 + || aProtocol.CompareF(KDescIp6()) == 0); + ASSERT(iBinder); + + iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TActive().CRef()); + return iBinder->Bind(aReceiver, aControl); + } + +void CRawIP2Flow::Unbind(ESock::MUpperDataReceiver* aUpperReceiver, ESock::MUpperControl* aUpperControl) + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tUnbind()"), this); + + ASSERT(iBinder); + iBinder->Unbind(aUpperReceiver, aUpperControl); + + delete iBinder; + iBinder = NULL; + + SendDataClientIdleIfNoClients(); + } + + +void CRawIP2Flow::SendDataClientIdleIfNoClients() + { + if (iBinder == NULL) + { + iSubConnectionProvider.PostMessage(Id(), ESock::TCFControlProvider::TIdle().CRef()); + } + } + +ESock::CSubConnectionFlowBase* CRawIP2Flow::Flow() +/** +Return the Flow corresponding to the MFlowBinderControl +*/ + { + return this; + } + +// ===================================================================================== +// +// MCFNode +// + +void CRawIP2Flow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage) + { + CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage); + + if (aMessage.IsMessage()) + { + SubConnectionError(static_cast(aMessage).iValue); + } + else if (TEChild::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case TEChild::TDestroy::EId : + Destroy(); + break; + default: +//TODO - logging + ASSERT(EFalse); + } + } + else if (ESock::TCFDataClient::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case ESock::TCFDataClient::TStart::EId : + StartFlowL(); + break; + case ESock::TCFDataClient::TStop::EId : + StopFlow(static_cast(aMessage).iValue); + break; + case ESock::TCFDataClient::TProvisionConfig::EId: + ProvisionConfig(static_cast(aMessage).iConfig); + break; + case ESock::TCFDataClient::TBindTo::EId: + { + ESock::TCFDataClient::TBindTo& bindToReq = message_cast(aMessage); + if (!bindToReq.iNodeId.IsNull()) + { + User::Leave(KErrNotSupported); + } + RClientInterface::OpenPostMessageClose(Id(), aSender, ESock::TCFDataClient::TBindToComplete().CRef()); + } + break; + default: +//TODO - logging + ASSERT(EFalse); + } + } + else if (ESock::TCFFlow::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case ESock::TCFFlow::TBlock::EId : + iBlocked = ETrue; + break; + case ESock::TCFFlow::TUnBlock::EId : + iBlocked = EFalse; + if (iBinder) + { + iBinder->StartSending(); + } + break; + case ESock::TCFFlow::TRejoin::EId: + { + ESock::TCFFlow::TRejoin& rejoinMsg = message_cast(aMessage); + ESock::TDefaultFlowFactoryQuery query(rejoinMsg.iNodeId); + CRawIP2Flow* otherFlow = static_cast(Factory().Find(query)); + ASSERT(otherFlow); + + //This rather ugly looking snipped of code implements + //the scenario whereat the network tears down the default + //scpr and the default scpr selects a new default amongst + //the non-default and subsequently performs a transparant + //swap - i.e.: the upper layer perceives this as a + //non-default going down. Since the datapath is pre-bound + //to the flow representing the default, the datapath needs + //to perform a transparent swap too, so that the upper layer + //doesn't notice anything. It does that by swapping the + //flows below the binders. + CBinderBase* localBinder = iBinder; + CBttLogger* logger = localBinder->iTheLogger; + + TBinderControlProxy* localBinderControl = iBinderControl; + iBinder = otherFlow->iBinder; + otherFlow->iBinder->ChangeFlow(*this); + localBinder->ChangeFlow(*otherFlow); + otherFlow->iBinder = localBinder; + iBinderControl = otherFlow->iBinderControl; + otherFlow->iBinderControl = localBinderControl; + otherFlow->iBinderControl->iFlow = otherFlow; + iBinderControl->iFlow = this; + + iBinder->iTheLogger = logger; + + iSubConnectionProvider.Close(); + iSubConnectionProvider.Open(address_cast(rejoinMsg.iNodeId)); + } + break; + default: +//TODO - logging + ASSERT(EFalse); + } + } + else // not a recognised realm or message + { + ASSERT(EFalse); + } + } + + +// ===================================================================================== +// +// Methods for handling incoming SCPR messages +// + +void CRawIP2Flow::SubConnectionGoingDown() + { + } + +void CRawIP2Flow::SubConnectionError(TInt /*aError*/) + { + } + +/* +Provisioning description for RawIp CFProtocol Flow: + +- on receipt of the ProvisionConfig message, the pointer contained within is stored + in iAccessPointConfig and the provisioning information contained within it is validated: + - CBCAProvision must be present. It is added by the RawIpMCPr and populated from CommsDat. A pointer to it + is stored in iProvision. + if any are missing, an error is stored in iProvisionError and sent in response to the StartFlow + message later on (ProvisionConfig has no response). + +- on receipt of the StartFlow message, further provisioning information is retrieved: + - CIPConfig must be present. It is added by the RawIpMCPr and populated from CommsDat. The binder retrieves + individual fields from it. + - CRawIpAgentConfig must be present. It is added by the RawIpAgentHandler and populated via calls + to the Agent. A pointer to it is stored in iAgentProvision. Note that the iGprsConfig field + is a pointer to a (large) structure in the Agent (see CRawIpAgentHandler). + if any of the above are missing, an Error message is signalled back to the SCPr in response + to the StartFlow. +*/ + +void CRawIP2Flow::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData) +/** +Handle ProvisionConfig message from SCPR. + +Just save the pointer for now - validate it later on StartFlow. + +@param aData provisioning pointer from message +*/ + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tProvisionConfig()"), this); + iProvisionError = KErrNone; + + AccessPointConfig().Close(); + AccessPointConfig().Open(aConfigData); + + ASSERT(iBCAProvisionConfig == NULL); + iBCAProvisionConfig = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId))); + + if (iBCAProvisionConfig == NULL) + { + _LOG_L1C1(_L8("CRawIP2Flow:\tProvisionConfigL() - CBCAProvision config incomplete")); + iProvisionError = KErrCorrupt; + return; + } + } + +void CRawIP2Flow::DynamicProvisionConfigL() +/** +Retrieve provisioning information available only at StartFlow time. +*/ + { + ASSERT(iAgentProvision == NULL); + iAgentProvision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CRawIpAgentConfig::EUid, CRawIpAgentConfig::ETypeId))); + + if (iAgentProvision == NULL) + { + User::Leave(KErrCorrupt); + } + + const CIPConfig* wcdmaIpProvision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId))); + if (wcdmaIpProvision == NULL) + { + _LOG_L1C2(_L8("CRawIP2Flow %08x:\tDynamicProvisionConfigL() - WCDMA config incomplete"), this); + iProvisionError = KErrCorrupt; + return; + } + // Pass pointer to binder specific provisioning information to binder + if (iBinder) + { + iBinder->SetProvision(*wcdmaIpProvision); + } + } + + +void CRawIP2Flow::Destroy() +/** +Handle Destroy message from SCPR. +*/ + { + DeleteThisFlow(); + } + +ESock::MLowerControl* CRawIP2Flow::TBinderControlProxy::GetControlL(const TDesC8& aProtocol) + { + return RawIP2Flow().GetControlL(aProtocol); + } + +ESock::MLowerDataSender* CRawIP2Flow::TBinderControlProxy::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) + { + return RawIP2Flow().BindL(aProtocol, aReceiver, aControl); + } + +void CRawIP2Flow::TBinderControlProxy::Unbind(ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl) + { + return RawIP2Flow().Unbind(aReceiver, aControl); + } + +ESock::CSubConnectionFlowBase* CRawIP2Flow::TBinderControlProxy::Flow() + { + return iFlow; + } + +// ===================================================================================== +// +// Utility functions +// + +void CRawIP2Flow::PostProgressMessage(TInt aStage, TInt aError) + { + iSubConnectionProvider.PostMessage(Id(), ESock::TCFMessage::TStateChange(Elements::TStateChange( aStage, aError)).CRef()); + } + +// +// NOTE: +// Attribute table should be in the control side module that instantiates CRawIpProvision. +// RawIP CFProtocol does not instantiate the CRawIpProvision object, so does not need to +// define the attribute tables. The attribute table can therefore be placed directly into +// the control side module. +// +// The reason for this is to save splitting RawIP CFProtocol into two DLL's - ECOM and Main - +// just for control side module to link against Main DLL to retrieve the attribute table. +// In fact, it can be placed into control side module as "START_ATTRIBUTE_TABLE" rather +// than "EXPORT_START_ATTRIBUTE_TABLE". In fact, do we just need "TYPEID_TABLE" ? +// +// EXPORT_START_ATTRIBUTE_TABLE(CRawIpProvision, KRawIpConfigUid, KRawIpConfigType) +// END_ATTRIBUTE_TABLE()