--- a/telephonyprotocols/rawipnif/src/RawIPFlow.cpp Mon May 03 13:37:20 2010 +0300
+++ b/telephonyprotocols/rawipnif/src/RawIPFlow.cpp Thu May 06 15:10:38 2010 +0100
@@ -1,873 +1,873 @@
-// Copyright (c) 2006-2010 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 <f32file.h>
-#include <nifman.h>
-#include <nifmbuf.h>
-#include <in_iface.h>
-#include <nifvar.h>
-#include "IPv4Binder.h"
-#include "IPv6Binder.h"
-#include "RawIPFlow.h"
-#include <comms-infras/linkprovision.h>
-#include <comms-infras/linkmessages.h>
-#include <comms-infras/ss_metaconnprov.h> // for SAccessPointConfig
-#include <elements/nm_messages_base.h>
-#include <elements/nm_messages_child.h>
-#include <comms-infras/ss_nodemessages_flow.h>
-
-using namespace Messages;
-using namespace MeshMachine;
-using namespace ESock;
-
-#ifdef __FLOG_ACTIVE
-//These variables are used only if flog is active.
-_LIT8(KTcpDumpFirstTag,"TcpDump");
-static const TUint16 KTcpDumpLinkType = 12;
-#endif
-
-CRawIPFlow::CRawIPFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf, CBttLogger* aTheLogger)
-/**
- * Constructor.
- *
- * @param aFactory Reference to the factory which created this object.
- * @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, CRawIPFlow);
- }
-
-void CRawIPFlow::ConstructL()
-/**
- * Second-phase constructor. Creates the Etel
- * control engine
- *
- * @param aName The name of the NIF (unused)
- */
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tConstructL()"), this);
- iBinderControl = new (ELeave) TBinderControlProxy(*this);
- iBcaController = CBcaIoController::NewL(*this, iTheLogger);
- }
-
-CRawIPFlow::~CRawIPFlow()
-/**
- * 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, CRawIPFlow);
- // Cleanup when stop was not called - harmless as it null's the pointer
- __PACKETLOG_DELETE;
- }
-
-void CRawIPFlow::StartFlowL()
-/**
- * Starts the Flow up. This process involves connecting to the BCA. When startup is
- * complete, LinkLayerUp() will be called.
- *
- * Called in response to corresponding SCPR message.
- *
- * @return Allways KErrNone
- */
- {
- ASSERT(iStarting==EFalse);
- iStarting = ETrue;
- _LOG_L1C2(_L8("CRawIPFlow %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(MControllerObserver::EStart, KErrNone);
-
- //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<KModemNameLen> modemName;
-
- _LIT8(KDoubleColon, "::");
-
- modemName.Copy(iProvision->GetPortName());
- const TInt pos = modemName.FindC((const TDesC8&)KDoubleColon);
- if(pos != KErrNotFound)
- {
- modemName.Delete(pos, 2);
- }
-
- //append time stamp
- const TUint KTimeStampLen = 8;
- TBuf8<KTimeStampLen> 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<KLogTextLen> 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 CRawIPFlow::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("CRawIPFlow %08x:\tLinkLayerUp()"), this);
-
- iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
-
-
- iBinder->StartSending();
- iStarted = ETrue;
- iStarting = EFalse;
- }
-
-void CRawIPFlow::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("CRawIPFlow %08x:\tLinkLayerDown(aError %d)"), this, aError);
- __PACKETLOG_DELETE;
-
- if (iStopping)
- {
- iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef());
- }
- else if (iStarting)
- {
- iSubConnectionProvider.PostMessage(Id(), TEBase::TError(TCFServiceProvider::TStart::Id(), aError).CRef());
- }
- else
- {
- iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef());
- }
-
- iStarted = EFalse;
- iStarting = EFalse;
- iStopping = EFalse;
- }
-
-void CRawIPFlow::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("CRawIPFlow %08x:\tStopFlow(aError %d)"), this, aError);
- __PACKETLOG_DELETE;
- iStopping = ETrue;
- ShutDown(MControllerObserver::EInitialised, aError);
- }
-
-MLowerDataSender::TSendResult CRawIPFlow::SendPacket(RMBufChain& aPdu, TAny* /*aProtocol*/,
- TUint16 /*aType*/)
-/**
- * Sends a packet, via the BCA controller. This method is protocol-agnostic,
- * and is called by the IPv4 and IPv6 binder to actually send packets.
- *
- * @param aPdu The packet to send
- * @return MLowerDataSender::TSendResult
- */
- {
- _LOG_L1C3(_L8("CRawIPFlow %08x:\tSendPacket(): length=%d"),
- this, aPdu.Length() - aPdu.First()->Length());
-
- __PACKETLOG_WRITE_PACKET(aPdu, 0);
- return iBcaController->Send(aPdu);
- }
-
-void CRawIPFlow::Process(RMBufChain& aPdu, TUint16 aProtocolCode)
-/**
- * Handles incoming packets which have been passed up from the BCA controller.
- * If the IPv4 binder wants to process the packet, it hands it on; otherwise,
- * the packet is binned.
- *
- * @param aPdu The incoming packet
- */
- {
- _LOG_L1C3(_L8("CRawIPFlow %08x:\tProcess() [aPdu length=%d]"),
- this, aPdu.Length() - aPdu.First()->Length());
-
- // If the packet has zero or negative length, bin it.
- if ((aPdu.Length() - aPdu.First()->Length()) <= 0)
- {
- _LOG_L1C1(_L8("Dumped packet: illegal length"));
- aPdu.Free();
- return;
- }
-
- // See if the protocol interface wants the packet.
- if (iBinder && iBinder->WantsProtocol(aProtocolCode))
- {
- __PACKETLOG_WRITE_PACKET(aPdu, 0);
- iBinder->Process(aPdu);
- }
- else
- {
- // The protocol didn't want the packet, so bin it.
- _LOG_L1C2(_L8("Packet was not processed: freeing (protocol code: %X)"),
- aProtocolCode);
- if (iBinder == NULL)
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tProcess(): NOTE: Binder not present"), this);
- }
- aPdu.Free();
- }
- }
-
-void CRawIPFlow::ResumeSending()
-/**
- * Notifies the protocol interface that it can resume sending packets.
- */
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tResumeSending()"), this);
-
- if (iBinder)
- {
- iBinder->StartSending();
- }
- else
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tResumeSending(): NOTE: Binder not present"), this);
- }
- }
-
-void CRawIPFlow::InitialiseL(TInitialisationState aState, TInt aError)
-/**
- * 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_L1C4(_L8("CRawIPFlow %08x:\tInitialiseL(aState %d, aError %d)"),
- this, aState, aError);
-
- if (aError != KErrNone)
- {
- _LOG_L2C2(_L8(" *** FAILED to initialise NIF *** Error =%d"),aError);
-
- // Initialise shutdown sequence
- switch (aState)
- {
- case MControllerObserver::EBcaController:
- ShutDown(MControllerObserver::EInitialised, aError);
- break;
- default:
- _LOG_L2C3(_L8("ERROR CRawIPFlow: Unknown state:%d in NIF: %S"), aState, &KNifName);
- User::Leave(KErrUnknown);
- break;
- }
- return;
- }
-
- switch (aState)
- {
- case MControllerObserver::EStart:
- {
- // Update local state from TSY information originally from Agent.
- GetBinder()->UpdateContextConfigL(*iAgentProvision->iGprsConfig);
- GetBinder()->UpdateConnectionSpeed(iAgentProvision->iConnectionSpeed);
-
- _LOG_L1C2(_L8("Port details %S"), &iProvision->GetPortName());
- iBcaController->SetPort(iProvision->GetPortName());
-
- _LOG_L1C3(_L8("bcaName details %S,%S"),&iProvision->GetBCAStack(), &iProvision->GetBCAName());
- iBcaController->SetBcaStackAndName(iProvision->GetBCAStack(), iProvision->GetBCAName());
-
- _LOG_L1C2(_L8("IAP ID details %u"), iProvision->GetIAPid());
- iBcaController->SetIapId(iProvision->GetIAPid());
-
- UpdateContextState(RPacketContext::EStatusActive, KErrNone);
-
- iBcaController->StartL();
- }
- break;
- case MControllerObserver::EBcaController:
- _LOG_L1C1(_L8(" ***** NIF INITIALISED *****"));
- LinkLayerUp();
- break;
- default:
- _LOG_L2C3(_L8("ERROR CRawIPFlow: Unknown state:%d in NIF: %S"), aState, &KNifName);
- User::Leave(KErrUnknown);
- break;
- }
- }
-
-void CRawIPFlow::ShutDown(TInitialisationState aState, 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_L1C4(_L8("CRawIPFlow %08x:\tShutDown(aState %d, aError %d)"),
- this, aState, 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;
- }
-
- switch (aState)
- {
- case MControllerObserver::EInitialised:
- iBcaController->Stop(aError);
- break;
- case MControllerObserver::EBcaController:
- LinkLayerDown(iInitError);
- break;
- default:
- _LOG_L2C1(_L8("ERROR CRawIPFlow: Unknown Shutdown step"));
- _BTT_PANIC(KNifName,KNifUnknownShutDownState);
- break;
- }
- }
-
-CBinderBase* CRawIPFlow::GetBinder()
-/**
- * Returns a pointer to the Binder class
- *
- * @return a pointer to a CBinderBase derived class
- */
- {
- return iBinder;
- }
-
-CBcaIoController* CRawIPFlow::GetBcaController()
-/**
- * Returns a pointer to the CBcaIoController class
- *
- * @return a pointer to CBcaIoController
- */
- {
- return iBcaController;
- }
-
-void CRawIPFlow::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("CRawIPFlow %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
-//
-
-MFlowBinderControl* CRawIPFlow::DoGetBinderControlL()
- {
- return iBinderControl;
- }
-
-// =====================================================================================
-//
-// MFlowBinderControl methods
-//
-
-MLowerControl* CRawIPFlow::GetControlL(const TDesC8& aProtocol)
- {
-#ifdef __BTT_LOGGING__
- //TBuf8<256> debugBuffer;
- //debugBuffer.Copy(aProtocol);
- _LOG_L1C3(_L8("CRawIPFlow %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
- iBcaController->SetType(KIp4FrameType);
-#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
- }
- else
- {
- _LOG_L1C2(_L8("CRawIPFlow %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
- iBcaController->SetType(KIp6FrameType);
-#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
- }
- else
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tGetControlL(): IPv6 binder already exists"), this);
- }
- }
- else
- {
- User::Leave(KErrNotSupported);
- }
-
- return iBinder;
- }
-
-MLowerDataSender* CRawIPFlow::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, 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(), TCFControlProvider::TActive().CRef());
- return iBinder->Bind(aReceiver, aControl);
- }
-
-void CRawIPFlow::Unbind(MUpperDataReceiver* aUpperReceiver, MUpperControl* aUpperControl)
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tUnbind()"), this);
-
- if (iBinder)
- {
- iBinder->Unbind(aUpperReceiver, aUpperControl);
-
- delete iBinder;
- iBinder = NULL;
- }
-
- SendDataClientIdleIfNoClients();
- }
-
-
-void CRawIPFlow::SendDataClientIdleIfNoClients()
- {
- if (iBinder == NULL)
- {
- iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
- }
- }
-
-CSubConnectionFlowBase* CRawIPFlow::Flow()
-/**
-Return the Flow corresponding to the MFlowBinderControl
-*/
- {
- return this;
- }
-
-// =====================================================================================
-//
-// Messages::ANode
-//
-
-void CRawIPFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
- {
- CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
-
- if (aMessage.IsMessage<TEBase::TError>())
- {
- SubConnectionError(static_cast<TEBase::TError&>(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 (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
- {
- switch (aMessage.MessageId().MessageId())
- {
- case TCFDataClient::TStart::EId :
- StartFlowL();
- break;
- case TCFDataClient::TStop::EId :
- StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
- break;
- case TCFDataClient::TProvisionConfig::EId:
- ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
- break;
- case TCFDataClient::TBindTo::EId:
- {
- TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(aMessage);
- if (!bindToReq.iNodeId.IsNull())
- {
- User::Leave(KErrNotSupported);
- }
- RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef());
- }
- break;
- default:
-//TODO - logging
- ASSERT(EFalse);
- }
- }
- else if (TCFFlow::ERealmId == aMessage.MessageId().Realm())
- {
- switch (aMessage.MessageId().MessageId())
- {
- case TCFFlow::TBlock::EId :
- {
- // if there is a packet being sent and it completes
- // flow control will stop sending any further packets
- // while the flow is blocked.
-
- iBcaController->BlockSending();
- }
- break;
- case TCFFlow::TUnBlock::EId :
- {
- // ResumeSending is specific for the unblocking the flow - it
- // cancels the flow control and restarts the flow appropriately
- // (i.e. if there is a packet outstanding, messages in the queue
- // or idle and no queue).
- iBcaController->ResumeSending();
- }
- break;
- case TCFFlow::TRejoin::EId:
- {
- TCFFlow::TRejoin& rejoinMsg = message_cast<TCFFlow::TRejoin>(aMessage);
- TDefaultFlowFactoryQuery query(rejoinMsg.iNodeId);
- CRawIPFlow* otherFlow = static_cast<CRawIPFlow*>(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<TNodeId>(rejoinMsg.iNodeId));
- }
- break;
- default:
-//TODO - logging
- ASSERT(EFalse);
- }
- }
- else if (TLinkMessage::ERealmId == aMessage.MessageId().Realm())
- {
- switch (aMessage.MessageId().MessageId())
- {
- case TLinkMessage::TAgentToFlowNotification::EId:
- {
- TLinkMessage::TAgentToFlowNotification& msg = static_cast<TLinkMessage::TAgentToFlowNotification&>(aMessage);
- Notification(msg.iValue);
- break;
- }
- default:
- ASSERT(EFalse);
- }
- }
- else // not a recognised realm or message
- {
- ASSERT(EFalse);
- }
- }
-
-
-// =====================================================================================
-//
-// Methods for handling incoming SCPR messages
-//
-
-void CRawIPFlow::SubConnectionGoingDown()
- {
- }
-
-void CRawIPFlow::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 CRawIPFlow::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("CRawIPFlow %08x:\tProvisionConfig()"), this);
-
- AccessPointConfig().Close();
- AccessPointConfig().Open(aConfigData);
-
- iProvision = static_cast<const CBCAProvision*>(AccessPointConfig().FindExtension(
- STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId)));
-
- }
-
-void CRawIPFlow::DynamicProvisionConfigL()
-/**
-Retrieve provisioning information available only at StartFlow time.
-*/
- {
- if (iProvision == NULL)
- {
- _LOG_L1C1(_L8("CRawIPFlow:\tProvisionConfigL() - CBCAProvision config incomplete"));
- iProvisionError = KErrCorrupt;
- return;
- }
-
- ASSERT(iAgentProvision == NULL);
- iAgentProvision = static_cast<const CRawIpAgentConfig*>(AccessPointConfig().FindExtension(
- STypeId::CreateSTypeId(CRawIpAgentConfig::EUid, CRawIpAgentConfig::ETypeId)));
-
- if (iAgentProvision == NULL)
- {
- User::Leave(KErrCorrupt);
- }
-
- const CIPConfig* wcdmaIpProvision = static_cast<const CIPConfig*>(AccessPointConfig().FindExtension(
- STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId)));
- if (wcdmaIpProvision == NULL)
- {
- _LOG_L1C2(_L8("CRawIPFlow %08x:\tDynamicProvisionConfigL() - WCDMA config incomplete"), this);
- iProvisionError = KErrCorrupt;
- return;
- }
- // Pass pointer to binder specific provisioning information to binder
- if (iBinder)
- {
- iBinder->SetProvision(*wcdmaIpProvision);
- }
- }
-
-
-void CRawIPFlow::Destroy()
-/**
-Handle Destroy message from SCPR.
-*/
- {
- DeleteThisFlow();
- }
-
-void CRawIPFlow::Notification(TInt aEvent)
-/**
-Handle Generic Link Tier messages from SCPR.
-
-These used to be implemented as Agent <-> NIF Notifications, hence the method name to promote
-some historical understanding.
-*/
- {
- _LOG_L1C3(_L8("CRawIPFlow %08x:\tNotification(aEvent %d)"), this, aEvent);
-
- switch (aEvent)
- {
- case EAgentToNifEventTypeDisableTimers: //GPRS suspension
- {
- _LOG_L1C1(_L8("CRawIPFlow::Received Suspend from Agent..."));
-
- // Let the BCA controller know that data can no longer be sent over
- // the PDP context.
- iBcaController->BlockSending();
-
- break;
- }
-
- case EAgentToNifEventTypeEnableTimers: //GPRS resumption
- {
- _LOG_L1C1(_L8("CRawIPFlow::Received Resume from Agent..."));
- iBcaController->ResumeSending();
-
- break;
- }
- case (EAgentToNifEventTypeDisableConnection) :
- {
- // This is handled by NIFMAN and passed to Flow as a Stop() call
- _LOG_L1C1(_L8("CRawIPFlow::Received Disable connection from Agent..."));
- break;
- }
-
- default :
- {
- _LOG_L1C2(_L8("CRawIPFlow::Received Notification [%d] from Agent..."), aEvent);
- break;
- }
- }//endswitch
- }
-
-
-ESock::MLowerControl* CRawIPFlow::TBinderControlProxy::GetControlL(const TDesC8& aProtocol)
- {
- return RawIPFlow().GetControlL(aProtocol);
- }
-
-ESock::MLowerDataSender* CRawIPFlow::TBinderControlProxy::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
- {
- return RawIPFlow().BindL(aProtocol, aReceiver, aControl);
- }
-
-void CRawIPFlow::TBinderControlProxy::Unbind(ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
- {
- return RawIPFlow().Unbind(aReceiver, aControl);
- }
-
-CSubConnectionFlowBase* CRawIPFlow::TBinderControlProxy::Flow()
- {
- return iFlow;
- }
-
-// =====================================================================================
-//
-// Utility functions
-//
-
-void CRawIPFlow::PostProgressMessage(TInt aStage, TInt aError)
- {
- iSubConnectionProvider.PostMessage(Id(), 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-2010 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 <f32file.h>
+#include <nifman.h>
+#include <nifmbuf.h>
+#include <in_iface.h>
+#include <nifvar.h>
+#include "IPv4Binder.h"
+#include "IPv6Binder.h"
+#include "RawIPFlow.h"
+#include <comms-infras/linkprovision.h>
+#include <comms-infras/linkmessages.h>
+#include <comms-infras/ss_metaconnprov.h> // for SAccessPointConfig
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_child.h>
+#include <comms-infras/ss_nodemessages_flow.h>
+
+using namespace Messages;
+using namespace MeshMachine;
+using namespace ESock;
+
+#ifdef __FLOG_ACTIVE
+//These variables are used only if flog is active.
+_LIT8(KTcpDumpFirstTag,"TcpDump");
+static const TUint16 KTcpDumpLinkType = 12;
+#endif
+
+CRawIPFlow::CRawIPFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf, CBttLogger* aTheLogger)
+/**
+ * Constructor.
+ *
+ * @param aFactory Reference to the factory which created this object.
+ * @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, CRawIPFlow);
+ }
+
+void CRawIPFlow::ConstructL()
+/**
+ * Second-phase constructor. Creates the Etel
+ * control engine
+ *
+ * @param aName The name of the NIF (unused)
+ */
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tConstructL()"), this);
+ iBinderControl = new (ELeave) TBinderControlProxy(*this);
+ iBcaController = CBcaIoController::NewL(*this, iTheLogger);
+ }
+
+CRawIPFlow::~CRawIPFlow()
+/**
+ * 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, CRawIPFlow);
+ // Cleanup when stop was not called - harmless as it null's the pointer
+ __PACKETLOG_DELETE;
+ }
+
+void CRawIPFlow::StartFlowL()
+/**
+ * Starts the Flow up. This process involves connecting to the BCA. When startup is
+ * complete, LinkLayerUp() will be called.
+ *
+ * Called in response to corresponding SCPR message.
+ *
+ * @return Allways KErrNone
+ */
+ {
+ ASSERT(iStarting==EFalse);
+ iStarting = ETrue;
+ _LOG_L1C2(_L8("CRawIPFlow %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(MControllerObserver::EStart, KErrNone);
+
+ //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<KModemNameLen> modemName;
+
+ _LIT8(KDoubleColon, "::");
+
+ modemName.Copy(iProvision->GetPortName());
+ const TInt pos = modemName.FindC((const TDesC8&)KDoubleColon);
+ if(pos != KErrNotFound)
+ {
+ modemName.Delete(pos, 2);
+ }
+
+ //append time stamp
+ const TUint KTimeStampLen = 8;
+ TBuf8<KTimeStampLen> 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<KLogTextLen> 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 CRawIPFlow::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("CRawIPFlow %08x:\tLinkLayerUp()"), this);
+
+ iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+
+
+ iBinder->StartSending();
+ iStarted = ETrue;
+ iStarting = EFalse;
+ }
+
+void CRawIPFlow::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("CRawIPFlow %08x:\tLinkLayerDown(aError %d)"), this, aError);
+ __PACKETLOG_DELETE;
+
+ if (iStopping)
+ {
+ iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef());
+ }
+ else if (iStarting)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TEBase::TError(TCFServiceProvider::TStart::Id(), aError).CRef());
+ }
+ else
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef());
+ }
+
+ iStarted = EFalse;
+ iStarting = EFalse;
+ iStopping = EFalse;
+ }
+
+void CRawIPFlow::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("CRawIPFlow %08x:\tStopFlow(aError %d)"), this, aError);
+ __PACKETLOG_DELETE;
+ iStopping = ETrue;
+ ShutDown(MControllerObserver::EInitialised, aError);
+ }
+
+MLowerDataSender::TSendResult CRawIPFlow::SendPacket(RMBufChain& aPdu, TAny* /*aProtocol*/,
+ TUint16 /*aType*/)
+/**
+ * Sends a packet, via the BCA controller. This method is protocol-agnostic,
+ * and is called by the IPv4 and IPv6 binder to actually send packets.
+ *
+ * @param aPdu The packet to send
+ * @return MLowerDataSender::TSendResult
+ */
+ {
+ _LOG_L1C3(_L8("CRawIPFlow %08x:\tSendPacket(): length=%d"),
+ this, aPdu.Length() - aPdu.First()->Length());
+
+ __PACKETLOG_WRITE_PACKET(aPdu, 0);
+ return iBcaController->Send(aPdu);
+ }
+
+void CRawIPFlow::Process(RMBufChain& aPdu, TUint16 aProtocolCode)
+/**
+ * Handles incoming packets which have been passed up from the BCA controller.
+ * If the IPv4 binder wants to process the packet, it hands it on; otherwise,
+ * the packet is binned.
+ *
+ * @param aPdu The incoming packet
+ */
+ {
+ _LOG_L1C3(_L8("CRawIPFlow %08x:\tProcess() [aPdu length=%d]"),
+ this, aPdu.Length() - aPdu.First()->Length());
+
+ // If the packet has zero or negative length, bin it.
+ if ((aPdu.Length() - aPdu.First()->Length()) <= 0)
+ {
+ _LOG_L1C1(_L8("Dumped packet: illegal length"));
+ aPdu.Free();
+ return;
+ }
+
+ // See if the protocol interface wants the packet.
+ if (iBinder && iBinder->WantsProtocol(aProtocolCode))
+ {
+ __PACKETLOG_WRITE_PACKET(aPdu, 0);
+ iBinder->Process(aPdu);
+ }
+ else
+ {
+ // The protocol didn't want the packet, so bin it.
+ _LOG_L1C2(_L8("Packet was not processed: freeing (protocol code: %X)"),
+ aProtocolCode);
+ if (iBinder == NULL)
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tProcess(): NOTE: Binder not present"), this);
+ }
+ aPdu.Free();
+ }
+ }
+
+void CRawIPFlow::ResumeSending()
+/**
+ * Notifies the protocol interface that it can resume sending packets.
+ */
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tResumeSending()"), this);
+
+ if (iBinder)
+ {
+ iBinder->StartSending();
+ }
+ else
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tResumeSending(): NOTE: Binder not present"), this);
+ }
+ }
+
+void CRawIPFlow::InitialiseL(TInitialisationState aState, TInt aError)
+/**
+ * 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_L1C4(_L8("CRawIPFlow %08x:\tInitialiseL(aState %d, aError %d)"),
+ this, aState, aError);
+
+ if (aError != KErrNone)
+ {
+ _LOG_L2C2(_L8(" *** FAILED to initialise NIF *** Error =%d"),aError);
+
+ // Initialise shutdown sequence
+ switch (aState)
+ {
+ case MControllerObserver::EBcaController:
+ ShutDown(MControllerObserver::EInitialised, aError);
+ break;
+ default:
+ _LOG_L2C3(_L8("ERROR CRawIPFlow: Unknown state:%d in NIF: %S"), aState, &KNifName);
+ User::Leave(KErrUnknown);
+ break;
+ }
+ return;
+ }
+
+ switch (aState)
+ {
+ case MControllerObserver::EStart:
+ {
+ // Update local state from TSY information originally from Agent.
+ GetBinder()->UpdateContextConfigL(*iAgentProvision->iGprsConfig);
+ GetBinder()->UpdateConnectionSpeed(iAgentProvision->iConnectionSpeed);
+
+ _LOG_L1C2(_L8("Port details %S"), &iProvision->GetPortName());
+ iBcaController->SetPort(iProvision->GetPortName());
+
+ _LOG_L1C3(_L8("bcaName details %S,%S"),&iProvision->GetBCAStack(), &iProvision->GetBCAName());
+ iBcaController->SetBcaStackAndName(iProvision->GetBCAStack(), iProvision->GetBCAName());
+
+ _LOG_L1C2(_L8("IAP ID details %u"), iProvision->GetIAPid());
+ iBcaController->SetIapId(iProvision->GetIAPid());
+
+ UpdateContextState(RPacketContext::EStatusActive, KErrNone);
+
+ iBcaController->StartL();
+ }
+ break;
+ case MControllerObserver::EBcaController:
+ _LOG_L1C1(_L8(" ***** NIF INITIALISED *****"));
+ LinkLayerUp();
+ break;
+ default:
+ _LOG_L2C3(_L8("ERROR CRawIPFlow: Unknown state:%d in NIF: %S"), aState, &KNifName);
+ User::Leave(KErrUnknown);
+ break;
+ }
+ }
+
+void CRawIPFlow::ShutDown(TInitialisationState aState, 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_L1C4(_L8("CRawIPFlow %08x:\tShutDown(aState %d, aError %d)"),
+ this, aState, 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;
+ }
+
+ switch (aState)
+ {
+ case MControllerObserver::EInitialised:
+ iBcaController->Stop(aError);
+ break;
+ case MControllerObserver::EBcaController:
+ LinkLayerDown(iInitError);
+ break;
+ default:
+ _LOG_L2C1(_L8("ERROR CRawIPFlow: Unknown Shutdown step"));
+ _BTT_PANIC(KNifName,KNifUnknownShutDownState);
+ break;
+ }
+ }
+
+CBinderBase* CRawIPFlow::GetBinder()
+/**
+ * Returns a pointer to the Binder class
+ *
+ * @return a pointer to a CBinderBase derived class
+ */
+ {
+ return iBinder;
+ }
+
+CBcaIoController* CRawIPFlow::GetBcaController()
+/**
+ * Returns a pointer to the CBcaIoController class
+ *
+ * @return a pointer to CBcaIoController
+ */
+ {
+ return iBcaController;
+ }
+
+void CRawIPFlow::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("CRawIPFlow %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
+//
+
+MFlowBinderControl* CRawIPFlow::DoGetBinderControlL()
+ {
+ return iBinderControl;
+ }
+
+// =====================================================================================
+//
+// MFlowBinderControl methods
+//
+
+MLowerControl* CRawIPFlow::GetControlL(const TDesC8& aProtocol)
+ {
+#ifdef __BTT_LOGGING__
+ //TBuf8<256> debugBuffer;
+ //debugBuffer.Copy(aProtocol);
+ _LOG_L1C3(_L8("CRawIPFlow %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
+ iBcaController->SetType(KIp4FrameType);
+#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
+ }
+ else
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %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
+ iBcaController->SetType(KIp6FrameType);
+#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
+ }
+ else
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tGetControlL(): IPv6 binder already exists"), this);
+ }
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ return iBinder;
+ }
+
+MLowerDataSender* CRawIPFlow::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, 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(), TCFControlProvider::TActive().CRef());
+ return iBinder->Bind(aReceiver, aControl);
+ }
+
+void CRawIPFlow::Unbind(MUpperDataReceiver* aUpperReceiver, MUpperControl* aUpperControl)
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tUnbind()"), this);
+
+ if (iBinder)
+ {
+ iBinder->Unbind(aUpperReceiver, aUpperControl);
+
+ delete iBinder;
+ iBinder = NULL;
+ }
+
+ SendDataClientIdleIfNoClients();
+ }
+
+
+void CRawIPFlow::SendDataClientIdleIfNoClients()
+ {
+ if (iBinder == NULL)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
+ }
+ }
+
+CSubConnectionFlowBase* CRawIPFlow::Flow()
+/**
+Return the Flow corresponding to the MFlowBinderControl
+*/
+ {
+ return this;
+ }
+
+// =====================================================================================
+//
+// Messages::ANode
+//
+
+void CRawIPFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+ {
+ CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
+
+ if (aMessage.IsMessage<TEBase::TError>())
+ {
+ SubConnectionError(static_cast<TEBase::TError&>(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 (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFDataClient::TStart::EId :
+ StartFlowL();
+ break;
+ case TCFDataClient::TStop::EId :
+ StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
+ break;
+ case TCFDataClient::TProvisionConfig::EId:
+ ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
+ break;
+ case TCFDataClient::TBindTo::EId:
+ {
+ TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(aMessage);
+ if (!bindToReq.iNodeId.IsNull())
+ {
+ User::Leave(KErrNotSupported);
+ }
+ RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef());
+ }
+ break;
+ default:
+//TODO - logging
+ ASSERT(EFalse);
+ }
+ }
+ else if (TCFFlow::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFFlow::TBlock::EId :
+ {
+ // if there is a packet being sent and it completes
+ // flow control will stop sending any further packets
+ // while the flow is blocked.
+
+ iBcaController->BlockSending();
+ }
+ break;
+ case TCFFlow::TUnBlock::EId :
+ {
+ // ResumeSending is specific for the unblocking the flow - it
+ // cancels the flow control and restarts the flow appropriately
+ // (i.e. if there is a packet outstanding, messages in the queue
+ // or idle and no queue).
+ iBcaController->ResumeSending();
+ }
+ break;
+ case TCFFlow::TRejoin::EId:
+ {
+ TCFFlow::TRejoin& rejoinMsg = message_cast<TCFFlow::TRejoin>(aMessage);
+ TDefaultFlowFactoryQuery query(rejoinMsg.iNodeId);
+ CRawIPFlow* otherFlow = static_cast<CRawIPFlow*>(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<TNodeId>(rejoinMsg.iNodeId));
+ }
+ break;
+ default:
+//TODO - logging
+ ASSERT(EFalse);
+ }
+ }
+ else if (TLinkMessage::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TLinkMessage::TAgentToFlowNotification::EId:
+ {
+ TLinkMessage::TAgentToFlowNotification& msg = static_cast<TLinkMessage::TAgentToFlowNotification&>(aMessage);
+ Notification(msg.iValue);
+ break;
+ }
+ default:
+ ASSERT(EFalse);
+ }
+ }
+ else // not a recognised realm or message
+ {
+ ASSERT(EFalse);
+ }
+ }
+
+
+// =====================================================================================
+//
+// Methods for handling incoming SCPR messages
+//
+
+void CRawIPFlow::SubConnectionGoingDown()
+ {
+ }
+
+void CRawIPFlow::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 CRawIPFlow::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("CRawIPFlow %08x:\tProvisionConfig()"), this);
+
+ AccessPointConfig().Close();
+ AccessPointConfig().Open(aConfigData);
+
+ iProvision = static_cast<const CBCAProvision*>(AccessPointConfig().FindExtension(
+ STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId)));
+
+ }
+
+void CRawIPFlow::DynamicProvisionConfigL()
+/**
+Retrieve provisioning information available only at StartFlow time.
+*/
+ {
+ if (iProvision == NULL)
+ {
+ _LOG_L1C1(_L8("CRawIPFlow:\tProvisionConfigL() - CBCAProvision config incomplete"));
+ iProvisionError = KErrCorrupt;
+ return;
+ }
+
+ ASSERT(iAgentProvision == NULL);
+ iAgentProvision = static_cast<const CRawIpAgentConfig*>(AccessPointConfig().FindExtension(
+ STypeId::CreateSTypeId(CRawIpAgentConfig::EUid, CRawIpAgentConfig::ETypeId)));
+
+ if (iAgentProvision == NULL)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ const CIPConfig* wcdmaIpProvision = static_cast<const CIPConfig*>(AccessPointConfig().FindExtension(
+ STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId)));
+ if (wcdmaIpProvision == NULL)
+ {
+ _LOG_L1C2(_L8("CRawIPFlow %08x:\tDynamicProvisionConfigL() - WCDMA config incomplete"), this);
+ iProvisionError = KErrCorrupt;
+ return;
+ }
+ // Pass pointer to binder specific provisioning information to binder
+ if (iBinder)
+ {
+ iBinder->SetProvision(*wcdmaIpProvision);
+ }
+ }
+
+
+void CRawIPFlow::Destroy()
+/**
+Handle Destroy message from SCPR.
+*/
+ {
+ DeleteThisFlow();
+ }
+
+void CRawIPFlow::Notification(TInt aEvent)
+/**
+Handle Generic Link Tier messages from SCPR.
+
+These used to be implemented as Agent <-> NIF Notifications, hence the method name to promote
+some historical understanding.
+*/
+ {
+ _LOG_L1C3(_L8("CRawIPFlow %08x:\tNotification(aEvent %d)"), this, aEvent);
+
+ switch (aEvent)
+ {
+ case EAgentToNifEventTypeDisableTimers: //GPRS suspension
+ {
+ _LOG_L1C1(_L8("CRawIPFlow::Received Suspend from Agent..."));
+
+ // Let the BCA controller know that data can no longer be sent over
+ // the PDP context.
+ iBcaController->BlockSending();
+
+ break;
+ }
+
+ case EAgentToNifEventTypeEnableTimers: //GPRS resumption
+ {
+ _LOG_L1C1(_L8("CRawIPFlow::Received Resume from Agent..."));
+ iBcaController->ResumeSending();
+
+ break;
+ }
+ case (EAgentToNifEventTypeDisableConnection) :
+ {
+ // This is handled by NIFMAN and passed to Flow as a Stop() call
+ _LOG_L1C1(_L8("CRawIPFlow::Received Disable connection from Agent..."));
+ break;
+ }
+
+ default :
+ {
+ _LOG_L1C2(_L8("CRawIPFlow::Received Notification [%d] from Agent..."), aEvent);
+ break;
+ }
+ }//endswitch
+ }
+
+
+ESock::MLowerControl* CRawIPFlow::TBinderControlProxy::GetControlL(const TDesC8& aProtocol)
+ {
+ return RawIPFlow().GetControlL(aProtocol);
+ }
+
+ESock::MLowerDataSender* CRawIPFlow::TBinderControlProxy::BindL(const TDesC8& aProtocol, ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
+ {
+ return RawIPFlow().BindL(aProtocol, aReceiver, aControl);
+ }
+
+void CRawIPFlow::TBinderControlProxy::Unbind(ESock::MUpperDataReceiver* aReceiver, ESock::MUpperControl* aControl)
+ {
+ return RawIPFlow().Unbind(aReceiver, aControl);
+ }
+
+CSubConnectionFlowBase* CRawIPFlow::TBinderControlProxy::Flow()
+ {
+ return iFlow;
+ }
+
+// =====================================================================================
+//
+// Utility functions
+//
+
+void CRawIPFlow::PostProgressMessage(TInt aStage, TInt aError)
+ {
+ iSubConnectionProvider.PostMessage(Id(), 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()