linklayerprotocols/pppnif/SPPP/PPPLCP.CPP
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerprotocols/pppnif/SPPP/PPPLCP.CPP	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,2439 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+//
+
+#include <e32hal.h>
+#include <e32math.h>
+#include <f32file.h>
+#include <random.h>
+#include "PPPLOG.H"								// must appear before ss_log.h
+#include <comms-infras/ss_metaconnprov.h>
+#include <comms-infras/ss_log.h>				// for LOG_NODE_CREATE etc.
+#include "PPPLCP.H"
+#include "PPPAUTH.H"
+#include "PPPCCP.H"
+#include "PPPLRD.H"
+#include "MSCBCPC.H"
+#include "PPP_VER.H"
+#include "PppProg.h"
+#include <commsdattypeinfov1_1.h>
+#include <networking/ppplcp.h>
+#include "ncpip.h"
+#include "ncpip6.h"
+#include "PPPConfig.h"
+#include "pppmessages.h"
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_child.h>
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/ss_nodemessages_flow.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <nifvar_internal.h>
+#endif
+
+using namespace Elements;
+using namespace Messages;
+using namespace MeshMachine;
+using namespace ESock;
+
+static const TInt KMinValueForMSCallBackCode=1000;
+
+//
+// PPP LCP
+//
+
+#ifdef __VC32__
+// warning C4355: 'this' : used in base member initializer list
+#pragma warning (disable:4355)
+#endif
+
+#if defined ESOCK_LOGGING_ACTIVE || defined SYMBIAN_TRACE_ENABLE
+_LIT8(KNif,"Ppp");
+#endif
+
+EXPORT_C CPppLcp* CPppLcp::NewL(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf)
+	{
+	CPppLcp* flow = new (ELeave) CPppLcp(aFactory, aSubConnId, aProtocolIntf);
+	return flow;
+	}
+
+// Registers as unknown initially as lists won't be initialised
+EXPORT_C CPppLcp::CPppLcp(ESock::CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConnId, ESock::CProtocolIntfBase* aProtocolIntf)
+  : CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), MPppFsm(this, EPppPhaseAll, KPppIdLcp), MPppOptionsExtender(),
+    iInitialised(EFalse),
+    iSavedError(KErrNone),
+    iTerminateAction(MNifIfNotify::EDisconnect),
+    iLastRequest(Messages::TNodeSignal::TMessageId()),
+    iLastRequestErrored(EFalse)
+	{
+    __FLOG_OPEN(KCFNodeTag, KNif);
+	LOG_NODE_CREATE1(KNif, CPppLcp, " [factory=%08x]", &aFactory);
+    __DECLARE_FSM_NAME(_S("LCP"));
+	iRecvrList.SetOffset(_FOFF(MPppRecvr, iPppRecvrListLink));
+    }
+
+#ifdef __VC32__
+#pragma warning (default:4355)
+#endif
+
+EXPORT_C CPppLcp::~CPppLcp()
+	{
+	PppNcpMsCbcpFactory::Delete( iPppMsCbcp );
+	iPppMsCbcp=NULL;
+	delete iRecvTimeRemMessage;
+	iRecvTimeRemMessage = NULL;
+	delete iRecvIdentification;
+	iRecvIdentification = NULL;
+
+	delete iPppLink;
+	iPppLink = NULL;
+
+// N.B.: HDLC link relies on iLogger
+#if defined (_DEBUG)
+	delete iLogger;
+#endif
+
+
+	delete iPppAcp;
+	iPppAcp = NULL;
+    delete iCallbackInfo;
+	iCallbackInfo = NULL;
+	delete iCallbackIETFRequestPacket;
+	iCallbackIETFRequestPacket = NULL;
+	delete iPppCcp;
+	iPppCcp = NULL;
+	delete iPppLrd;
+	iPppLrd = NULL;
+	delete iContainerForDlls;
+	iContainerForDlls = NULL;
+
+	ASSERT(iBinder4 == NULL);
+	ASSERT(iBinder6 == NULL);
+
+	LOG_NODE_DESTROY(KNif, CPppLcp);
+
+    __FLOG_CLOSE;
+	}
+
+//-=========================================================
+// Messages::ANode methods
+//-=========================================================
+
+EXPORT_C void CPppLcp::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+    {
+	/**
+	   These messages may be received in the middle of another request, such as start.
+	   Therefore they must be handled before the CSubConnectionFlowBase::ReceivedL so
+	   that they do not override the last request originator for that
+	*/	
+   	if (TLinkMessage::ERealmId == aMessage.MessageId().Realm())
+       	{
+       	switch ((iLastRequest = aMessage.MessageId()).MessageId())
+           	{
+        case TLinkMessage::TAuthenticateResponse::EId:
+			{
+        	AuthenticateResponseMessage();
+        	break;
+			}
+        case TLinkMessage::TAgentToFlowNotification::EId:
+			{
+			TLinkMessage::TAgentToFlowNotification& msg = static_cast<TLinkMessage::TAgentToFlowNotification&>(aMessage);
+        	AgentToFlowNotification(msg.iValue);
+        	break;
+			}
+        default:
+	    	__FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+        	}
+        return;
+        }
+	
+	CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
+	if (TEBase::ERealmId == aMessage.MessageId().Realm())
+    	{
+    	switch ((iLastRequest = aMessage.MessageId()).MessageId())
+        	{
+        case TEBase::TError::EId :
+            SubConnectionError(static_cast<TEBase::TError&>(aMessage).iValue);
+            break;
+        case TEBase::TCancel::EId :
+        	if (iMMState != EStarting)
+	        	{
+	        	User::Leave(KErrNotReady);
+	        	}
+			DoStopFlow(KErrCancel, MNifIfNotify::EDisconnect);
+			break;
+        default:
+		    __FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+			}
+		return;
+		}
+    else if (TEChild::ERealmId == aMessage.MessageId().Realm())
+    	{
+    	switch ((iLastRequest = aMessage.MessageId()).MessageId())
+        	{
+        case TEChild::TDestroy::EId :
+            Destroy();
+            break;
+        default:
+		    __FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+			}
+		return;
+		}
+    else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
+    	{
+    	switch ((iLastRequest = 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:
+		    __FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+			}
+		return;
+		}
+    else if (TCFFlow::ERealmId == aMessage.MessageId().Realm())
+    	{
+    	switch ((iLastRequest = aMessage.MessageId()).MessageId())
+        	{
+        case TCFFlow::TBlock::EId :
+            if (iBinder4)
+            	{
+            	iBinder4->BlockFlow(MLowerControl::EDisableAllOtherBindersOnFlow);
+            	}
+            if (iBinder6)
+            	{
+            	iBinder6->BlockFlow(MLowerControl::EDisableAllOtherBindersOnFlow);
+            	}
+            break;
+        case TCFFlow::TUnBlock::EId :
+            if (iBinder4)
+            	{
+            	iBinder4->SendFlowOn();
+            	}
+            if (iBinder6)
+            	{
+            	iBinder6->SendFlowOn();
+            	}
+            break;
+        default:
+		    __FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+			}
+		return;
+		}
+    else if (TCFMessage::ERealmId == aMessage.MessageId().Realm())
+    	{
+		__FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+		PppPanic(EPppPanic_UnexpectedSCPRMessage);
+		return;
+		}
+    else if (TCFMessage::ERealmId == aMessage.MessageId().Realm())
+    	{
+    	switch ((iLastRequest = aMessage.MessageId()).MessageId())
+        	{
+        case TCFMessage::TStateChange::EId :
+            __FLOG(_L8("WARNING: CPppLcp::\tReceivedL() - I have received a TStateChange and I have ignored it"));
+            break;
+        default:
+		    __FLOG_2(_L8("CPppLcp\tReceivedL() unexpected message received [%08x,%d]"), aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
+			PppPanic(EPppPanic_UnexpectedSCPRMessage);
+			}
+		return;
+		}
+    }
+
+//-=========================================================
+// Methods for handling SCPR messages
+//-=========================================================
+
+EXPORT_C void CPppLcp::SubConnectionGoingDown()
+    {
+    }
+
+EXPORT_C void CPppLcp::SubConnectionError(TInt /*aError*/)
+    {
+    }
+
+EXPORT_C void CPppLcp::StartFlowL()
+    {
+    ASSERT(iMMState == 0);
+
+	if (iSavedError)
+		{
+		// Provisioning error has already occurred
+	    __FLOG_1(_L8("CPppLcp:\tStartFlowL() error %d"), iSavedError);
+		User::Leave(iSavedError);
+		}
+
+    __FLOG(_L8("CPppLcp::\tStartFlowL()"));
+
+	User::LeaveIfError(DoStartFlow());
+    iMMState = EStarting;
+    }
+
+EXPORT_C void CPppLcp::StopFlow(TInt aError)
+    {
+    __FLOG_1(_L8("CPppLcp::\tStopFlow(%d)"), aError);
+    iMMState = EStopping;
+    DoStopFlow(aError, MNifIfNotify::EDisconnect);
+    }
+
+EXPORT_C void CPppLcp::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData)
+    {
+    iSavedError = KErrNone;
+
+    TRAPD(err, ProvisionConfigL(aConfigData));
+    if (err)
+        {
+        __FLOG_1(_L8("CPppLcp::\tProvisionConfig(): error %d"), err);
+        iSavedError = err;		// report error later on TCFDataClient::TStart message - there no response to TProvisionConfig message
+        }
+    }
+
+EXPORT_C void CPppLcp::Destroy()
+    {
+    // No-one should be bound to us from above if we are about to disappear.
+    ASSERT(iBinder4 == NULL && iBinder6 == NULL);
+	DeleteThisFlow();
+    }
+
+EXPORT_C void CPppLcp::AuthenticateResponseMessage()
+/**
+Process link specific messages.
+*/
+	{
+	// Retrieve credentials from control side memory
+	ASSERT(iAgentProvision); //should have been cheked before attempting
+	                         //authentication.
+	iCredentials = iAgentProvision->Credentials();
+	ASSERT(iCredentials);
+	TInt authErr = KErrNone;
+	CPppAuthentication* p = iAuthenticate;
+	iAuthenticate = NULL;
+	if((authErr = iCredentials->GetResult())==KErrNone)
+		{
+		iAuthenticateDone = ETrue;
+		}
+	if (p)
+    	{
+    	//may have bailed out due to tear down in progress.
+    	p->CallAuthenticateComplete(authErr);
+    	}
+
+
+	if (authErr != KErrNone)
+    	{
+    	PostErrorMessage(authErr);
+    	}
+	}
+
+EXPORT_C void CPppLcp::AgentToFlowNotification(TInt aNotificationId)
+    {
+    TInt err;
+    if ((err = NotificationMessage(TAgentToNifEventType(aNotificationId))) != KErrNone)
+        {
+		if (iMMState == EStarted)
+			{
+			PostFlowDownMessage(err);
+			}
+		else
+			{
+			PostErrorMessage(err);
+			}
+        }
+    }
+
+TInt CPppLcp::NotificationMessage(TAgentToNifEventType aNotificationId)
+	{
+	switch(aNotificationId)
+		{
+	case EAgentToNifEventTypeModifyInitialTimer:
+		// Notification destined for binders
+		if (iBinder4)
+			{
+			return iBinder4->Notification(aNotificationId);
+			}
+		if (iBinder6)
+			{
+			return iBinder6->Notification(aNotificationId);
+			}
+		break;
+
+	case EAgentToNifEventTypeDisableTimers:
+	case EAgentToNifEventTypeEnableTimers:
+		return Notification(aNotificationId, NULL);
+
+	case EAgentToNifEventTypeGetDataTransfer:
+		break;
+
+	default:
+		PppPanic(EPppPanic_UnexpectedSCPRMessage);
+		}
+	return KErrNotSupported;		// keep compiler happy
+	}
+
+
+//
+// Utility functions for sending messages to SCPR
+//
+void CPppLcp::PostProgressMessage(TInt aStage, TInt aError)
+	{
+	if (iLastStateChange.iStage != aStage || iLastStateChange.iError != aError)
+		{
+		//unsolicited send of TStateChange message
+		iSubConnectionProvider.PostMessage(Id(), TCFMessage::TStateChange(TStateChange(aStage, aError)).CRef());
+		iLastStateChange.iStage = aStage;
+		iLastStateChange.iError = aError;
+		}
+	}
+
+void CPppLcp::PostDataClientStartedMessage()
+	{
+    #ifdef __FLOG_ACTIVE
+		TPtrC8 ptr = GetMMStateName();
+	   	__FLOG_1(_L8("CPppLcp:\tPostDataClientStartedMessage() - State: %S."), &ptr);
+ 	#endif
+
+	if (iMMState == EStarting)
+    	{
+    	iMMState = EStarted;
+    	//respond to earlier start request
+    	iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+    	}
+    
+    #ifdef __FLOG_ACTIVE
+    	if(iMMState != EStarted)
+    		{
+	 	   	__FLOG(_L8("ERROR: CPppLcp:\tPostDataClientStartedMessage() - LCP was unable to start"));
+    		}
+ 	#endif
+
+    __ASSERT_DEBUG(iMMState == EStarted, PppPanic(EPppPanic_LCPFailedToStart));
+	}
+
+void CPppLcp::PostFlowDownMessage(TInt aError)
+	{
+    #ifdef __FLOG_ACTIVE
+		TPtrC8 ptr = GetMMStateName();
+	   	__FLOG_2(_L8("CPppLcp:\tPostFlowDownMessage() - Error: %d, State: %S."), aError, &ptr);
+ 	#endif
+
+	ASSERT(aError != KErrNone);
+	if (iMMState == EStopping)
+	    {
+	    if (!iLastRequestErrored)
+	    	{
+			// Unexpected termination so send TError message
+			// Flow has gone down for an expected reason
+			iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef());
+			// The SCPR activity will terminate so wait for the next request
+			iLastRequestErrored = EFalse;
+	    	}
+	    else
+	    	{
+			// TError message has already been sent so ignore
+	    	iLastRequestErrored = EFalse;
+			}
+	    }
+    else if (iMMState == EStarted )
+        {
+        // Something has occured in the bearer causing the link to go down unexpectedly
+        // We use the RNodeInterface version of PostMessage because
+        // TDataClientGoneDown is always sent as an unsolicited message. We don't want the
+        // activity Id to be overidden.
+    	iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, iTerminateAction).CRef());
+	    }
+	else if (iMMState == EStarting)
+		{
+	    if (!iLastRequestErrored)
+	    	{
+			// Unexpected termination so send TError message
+			iLastRequestOriginator.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(), aError).CRef());
+			// The SCPR activity will terminate so wait for the next request
+			iLastRequestErrored = EFalse;
+	    	}
+	    else
+	    	{
+	    	// TError message has already been sent so ignore
+	    	iLastRequestErrored = EFalse;
+	    	}
+		}
+    iMMState = EStopped;
+	}
+
+void CPppLcp::PostErrorMessage(TInt aError)
+	{
+	ASSERT(aError != KErrNone);
+	// Error is always a response to an earlier received request
+	if (iLastRequestOriginator.IsOpen()) // Errors only relevant if responding to something
+		{
+		iLastRequestOriginator.ReplyTo(Id(), TEBase::TError(iLastRequest, aError).CRef());
+		}
+	}
+
+void CPppLcp::MaybePostDataClientIdle()
+    {
+    // Can only send DataClientIdle when the upper layer has unbound and the flow is stopped
+	if (iBinder4 == NULL && iBinder6 == NULL && !iSentIdle)
+		{
+		// TDataClientIdle is sent unsolicited to the control side
+   		iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
+		iSentIdle = ETrue;
+		}
+    }
+
+//-=========================================================
+// MFlowBinderControl methods
+//-=========================================================
+EXPORT_C MLowerControl* CPppLcp::GetControlL(const TDesC8& aProtocol)
+    {
+    User::LeaveIfError(iSavedError);
+    MLowerControl* lowerControl = NULL;
+	if (aProtocol.CompareF(KProtocol4()) == 0  ||
+		aProtocol.CompareF(KDescIcmp) == 0)
+		{
+        __FLOG(_L8("CPppLcp:\tGetLowerControlL(KProtocol4)"));
+		iBinder4 = CPppBinderIp4::NewL(this);
+        lowerControl = iBinder4;
+		}
+	else
+	if (aProtocol.CompareF(KProtocol6()) == 0)
+		{
+        __FLOG(_L8("CPppLcp:\tGetLowerControlL(KProtocol6)"));
+        iBinder6 = CPppBinderIp6::NewL(this);
+        lowerControl = iBinder6;
+		}
+    return lowerControl;
+    }
+
+EXPORT_C MLowerDataSender* CPppLcp::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
+    {
+    __FLOG_1(_L8("CPppLcp:\tBindL(%S)"), &aProtocol);
+
+	MLowerDataSender* lowerDataSender = NULL;
+
+	if (aProtocol.CompareF(KProtocol4()) == 0)
+		{
+		lowerDataSender = iBinder4->BindL(*aReceiver, *aControl);
+		}
+	else
+	if (aProtocol.CompareF(KProtocol6()) == 0)
+		{
+		lowerDataSender = iBinder6->BindL(*aReceiver, *aControl);
+		}
+
+	if (lowerDataSender)
+    	{
+    	// TDataClientActive is sent unsolicited to the control side
+    	iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
+    	}
+
+	return lowerDataSender;
+    }
+
+EXPORT_C void CPppLcp::Unbind(MUpperDataReceiver* aReceiver, MUpperControl* aControl)
+    {
+    __FLOG(_L8("CPppLcp:\tUnbind()"));
+
+	if (iBinder4 && iBinder4->MatchesUpperControl(aControl))
+		{
+        iBinder4->UnBind(*aReceiver, *aControl);
+		delete iBinder4;
+		iBinder4 = NULL;
+		}
+	else if (iBinder6 && iBinder6->MatchesUpperControl(aControl))
+		{
+        iBinder6->UnBind(*aReceiver, *aControl);
+		delete iBinder6;
+		iBinder6 = NULL;
+		}
+
+    MaybePostDataClientIdle();
+    }
+
+EXPORT_C CSubConnectionFlowBase* CPppLcp::Flow()
+	{
+	return this;
+	}
+
+//-=========================================================
+// MUpperDataReceiver methods
+//-=========================================================
+EXPORT_C void CPppLcp::Process(RMBufChain& aData)
+    {
+    LinkRecv(aData);
+    }
+
+//-=========================================================
+// MUpperControl methods
+//-=========================================================
+EXPORT_C void CPppLcp::StartSending()
+    {
+    if (iBinder4)
+    	{
+    	iBinder4->SendFlowOn();
+    	}
+    if (iBinder6)
+    	{
+    	iBinder6->SendFlowOn();
+    	}
+    }
+
+EXPORT_C void CPppLcp::Error(TInt aError)
+	{
+	if (iLastRequestOriginator.IsOpen())
+		{
+		// There is an outstanding request to complete
+		iLastRequestOriginator.ReplyTo(Id(),TEBase::TError(iLastRequest, aError).CRef());
+		iLastRequestErrored = ETrue;
+		}
+	else
+		{
+		// There is no outstanding request to complete
+		// This is a spurious error that will be ignored by
+		// the SCPR
+		__ASSERT_DEBUG(EFalse, PppPanic(EPppPanic_SpuriousError));
+		}
+    iLastRequest = Messages::TNodeSignal::TMessageId();
+	}
+
+//-=========================================================
+// Custom methods
+//-=========================================================
+// provide compatability for classes using old CNifIfLink style API
+void CPppLcp::ProvisionConfigL(const ESock::RMetaExtensionContainerC& aConfigData)
+/**
+Handle ProvisionConfig messages from SCPR.
+
+Provisioning requirements:
+
+- On receipt of a ProvisionConfig message, provisioning information in the SAccessPointConfig array
+  is validated, and the following structures must be present:
+  	- CBCAProvision, CIPConfig, CPppLcpConfig, CPppAuthConfig
+  if any are missing, then an error is saved in iSavedError (there is no response to ProvisionConfig).
+
+- on receipt of a StartFlow message:
+  - if iSavedError is not KErrNone, send a Error message to SCPr
+  - search SAccessPointConfig again (in RetrieveDynamicProvisionInfo()), for Agent provisioning
+    information:
+  	- CAgentProvisionInfo, CPppProvisionInfo
+  	if any are missing, send a Error message to SCPr
+*/
+    {
+	// Retrieve MetaConnectionProvider provisioned information
+  	iBCAProvision = static_cast<const CBCAProvision*>(
+  	      aConfigData.FindExtension(STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId)));
+  	iPppNcpConfig = static_cast<const CIPConfig*>(
+  	      aConfigData.FindExtension(STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId)));
+  	iPppLcpConfig = static_cast<const CPppLcpConfig*>(
+  	      aConfigData.FindExtension(STypeId::CreateSTypeId(CPppLcpConfig::EUid, CPppLcpConfig::ETypeId)));
+  	iPppAuthConfig  = static_cast<const CPppAuthConfig*>(
+  	      aConfigData.FindExtension(STypeId::CreateSTypeId(CPppAuthConfig::EUid, CPppAuthConfig::ETypeId)));
+
+    if (iBCAProvision == NULL || iPppNcpConfig == NULL || iPppLcpConfig == NULL || iPppAuthConfig == NULL)
+        {
+        __FLOG_4(_L8("CPppLcp:\tError: ProvisionConfigL() - PPP config incomplete: iBCAProvision %08x, iPppNcpConfig %08x, iPppLcpConfig %08x, iPppAuthConfig %08x"),
+        		 iBCAProvision, iPppNcpConfig, iPppLcpConfig, iPppAuthConfig);
+        User::Leave(KErrCorrupt);
+        }
+
+    iAccessPointConfig.Close();
+	iAccessPointConfig.Open(aConfigData);
+
+	if (!iInitialised && GetLcpConfig() && GetNcpConfig() && GetAuthConfig() && GetBCAProvision())
+		{
+		InitL();
+		iInitialised = ETrue;
+		}
+    }
+
+TInt CPppLcp::RetrieveDynamicProvisionInfo()
+/**
+Retrieve Provisioning Information which becomes available at Flow start time.
+
+@return KErrNone if success, KErrCorrupt if information not available.
+*/
+	{
+	// Retrieve Agent provisioned information.
+	// The only thing PPP needs from the Agent provisioned information are the credentials,
+	// whilst PPP doesn't always pursue authentication. It's ok to continue for now.
+	iAgentProvision = static_cast<const CAgentProvisionInfo*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CAgentProvisionInfo::EUid, CAgentProvisionInfo::ETypeId)));
+#ifdef _DEBUG
+	if (iAgentProvision == NULL)
+    	{
+        __FLOG_0(_L8("CPppLcp:\tRetrieveDynamicProvisionInfo() - Generic agent config not found, continuing"));
+    	}
+#endif
+
+	// Retrieve PPP specific Agent provisioned information
+	iPppAgentProvision = static_cast<const CPppProvisionInfo*>(
+          AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CPppProvisionInfo::EUid, CPppProvisionInfo::ETypeId)));
+
+    if (iPppAgentProvision == NULL)
+        {
+        __FLOG_0(_L8("CPppLcp:\tRetrieveDynamicProvisionInfo() - PPP agent config not found"));
+        return KErrCorrupt;
+        }
+	return KErrNone;
+	}
+
+void CPppLcp::Stop(TInt aReason, MNifIfNotify::TAction aAction)
+    {
+    DoStopFlow(aReason, aAction);
+    }
+
+MLowerDataSender::TSendResult CPppLcp::Send(RMBufChain& aPdu, TUint aProtocol)
+    {
+    return MLowerDataSender::TSendResult(iPppLink->Send(aPdu, aProtocol));
+    }
+
+//
+// Upcalls from Binders
+//
+
+// BinderLinkUp() overriden by CFProtocols derived from CPppLcp
+EXPORT_C void CPppLcp::BinderLinkUp(TPppProtocol aProtocol)
+	{
+	(void)aProtocol;
+	ASSERT(aProtocol >= CPppLcp::EPppProtocolBegin && aProtocol <= CPppLcp::EPppProtocolEnd);
+	FlowUp();
+	}
+
+void CPppLcp::Progress(TInt aStage, TInt aError)
+/**
+Upcall from binders to send progress
+
+@param aProgress progress parameters
+@param aProtocol protocol.  This field is primarily for the benefit of CFProtocols that
+derive from CPppLcp, so that they can identify which binder type is issuing the progress.
+
+*/
+	{
+    __FLOG_2(_L8("CPppLcp:\tProgress(%d, %d)"), aStage, aError);
+	PostProgressMessage(aStage, aError);
+	}
+
+void CPppLcp::FlowUp()
+    {
+    __FLOG(_L8("CPppLcp:\tFlowUp()"));
+	PostDataClientStartedMessage();
+    }
+
+void CPppLcp::FlowDown(TInt aError, MNifIfNotify::TAction aAction)
+    {
+    __FLOG_2(_L8("CPppLcp:\tFlowDown(%d, %d)"), aError, aAction);
+
+	// If ENoAction is specified, this is just an
+    // informational call indicating that the link has gone
+    // down briefly and is expected to go back up shortly.
+    if(aAction == MNifIfNotify::ENoAction)
+    	{
+    	return;
+    	}
+    	
+    if (aError == KErrNone)
+        {
+        //It is quite common for the fsm to pass an errorless down signal.
+        aError = KErrUnknown;
+        }
+
+    //awaiting FsmTermination phase complete to post flow down
+    iTerminateAction = aAction;
+    PostFlowDownMessage(aError);
+    }
+
+
+//-=========================================================
+// For CPPPAuthenticate methods - might be worth moving them elsewhere.
+//-=========================================================
+void CPppLcp::Authenticate(CPppAuthentication* aAp)
+	{
+	if(iAuthenticateDone)
+		{
+	    __FLOG(_L8("CPppLcp:\tAuthenticate(): calling CallAuthenticateComplete()"));
+		aAp->CallAuthenticateComplete(KErrNone);
+		return;
+		}
+
+	if(iAuthenticate)
+    	{
+    	aAp->CallAuthenticateComplete(KErrAlreadyExists);
+    	return;
+    	}
+
+    if (iAgentProvision == NULL)
+        {
+        //PPP decides to authenticate, but there is no
+        //agent provision structure holding the credentials.
+        aAp->CallAuthenticateComplete(KErrCorrupt);
+        }
+
+    __FLOG(_L8("CPppLcp:\tAuthenticate(): sending Authenticate message"));
+
+	// Send Authenticate message to SCPR requesting credentials for authentication.
+	// TAuthenticate is sent unsolicited to the control side
+	iSubConnectionProvider.PostMessage(Id(), TLinkMessage::TAuthenticate().CRef());
+
+    iAuthenticate = aAp;
+	}
+
+void CPppLcp::CancelAuthenticate(CPppAuthentication* aAp)
+	{
+
+	if(aAp==iAuthenticate)
+		{
+		iAuthenticate=0;
+		iLastRequestOriginator.ReplyTo(Id(), TEBase::TCancel().CRef());
+		}
+	}
+
+//-=========================================================
+// CSubConnectionFlowBase methods
+//-=========================================================
+EXPORT_C MFlowBinderControl* CPppLcp::DoGetBinderControlL()
+    {
+    return this;
+    }
+
+// ---- PPP Specifics ----
+void CPppLcp::InitL()
+/**
+Construct the Link Protocol Object
+
+@exception leaves if could not allocate memory
+@returns none
+ */
+	{
+	ASSERT(!iInitialised && GetLcpConfig() && GetNcpConfig() && GetAuthConfig() && GetBCAProvision());
+
+#ifdef ESOCK_LOGGING_ACTIVE
+	// instantiate logging object
+
+	ASSERT(iLogger == NULL);
+
+	iLogger = CPppLog::NewL();
+	iLogLevel = 1; //Set default log level
+
+	LOG( iLogger->Printf(_L("-----------------------------------------------------------------------------------------")); )
+	LOG( iLogger->Printf(_L("---- New PPP instance [0x%+08x] ------------------------------------------------------"), this); )
+	LOG( iLogger->Printf(_L("-----------------------------------------------------------------------------------------")); )
+
+  	// Determine the link mode early so everyone can read it
+  	iLinkMode = GetLcpConfig()->GetIfServerMode();
+  	LOG(
+  		if (iLinkMode == CPppLcpConfig::EPppLinkIsServer)
+  			{
+ 			iLogger->Printf(_L("PPP running in server mode"));
+  			}
+  		else
+  			{
+  			iLogger->Printf(_L("PPP running in client mode"));
+  			}
+  		)
+#endif
+
+	FsmConstructL();
+
+
+	// Use HDLC as lower layer
+	iPppLink = PppLink()->PppCreateLinkL(this, KNullDesC);
+
+	if(iPppLink)
+		{
+		iContainerForDlls = CObjectConIx::NewL();
+
+		//
+		// Note: Authentication credentials (iCredentials) are initialised from SCPR
+		// provisioning information.
+		//
+
+		// Create compression control protocol object
+		iPppCcp = CPppCcp::NewL(this);
+
+		// Create authentication protocol configuration object
+		iPppAcp = CPppAcp::NewL(this);
+
+		// Create link quality checking object
+		iPppLrd = CPppLrd::NewL(this);
+		Register();
+		}
+	}
+
+void CPppLcp::CallbackGrantedAndAuthenticated()
+/**
+To be called when the authentication (if any) has been completed successfully.
+If there's no authentication at all, this should be called at the
+point where the authentication phase would otherwise be.
+
+If the other end has agreed to our request for callback, then this causes NETDIAL
+to be notified that it's "all systems go" for callback.
+
+If the other end has not confirmed accepted our request for callback, or if we haven't asked,
+then this does nothing.
+*/
+	{
+	if (! iCallbackRequestGranted)
+		return;
+
+	iCallbackRequestGranted = EFalse;	// do this once only (cheat)
+
+	//
+	// The following used to be Notification(ENifToAgentEventTypePPPCallbackGranted), but
+	// has been converted to a progress to avoid having to define a special Flow to SCPR
+	// Notification() message.
+	PostProgressMessage(EPppProgressCallbackGranted, KErrNone);
+	}
+
+
+static const TInt KMaxCallbackRequestInfo = 256;
+
+class CallbackAction
+	{
+public:
+	static INLINE TBool	IsInfoFieldRequired( TCallbackAction aCallbackAction );
+	static INLINE TCallbackIETFRequestType  IETFRequestType( TCallbackAction aCallbackAction );
+	static INLINE TBool IsMSCBCP( TCallbackAction aCallbackAction );
+	static INLINE TMSCBCPAction MSCBCPAction( const TCallbackAction aAction );
+	};
+
+
+INLINE TMSCBCPAction CallbackAction::MSCBCPAction( const TCallbackAction aAction )
+	{
+	__ASSERT_DEBUG( aAction == ECallbackActionMSCBCPRequireClientSpecifiedNumber
+						|| aAction == ECallbackActionMSCBCPAcceptServerSpecifiedNumber
+						|| aAction == ECallbackActionMSCBCPOverrideServerSpecifiedNumber,
+					PppPanic(EPppPanic_PPPInvalidCallback) );
+
+	return (TMSCBCPAction) aAction;
+	}
+
+
+TBool CallbackAction::IsInfoFieldRequired( TCallbackAction aCallbackAction )
+	{
+	switch (aCallbackAction)
+		{
+	case ECallbackActionIETFType0:
+		return EFalse;
+	case ECallbackActionIETFType1:
+		return ETrue;
+	case ECallbackActionIETFType2:
+		return ETrue;
+	case ECallbackActionIETFType3:
+		return ETrue;
+	case ECallbackActionIETFType4:
+		return ETrue;
+	case ECallbackActionIETFType5:
+		return ETrue;
+	case ECallbackActionMSCBCPRequireClientSpecifiedNumber:
+		return ETrue;
+	case ECallbackActionMSCBCPAcceptServerSpecifiedNumber:
+		return EFalse;
+	case ECallbackActionMSCBCPOverrideServerSpecifiedNumber:
+		return ETrue;
+	default:
+		__ASSERT_DEBUG(EFalse, PppPanic(EPppPanic_PPPInvalidCallback));
+		return EFalse;
+		}
+	}
+
+
+inline TBool CallbackAction::IsMSCBCP( TCallbackAction aCallbackAction )
+	{
+	return int(aCallbackAction) > KMinValueForMSCallBackCode;	// MS codes are >1000
+	}
+
+
+TCallbackIETFRequestType CallbackAction::IETFRequestType( TCallbackAction aCallbackAction )
+	{
+	return CallbackAction::IsMSCBCP( aCallbackAction )
+				? ECallbackIETFRequestTypeMSCBCP
+				: TCallbackIETFRequestType( aCallbackAction );
+	}
+
+
+
+TBool CPppLcp::QueryExternalIPConfiguration()
+/**
+Returns the external IP configuration flag.
+@return	External IP configuration flag value. */
+	{
+	return iDoExternalIPConfiguration;
+	}
+
+void CPppLcp::InitCallbackInfoL()
+	{
+	if ( !GetLcpConfig()->GetIfCallbackEnabled() )
+    	{
+    	return;
+    	}
+	if ( GetPppAgentConfig()->IsDialIn() )
+    	{
+    	return;
+    	}
+
+	iCallbackEnabled = ETrue;
+	iCallbackAction = TCallbackAction(GetLcpConfig()->GetIfCallbackType());
+	iCallbackIETFRequestType = CallbackAction::IETFRequestType( iCallbackAction );
+	NewCallbackRequestInfoL( iCallbackIETFRequestType );
+
+	if ( CallbackAction::IsMSCBCP( iCallbackAction ) )
+		{
+		if ( CallbackAction::IsInfoFieldRequired( iCallbackAction ) )
+			{
+			// Get the info field from the NETDIAL database, for the benefit of MS-CBCP
+			GetCallbackInfoL();	// sets iCallbackInfo
+			}
+		iPppMsCbcp = PppNcpMsCbcpFactory::NewL(	this,				// CPppLcp* aLcp,
+												CallbackAction::MSCBCPAction( iCallbackAction ),	// TMSCBCPAction aAction,
+												iCallbackInfo,		// TUint8*  aCallbackInfo,
+												iCallbackInfoLen ); // TInt aCallbackInfoLen
+		}
+	}
+
+
+void CPppLcp::GetCallbackInfoL()
+/**
+Get the CallbackInfo field from the NETDIAL database
+Allocates a buffer for it, and (if successful)
+sets iCallbackInfo to point at the buffer allocated.
+
+@post iCallbackInfo, iCallbackInfoLen are set
+*/
+	{
+	if ( iCallbackInfo )	// already done it
+        {
+        return;
+        }
+  	TUint8*  p = new (ELeave) TUint8[ KMaxCallbackRequestInfo ];
+  	TPtr8 tptr( p, KMaxCallbackRequestInfo );
+    tptr.Copy(GetLcpConfig()->GetIfCallbackInfo());
+  	TInt len = tptr.Length();
+
+  	iCallbackInfo = p;
+  	iCallbackInfoLen = len;
+	__ASSERT_DEBUG( iCallbackInfo, PppPanic(EPppPanic_PPPNoCallbackInfo) );
+	__ASSERT_DEBUG( iCallbackInfoLen <=KMaxCallbackRequestInfo, PppPanic(EPppPanic_PPPInvalidCallback) );
+	}
+
+void CPppLcp::NewCallbackRequestInfoL( TCallbackIETFRequestType aRequestType )
+/**
+Allocates a buffer containing a PPP callback request packet a la draft RFC.
+
+Format is: [ length ] [ type ] [ .. info ... ]
+
+@post Sets iCallbackIETFRequestPacket to point to the buffer allocated
+
+@param aRequestType Callback IETF request type code
+*/
+	{
+
+	if ( iCallbackIETFRequestPacket )	// if buffer exists already, delete it
+		{
+		delete iCallbackIETFRequestPacket;
+		iCallbackIETFRequestPacket = NULL;
+		}
+	TInt len;
+	if ( aRequestType == ECallbackIETFRequestType0 || aRequestType == ECallbackIETFRequestTypeMSCBCP)
+		{
+		len = 0;
+		}
+	else
+		{
+		GetCallbackInfoL();	// Sets iCallbackInfo to be valid
+		__ASSERT_DEBUG( iCallbackInfo, PppPanic(EPppPanic_PPPNoCallbackInfo) );
+		len = iCallbackInfoLen;
+		}
+	__ASSERT_DEBUG( !iCallbackIETFRequestPacket, PppPanic(EPppPanic_PPPInvalidCallback) );
+
+	// Allocate space for the Operation byte i.e. aRequestType ( 0 - 4 )
+	iCallbackIETFRequestPacket = new (ELeave) TUint8[ len + 1 ];
+	// Set the length to include the Operation byte
+	iCallbackIETFRequestPacketLen = len+1;
+	// Set up the Operation Byte
+	iCallbackIETFRequestPacket[0] = TUint8( aRequestType );
+	// Append the database retrieved information field (Could be a Phone Number)
+	// Generic code will add Callback type code and length byte later on
+	if(len)
+		Mem::Copy( iCallbackIETFRequestPacket +1, iCallbackInfo, len);
+	}
+
+
+void CPppLcp::PhaseAdvancesBeyondAuthenticate()
+	{
+	CallbackGrantedAndAuthenticated();
+	}
+
+
+TBool CPppLcp::DoesDllExist(const TDesC& aFilename)
+/**
+Search to see if a loadable DLL does actually exist
+
+@param aFilename DLL filename
+
+@return ETrue if the file exists
+*/
+	{
+	TBool RetCode = EFalse;
+
+
+    RLibrary lib;
+	_LIT(KSysLibs,"\\SYSTEM\\LIBS\\");
+    if (lib.Load(aFilename, KSysLibs) == KErrNone)
+        {
+        RetCode = ETrue;
+        lib.Close();
+        }
+
+	return RetCode;
+	}
+
+TInt CPppLcp::DoStartFlow()
+/**
+Start the PPP link.
+
+@return Error code
+*/
+	{
+	TInt err = KErrNone;
+#if defined (_DEBUG)
+	// Move logging to new log file
+	TRAP(err, iLogger->SetLogFileNameL(GetNcpConfig()->GetPortName()));
+	if (err!=KErrNone)
+		{
+		// ** DO NOT forget to enclose any LOG() macros after an 'if' within '{...}' or else
+		// the first innocent source line after the LOG() statement will be swallowed
+		// by the 'if' when LOG() is empty !!
+		LOG( iLogger->Printf(_L("Could not change log file name for this instance of PPP [0x%+08x]"), this); )
+		}
+
+	if (GetLcpConfig()->GetISPName().Ptr())
+		{
+		_LIT(KLine64, "---------------------------------------------------------------");
+		LOG( iLogger->Printf(KLine64); )  ;
+		LOG( iLogger->Printf(_L("Calling ISP '%S' using modem on %S"), GetLcpConfig()->GetISPName().Ptr(), GetNcpConfig()->GetPortName().Ptr()); ) ;
+		LOG( iLogger->Printf(KLine64); ) ;
+		}
+#endif
+
+	err = RetrieveDynamicProvisionInfo();
+	if (err != KErrNone)
+		{
+		return err;
+		}
+
+    iDoLcpExts=GetLcpConfig()->GetEnableLcpExtensions();
+
+	// Are we doing external IP configuration (MobileIP)?
+	TRAPD(res, PppLink()->StartL();)
+
+	//Are we doing CCP ?
+	if (!GetLcpConfig()->GetEnableSwComp())
+		{
+		//Deregister CCP
+		if(iPppCcp)
+			iPppCcp->RemoveRegistration();
+		}
+
+	// Configure the FSM to never time out while connecting if we're a server
+	ConnectionPersist(PppLinkMode() == CPppLcpConfig::EPppLinkIsServer);
+
+	return res;
+	}
+
+void CPppLcp::DoStopFlow(TInt aReason, MNifIfNotify::TAction aAction)
+/**
+Cleanly stop the LCP link and notify the NIF.
+If aReason == KErrConnectionTerminated signal Authoritative stop: there is no graceful
+termination: PPP signals CNifAgentRef::LinkLayerDown to Nifman, which results in PPP deletion.
+
+@param aReason The reason the link is going down
+@param aAction The action to take once the link is down
+*/
+	{
+ 	LOG( iLogger->Printf(_L("CPppLcp::Stop: Administrative Close of PPP. aReason [%d], aAction [%d]"),aReason, aAction); )
+ 	iFsmTerminationCauseError = aReason;
+
+ 	// If it's an Authoritative Stop (KErrConnectionTerminated),
+ 	// we shut down as quickly as possible, with no concern for
+ 	// graceful termination. The assumption is that other networking components do the same, i.e.
+ 	// they do not expect us to shut down gracefully.
+ 	// We do not go through RFC-compliant PPP Termination sequence, because shutting down and releasing resources
+ 	// has higher priority than negotiationg with the peer.
+	if(KErrConnectionTerminated != aReason)  // Normal stop
+		{
+		if(iTerminateRequestEnabled) // Fully RFC1661 compliant shutdown, as opposed to "legacy" shutdown.
+		                             // Once the "legacy" shutdown (provided for back-compatibility) is removed,
+		                             // the check for TerminateRequestEnabled may be safely removed as well.
+			{
+			FsmLayerDown(aReason);
+ 			TerminateLink(aAction, aReason);
+ 			return;
+			}
+		else // "Legacy" shutdown sequence.
+		     // PPP terminates immediately, after making a "best-effort" attempt to send 1 LCP TerminateRequest.
+		     // Once this legacy behaviour is not required any more, this section of code may be safely removed.
+			{
+			TerminateLink(aAction, aReason); // "Best-effort" attempt to send TerminateRequest.
+			// Proceed to "Authoritative" shutdown. This may result in TerminateRequest being cancelled.
+			}
+		}
+
+	// This is the "Authoritative" shutdown sequence. If we are terminating gracefully, we will not get here.
+	// Inform Nifman that we are ready to be cleaned-up. We do not do full clean-up here,
+ 	// because this is done anyway in destructors, which will be invoked once Nifman tells PPP to delete itself.
+ 	// At this point we want to unblock Nifman as quickly as possible, to allow it to proceed with the rest
+ 	// of the Authoritative shutdown sequence.
+	PppLink()->Stop(aReason); // Make sure PPP does not use the Link after telling nifman that the NIF is finished.
+
+ 	// We need to inform Nifman from here only if it is authoritative shutdown.
+ 	// In other cases, FSM goes through state transitions on shutdown, which result
+ 	// in FsmTerminationPhaseComplete to be called, and notify the Nifman.
+ 	if(KErrConnectionTerminated == aReason)
+ 		{
+ 		// Tell Nifman that PPP is finished. After the Agent finishes (terminates the connection, air link, etc), Nifman
+ 		// closes the NIF, which results in PPP deletion. The call to delete PPP originates in Nifman, implemented as
+ 		// asynchronous callback. This call would invoke the destructors, which do the actual cleanup in the NIF.
+ 	 	//iNotify->LinkLayerDown(aReason, aAction); REMEK: DO SOMETHING HERE - TALK TO NADEEM,
+ 	 	                                          //the following line has been added as a replacement of this line.
+
+ 		PostProgressMessage(EPppProgressLinkDown, aReason);
+ 	 	PostFlowDownMessage(aReason);
+ 		}
+	}
+
+//
+// Protocols Manager
+//
+
+TInt CPppLcp::PppOpen()
+/**
+Called by an upper layer when it is started.
+
+@return Error code
+*/
+	{
+
+	LOG( iLogger->Printf(_L("PPPOpen - iOpenCount=%d\n"),iOpenCount); )
+	if (iOpenCount++>0)
+		return KErrNone;
+
+	return FsmOpen();
+	}
+
+void CPppLcp::PppClose(TInt aReason)
+/**
+Called by an upper layer when it is finished.
+
+@param aReason The reason the protocol is finished
+*/
+	{
+	LOG( iLogger->Printf(_L("PPPClose - iOpenCount=%d\r\n"),iOpenCount); )
+	if (--iOpenCount>0)
+		{
+		if (AllNcpsUp()) //This will need to happen when one ncp goes up but the other does not go up
+			{
+			FlowUp();
+			}
+		return;
+		}
+	FsmClose(aReason);
+	iNcpUpCount = 0;
+	}
+
+void CPppLcp::RegisterRecvr(MPppRecvr* aRecvr)
+/**
+Register an object that is interested in receiving certain packets.
+The receiver object knows the protocol number it is interested in.
+
+@param aRecvr Object to receive packets
+*/
+	{
+	iRecvrList.AddLast(*aRecvr);
+	if (aRecvr->iPppId==KPppIdLcp)
+		return;
+
+	if (iPhase>=aRecvr->iActivePhase)
+			aRecvr->LowerLayerUp();
+
+	else
+		aRecvr->LowerLayerDown(KErrNone);
+	}
+
+void CPppLcp::ReregisterRecvr(MPppRecvr* aRecvr)
+/**
+Reregister an object that is receiving certain packets.
+The receiver object knows the protocol number it is interested in.
+
+@param aRecvr Object registered to receive packets
+*/
+	{
+	aRecvr->Deque();
+	RegisterRecvr(aRecvr);
+	}
+
+void CPppLcp::DeregisterRecvr(MPppRecvr* aRecvr)
+/**
+Unregister an object that is no longer interested in receiving certain
+packets.
+
+@param aRecvr Object registered to receive packets
+*/
+	{
+	aRecvr->Deque();
+	}
+
+//
+// PPP Upcalls from Link
+//
+
+void CPppLcp::LinkRecv(RMBufChain& aPacket)
+/**
+Called by the link layer for each new PPP packet received.
+Search registered Recvr list and deliver to all recipients.
+
+@param aPacket MBuf chain containing received packet
+*/
+	{
+	MPppRecvr* rcvr;
+
+	RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPacket);
+	TUint prot = TPppAddr::Cast(info->iDstAddr).GetProtocol();
+
+   //
+   // For Van Jacobson compression have to tell NCPIP if a CRC error
+   // occurred, may as well tell all the protocols!!
+   //
+   const TBool CrcError = TPppAddr::Cast(info->iDstAddr).CRCError();
+
+	TDblQueIter<MPppRecvr> iter(iRecvrList);
+	while (rcvr = iter++, rcvr!=NULL)
+		{
+		if (CrcError)
+			{
+			rcvr->FrameError();
+			continue;
+			}
+
+		if (prot==rcvr->iPppId)
+			{
+			if (iPhase>=rcvr->iActivePhase)
+				{
+				rcvr->RecvFrame(aPacket);
+				return;
+				}
+			else
+				{
+				// Protocol is known, but not available so
+				// silent discard instead of reject
+				aPacket.Free();
+				}
+			}
+		}
+
+   if (CrcError)
+      {
+      //
+      // Have told everyone now so throw away the frame
+      //
+		aPacket.Free();
+      }
+
+
+	if (!aPacket.IsEmpty())
+		{
+		// Unrecognised protocol
+		// This line was commented out and consequently NBCF requests were not
+		// being rejected.
+
+
+ 		// Cisco Router fix
+ 		// There is a defect in some Cisco routers where they will send
+ 		// an authentication request before they have sent an LCP Config-Ack
+ 		// So if we are in the Ack-Sent state and we get an authentication request
+ 		// - i.e. CHAP (0xC223) or PAP (0xC023)) - then silently discard the packet
+ 		// rather than sending a Protocol reject
+
+ 		if ((iPhase == EPppPhaseEstablish) &&
+ 			(FsmState() == EPppFsmAckSent) &&
+ 			((prot == KPppIdChap) || (prot == KPppIdPap)))
+ 			{
+ 			; // don't send a protocol reject
+ 			LOG( iLogger->Printf(_L("CHAP / PAP Authenticate request received before entering the AUTHENTICATE phase: silently discarding packet\n")); )
+ 			}
+ 		else
+ 			FsmRejectPacket(aPacket, KPppLcpProtocolReject);
+
+		aPacket.Free();
+		}
+	}
+
+void CPppLcp::LinkLayerUp()
+/**
+Called from the lower layer when it becomes ready.
+*/
+	{
+	LOG( iLogger->Printf(_L("Link Layer Up")); )
+	MPppRecvr* rcvr = this;
+	rcvr->LowerLayerUp();
+//	PppOpen();
+	}
+
+void CPppLcp::LinkLayerDown(TInt aStatus)
+/**
+Called from the lower layer when it finishes shutting down.
+
+@param aStatus Error code indicating the reason the link is going down
+*/
+	{
+	// Note on errors:
+	// Link can be down due to 1 of 2 causes: Comms failure of some sort, OR closing the link
+	// by LCP. In the first case, we should get the Comms error from the link in aStatus.
+	// In the second case,we have our own error describing why LCP is shutting down the link.
+
+	if(KErrNone == iError) // Link reported failure. We didn't ask it to be closed
+		{
+		if(KErrNone == aStatus) // We have no error to work with!
+			{
+			// We absolutely must signal an error, otherwise Nifman will
+			// ignore NIF's notification in certain states (e.g. before KLinkLayerUp).
+			// This results in the interface and its ESock clients being stuck.
+			//
+			// After the first (outgoing) stage of callback, however, signalling EPppProgressLinkDown
+			// with an error (in FsmTerminationPhaseComplete()) incorrectly triggers Nifman to perform
+			// a connection retry with the next preference.  Passing KErrNone in this particular
+			// circumstance is okay.
+			//
+			if (iTerminateAction != MNifIfNotify::ECallBack)
+				{
+				iError = KErrUnknown;
+				}
+			}
+		else
+			{
+			iError = aStatus; // Report link error as PPP error.
+			}
+		}
+	// Else: we have an error code already. Most likely, as result of closing the link.
+
+	LOG( iLogger->Printf(_L("Link Layer Down reason %d\n"), aStatus); )
+	MPppRecvr* rcvr = this;
+	rcvr->LowerLayerDown(aStatus);
+	}
+
+
+void CPppLcp::LinkFlowOn()
+/**
+Link advisory flow on signal.
+*/
+	{
+	MPppRecvr* rcvr;
+	TDblQueIter<MPppRecvr> iter(iRecvrList);
+	while (rcvr = iter++, rcvr!=NULL)
+		rcvr->FlowOn();
+	}
+
+
+void CPppLcp::PhaseAdvance(TPppPhase aNewPhase)
+/**
+Switch to the next PPP operation phase.
+When the PPP phase is advanced, protocols may have reached
+their active phase and so have to be bound in to the
+main data path and signalled active.
+
+@param aNewPhase Phase just entered
+*/
+	{
+	TPppPhase oldphase = iPhase;
+	iPhase = aNewPhase;
+	LOG( iLogger->DumpPhase(oldphase, aNewPhase); )
+	if (oldphase==aNewPhase)
+		return;
+	TBool skip = ETrue;
+
+	if (!iRecvrList.IsEmpty())
+		{
+		MPppRecvr* rcvr;
+		TDblQueIter<MPppRecvr> iter(iRecvrList);
+		while (rcvr=iter++, rcvr!=NULL)
+			{
+			if (rcvr->iPppId==KPppIdLcp)
+				continue;
+			if (aNewPhase==rcvr->iActivePhase)
+				{
+				skip = EFalse;
+
+				rcvr->LowerLayerUp();
+
+				}
+			else if (oldphase<rcvr->iActivePhase && aNewPhase>rcvr->iActivePhase)
+				rcvr->LowerLayerUp();
+			}
+		}
+	if (skip && aNewPhase>EPppPhaseEstablish && aNewPhase<EPppPhaseNetwork)
+		PhaseComplete();
+	}
+
+void CPppLcp::TerminateLink(MNifIfNotify::TAction aAction, TInt aError)
+/**
+Cleanly take down the LCP (and therefore PPP) link.
+
+@param aAction The action to take after the link terminates
+@param aError The reason the link is going down
+*/
+{
+	iError = aError;
+	iTerminateAction = aAction;
+	LOG( iLogger->Printf(_L("TerminateLink due to error %d"), aError); )
+	MPppFsm::TerminateLink();
+	iGotCallbackInfo = EFalse;
+}
+
+void CPppLcp::PhaseRetard(TPppPhase aNewPhase, TInt aReason)
+/**
+Return to a previous PPP operation phase.
+When the PPP phase is retarded, active protocols may no
+longer be in their active phase and so have to be unbound
+from the main data path and signalled inactive.
+
+@param aNewPhase Phase just entered
+@param aReason Error code indicating the reason we are changing phases
+*/
+	{
+	LOG( iLogger->Printf(_L("PhaseRetard, reason[%d]"), aReason); )
+	if (aReason==KErrCommsLineFail && FsmIsThisLayerOpen())		// going to do reconnection
+		iGotCallbackInfo=EFalse;
+
+	TPppPhase oldphase = iPhase;
+	iPhase = aNewPhase;
+	LOG( iLogger->DumpPhase(oldphase, aNewPhase); )
+	if (oldphase==aNewPhase)
+		return;
+
+	// Terminate the link from here if and only if it is NCP failure of some sort
+	switch(aReason)
+		{
+		case KErrIfAuthenticationFailure:
+		case KErrIfAuthNotSecure:
+		case KErrIfAccountDisabled:
+		case KErrIfRestrictedLogonHours:
+		case KErrIfPasswdExpired:
+		case KErrIfNoDialInPermission:
+		case KErrIfChangingPassword:
+		case KErrIfCallbackNotAcceptable:
+		case KErrIfDNSNotFound:
+			TerminateLink(MNifIfNotify::EDisconnect, aReason);
+			Error(aReason);
+		default:
+			break;
+		}
+
+
+	if (!iRecvrList.IsEmpty())
+		{
+		MPppRecvr* rcvr;
+		TDblQueIter<MPppRecvr> iter(iRecvrList);
+		while (rcvr=iter++, rcvr!=NULL)
+			{
+			if (rcvr->iPppId==KPppIdLcp)
+				continue;
+
+			if (/*oldphase>=rcvr->iActivePhase &&*/ aNewPhase<rcvr->iActivePhase/* || aReason!=KErrNone*/)
+				rcvr->LowerLayerDown(aReason);
+			}
+		}
+   	}
+
+
+void CPppLcp::PhaseComplete()
+/**
+Advance to the next PPP phase after successfully completing the current phase.
+*/
+	{
+	switch (iPhase)
+		{
+	case EPppPhaseTerminate:
+		break;
+	case EPppPhaseEstablish:
+		PhaseAdvance(EPppPhaseEarlyCallback);
+		break;
+	case EPppPhaseEarlyCallback:
+		PhaseAdvance(EPppPhaseAuthenticate);
+		break;
+	case EPppPhaseAuthenticate:
+		//PhaseAdvancesBeyondAuthenticate();
+		PhaseAdvance(EPppPhaseLateCallback);
+		break;
+	case EPppPhaseLateCallback:
+		if (!iCallbackEnabled)
+			{
+			PhaseAdvance(EPppPhaseNetwork);
+			}
+		break;
+	case EPppPhaseNetwork:
+		break;
+	default:
+		break;
+		}
+	}
+
+void CPppLcp::PhaseAborted(TInt aStatus)
+/**
+Return to a previous PPP phase after ending the current phase.
+
+@param aStatus Error code indicating the reason we are ending the phase
+*/
+	{
+	switch (iPhase)
+		{
+	case EPppPhaseNetwork:
+		{
+		// NCP failer only translates to total failure
+		// if there are no more live NCPs
+		TInt nets=0;
+		MPppRecvr* rcvr;
+		TDblQueIter<MPppRecvr> iter(iRecvrList);
+		while (rcvr=iter++, rcvr!=NULL)
+			{
+			if (rcvr->iActivePhase==EPppPhaseNetwork && rcvr->iPppAbortCode==KErrNone)
+				++nets;
+			}
+		if (nets>0)
+			break;
+		// else fall through...
+		}
+	case EPppPhaseTerminate:
+	case EPppPhaseEstablish:
+	case EPppPhaseEarlyCallback:
+	case EPppPhaseAuthenticate:
+	case EPppPhaseLateCallback:
+		PhaseRetard(EPppPhaseTerminate, aStatus);
+		break;
+	default:
+		break;
+		}
+	}
+
+//
+// PPP Upcalls from FSM
+//
+
+EXPORT_C TInt CPppLcp::FsmLayerStarted()
+/**
+Open the layer below.
+Upcall from the FSM.
+
+@return Error code
+*/
+	{
+	TRAPD(err, iPppLink->OpenL());
+	if (err==KErrNone)
+		PhaseAdvance(EPppPhaseEstablish);
+	return err;
+	}
+
+EXPORT_C void CPppLcp::FsmLayerFinished(TInt aReason)
+/**
+Close the layer below.
+Upcall from the FSM.
+
+@param aReason Error code indicating the reason we are finished
+*/
+	{
+	LOG( iLogger->Printf(_L("CPppLcp::FsmLayerFinished aReason %d"), aReason); )
+	iError = aReason;
+	iPppLink->Close();
+	//PhaseAborted(aReason<KErrNone ? aReason : KErrTimedOut); PRR 15/4/98
+	PhaseAborted(aReason); // PRR 15/4/98
+
+	if (aReason == KErrCommsLineFail)
+		{
+		LinkLayerDown(aReason);
+		}
+	}
+
+EXPORT_C void CPppLcp::FsmTerminationPhaseComplete()
+/**
+Called when the FSM has stopped.
+Upcall from the FSM.
+*/
+	{
+	LOG( iLogger->Printf(_L("CPppLcp::FsmTerminationPhaseComplete iError[%d]"), iError); )
+ 	PostProgressMessage(EPppProgressLinkDown, iError);
+
+  	if (iTerminateAction == MNifIfNotify::EDisconnect)
+  		{
+  		// Tell SCPR that PPP is finished. After the Agent finishes (terminates the connection, air link, etc), Nifman
+   		// closes the NIF, which results in PPP deletion. The call to delete PPP originates in Nifman, implemented as
+   		// asynchronous callback. This call would invoke the destructors, which do the actual cleanup in the NIF.
+		PostFlowDownMessage(iError);
+  		}
+  	else if (iTerminateAction == MNifIfNotify::ECallBack)
+  		{
+  		// Action is not EDisconnect: this may not necessarily trigger NIF deletion - Nifman may try to restart the link.
+        iLastRequestOriginator.ReplyTo(Id(), TPPPMessage::TPppLinkExpectingCallback().CRef());
+
+		// After the first (outgoing) stage of callback, iTerminateAction contains ECallback.  If the
+		// connection comes up correctly and is subsequently terminated from "below" (i.e. from HDLC
+		// calling CPppLcp::LinkLayerDown() rather than from "above" (via CPppLcp::Stop() and TerminateLink()),
+		// then iTerminateAction remains set to ECallback.  As a result, at the end of the call we end
+		// up incorrectly signalling Nifman with LinkLayerDown(ECallback) which causes Nifman to wrongly
+		// perform the ECallback actions rather than the EDisconnect actions (which means issuing a
+		// Connect() to the Agent which subsequently goes wrong).
+		iTerminateAction = MNifIfNotify::EDisconnect;
+		}
+  	else
+  	    {
+  	    // It is believed that EReconnect does not get set into iTerminateStatus
+  	    // and therefore iTerminateAction should only ever be the ENoAction value
+  	    ASSERT(iTerminateAction == MNifIfNotify::ENoAction);
+  	    PostFlowDownMessage(KErrNone);
+  	    }
+
+	iCallbackEnabled = EFalse;
+	iGotCallbackInfo = EFalse;
+	PhaseAdvance(EPppPhaseTerminate);
+	PppNcpMsCbcpFactory::Delete( iPppMsCbcp );
+	iPppMsCbcp = NULL;
+	}
+
+EXPORT_C void CPppLcp::FsmLayerUp()
+/**
+Signal up event to next layer above
+Upcall from the FSM.
+*/
+	{
+	ExtOptNegotiationComplete();
+	PhaseComplete();
+	}
+
+EXPORT_C void CPppLcp::FsmLayerDown(TInt aReason)
+/**
+Signal down event to next layer above
+Upcall from the FSM.
+
+@param aReason Error code indicating the reason the layer is going down
+*/
+	{
+	ExtOptNegotiationAborted();
+	if(aReason!=KErrNone && iPhase==EPppPhaseEstablish)
+		iPhase=EPppPhaseTerminate;
+	PhaseRetard(EPppPhaseEstablish, aReason);
+	}
+
+EXPORT_C void CPppLcp::FsmFillinConfigRequestL(RPppOptionList& aRequestList)
+/**
+Fill in Config Request to be sent
+
+@param aRequestList Receives LCP option list
+*/
+	{
+	ExtOptNegotiationStarted();
+	iMaxSendSize = 0;
+
+// Removed September 1999 , both set to zero in GetSendRecvSize()
+//	iMaxRecvSize = 0;
+//	iPppLink->GetSendRecvSize(iMaxSendSize, iMaxRecvSize);
+//	iMaxRecvSize could be read from ppp.ini file
+	// Get desired Link options
+	if (iMaxSendSize==0)
+		iMaxSendSize = KPppDefaultFrameSize;
+	if (iMaxRecvSize==0)
+		iMaxRecvSize = KPppDefaultFrameSize;
+	else if(iMaxRecvSize != KPppDefaultFrameSize)
+		// Only add to request if not the default
+		aRequestList.CreateAndAddL(KPppLcpOptMaxRecvUnit, (TUint16)iMaxRecvSize);
+
+	// Create a new magic number
+	iConsecMagic = 0;
+	iRemMagicNumber = 0;
+	if (iLocMagicNumber == 0)
+		{
+		NewMagicNumberL(iLocMagicNumber);
+		}
+	aRequestList.CreateAndAddL(KPppLcpOptMagicNumber, (TUint32)iLocMagicNumber);
+
+	AppendCallbackRequestL( aRequestList );
+
+	ExtOptFillinConfigRequestL(aRequestList);
+	}
+
+EXPORT_C void CPppLcp::AppendCallbackRequestL( RPppOptionList& aRequestList )
+/**
+Append an LCP OPT of type "callback-request" to the given list
+
+@param aRequestList LCP option list to fill in
+*/
+	{
+	if ( ! iGotCallbackInfo )
+		{
+		InitCallbackInfoL();
+		iGotCallbackInfo = ETrue;
+		}
+
+	if ( ! iCallbackEnabled )
+		return;
+	__ASSERT_DEBUG( iCallbackIETFRequestPacket, PppPanic(EPppPanic_IETFNoCalback) );
+	__ASSERT_DEBUG( iCallbackIETFRequestPacketLen!=0, PppPanic(EPppPanic_IETFCalbackInvalid) );
+	aRequestList.CreateAndAddL( KPppLcpOptCallback, iCallbackIETFRequestPacket, iCallbackIETFRequestPacketLen);
+	}
+
+EXPORT_C void CPppLcp::FsmCheckConfigRequest(RPppOptionList& aRequestList, RPppOptionList& aAckList, RPppOptionList& aNakList, RPppOptionList& aRejList)
+/**
+Check options in a received config request.
+Each option is added to the appropriate Ack, Nak or Rej list.
+Upcall from the FSM.
+
+@param aRequestList LCP options to check
+@param aAckList Acked LCP options
+@param aNakList Naked LCP options
+@param aRejList Rejected LCP options
+*/
+	{
+	const TInt KOptMaxRecvUnitValueLen = 2; // correct value
+	const TInt KOptMagicNumberValueLen = 4;
+	const TInt KOptMruMinSize = 4;
+
+	RPppOption opt;
+	TBool forceNak(EFalse);
+	while (aRequestList.Remove(opt))
+		{
+		forceNak = EFalse; // Should the option be NAKed due to corruption?
+
+		switch (opt.OptType())
+			{
+		case KPppLcpOptMaxRecvUnit:
+			// Check for correct MRU option length and MRU value >= 4
+			if(KOptMaxRecvUnitValueLen == opt.ValueLength() && BigEndian::Get16(opt.ValuePtr()) >= KOptMruMinSize ) // valid option: Ack
+				{
+				aAckList.Append(opt);
+				}
+			else // invalid: NAK: put desired option, correct length
+				{
+				opt.SetValueLength(KOptMaxRecvUnitValueLen);
+				//N.B. We NAK with our MRU, read from the .ini file.
+				BigEndian::Put16(opt.ValuePtr(), static_cast<TUint16>(iMaxRecvSize));
+				aNakList.Append(opt);
+				}
+			break;
+
+		case KPppLcpOptMagicNumber:
+			if(KOptMagicNumberValueLen == opt.ValueLength()) // Correct length
+				{
+				iRemMagicNumber = BigEndian::Get32(opt.ValuePtr());
+				// Magic number of zero is not allowed and results in a Nak.
+				if (iRemMagicNumber == 0)
+					{
+					forceNak = ETrue;
+					}
+				}
+			else // Invalid length: correct it and NAK.
+				{
+				opt.SetValueLength(KOptMagicNumberValueLen);
+				forceNak = ETrue;
+				}
+
+			// NAK if local and remote magic numbers are equal, or if
+			// the option is corrupt.
+			if((iRemMagicNumber == iLocMagicNumber) || forceNak)
+			  	{
+				TRAPD(result, NewMagicNumberL(iRemMagicNumber));
+
+				if(result == KErrNone)
+					{
+					BigEndian::Put32(opt.ValuePtr(), iRemMagicNumber);
+					}
+				else
+					{
+					LOG( iLogger->Printf(_L("CPppLcp::FsmCheckConfigRequest Error when using NewMagicNumberL iError[%d]"), result); )
+					}
+				aNakList.Append(opt);
+				}
+			else // Remote magic number option is OK and remote number != local number
+				{
+				aAckList.Append(opt);
+				}
+			break;
+		case KPppLcpOptMultiLinkEndPointDescriminator:
+	        aAckList.Append(opt);
+			break;
+
+		default:
+    		ExtOptCheckConfigRequest(opt, aAckList, aNakList, aRejList);
+			}
+		}
+	}
+
+EXPORT_C void CPppLcp::FsmApplyConfigRequest(RPppOptionList& aRequestList)
+/**
+Apply options in a received config request (that was ACK'd).
+Upcall from the FSM.
+
+@param aRequestList LCP options to use
+*/
+	{
+	TMBufPktQIter iter(aRequestList);
+	RPppOption opt;
+
+	while (opt = iter++, !opt.IsEmpty())
+		{
+		switch (opt.OptType())
+			{
+		case KPppLcpOptMaxRecvUnit:
+			iMaxSendSize = BigEndian::Get16(opt.ValuePtr());
+			break;
+		case KPppLcpOptMagicNumber:
+			iRemMagicNumber = BigEndian::Get32(opt.ValuePtr());
+			break;
+		default:
+			ExtOptApplyConfigRequest(opt);
+			break;
+			}
+		}
+	}
+
+EXPORT_C void CPppLcp::FsmRecvConfigAck(RPppOptionList& aReplyList)
+/**
+Received a Config Ack - apply the options
+Upcall from the FSM.
+
+@param aReplyList LCP options to use
+*/
+	{
+	TMBufPktQIter iter(aReplyList);
+	RPppOption opt;
+
+	while (opt = iter++, !opt.IsEmpty())
+		{
+		switch (opt.OptType())
+			{
+		case KPppLcpOptMaxRecvUnit:
+			iMaxRecvSize = BigEndian::Get16(opt.ValuePtr());
+			break;
+		case KPppLcpOptMagicNumber:
+			// Magic number is OK
+			SendIdentification();
+			break;
+		case KPppLcpOptCallback:
+			CallbackRequestGranted();
+			break;
+		default:
+			ExtOptRecvConfigAck(opt);
+			break;
+			}
+		}
+	}
+
+EXPORT_C void CPppLcp::FsmRecvConfigNak(RPppOptionList& aReplyList, RPppOptionList& aReqList)
+/**
+Modify request after receiving a Config Nak
+Upcall from the FSM.
+
+@param aReplyList NAK'd LCP options
+@param aReqList The associated original request to be modified
+*/
+	{
+	TMBufPktQIter iter(aReplyList);
+	RPppOption opt;
+
+	while (opt = iter++, !opt.IsEmpty())
+		{
+		switch (opt.OptType())
+			{
+		case KPppLcpOptMaxRecvUnit:
+			aReqList.ReplaceOption(opt);
+			break;
+		case KPppLcpOptMagicNumber:
+			{
+			iLocMagicNumber = BigEndian::Get32(opt.ValuePtr());
+			if (iLocMagicNumber==iRemMagicNumber)
+				{
+				if (++iConsecMagic>KPppFsmNonConvergeLimit)
+					{
+					FsmAbort(KErrTimedOut);
+					return;
+					}
+				}
+			else
+				iConsecMagic = 0;
+			aReqList.ReplaceOption(opt);
+			}
+			break;
+		default:
+			ExtOptRecvConfigNak(opt, aReqList);
+			break;
+			}
+		}
+	}
+
+EXPORT_C void CPppLcp::FsmRecvConfigReject(RPppOptionList& aReplyList, RPppOptionList& aReqList)
+/**
+Modify request after receiving a Config Reject
+Upcall from the FSM.
+
+@param aReplyList NAK'd LCP options
+@param aReqList The associated original request to be modified
+*/
+	{
+	TMBufPktQIter iter(aReplyList);
+	RPppOption opt;
+
+	while (opt = iter++, !opt.IsEmpty())
+		{
+		switch (opt.OptType())
+			{
+		case KPppLcpOptMaxRecvUnit:
+		case KPppLcpOptMagicNumber:
+			aReqList.RemoveOption(opt);
+			break;
+		//PG if call back is rejected take the link down
+		case KPppLcpOptCallback:
+			PhaseAborted(KErrIfCallbackNotAcceptable);
+			break;
+		default:
+			ExtOptRecvConfigReject(opt, aReqList);
+			break;
+			}
+		}
+	}
+
+EXPORT_C TBool CPppLcp::FsmRecvUnknownCode(TUint8 aCode, TUint8 aId, TInt aLength, RMBufChain& aPacket)
+/**
+Process a packet with an otherwise unrecognised LCP opcode.
+If processing of extended codes is enabled or the code can otherwise be
+handled here, process it.
+Upcall from the FSM.
+
+@param aCode Unrecognised opcode
+@param aId Packet identifier
+@param aLength Length of packet
+@param aPacket MBuf chain containing received packet
+
+@return ETrue if the packet was handled
+*/
+	{
+	switch (aCode)
+		{
+	case KPppLcpIdentification:
+		if(DoLcpExts())
+			{
+			if(aLength<=4)
+				return ETrue;
+			aPacket.TrimStart(4);
+			TUint num = BigEndian::Get32(aPacket.First()->Ptr());
+			if (num==iRemMagicNumber)
+				{
+				delete iRecvIdentification;
+				iRecvIdentification = NULL;
+				iRecvIdentification = HBufC8::New(aLength-8);
+				if(!iRecvIdentification)
+					return ETrue;
+				TPtr8 des = iRecvIdentification->Des();
+				aPacket.CopyOut(des, 4);
+				}
+			return ETrue;
+			}
+		else
+			return EFalse;
+
+	case KPppLcpTimeRemaining:
+		if(DoLcpExts())
+			{
+			if(aLength<=4)
+				return ETrue;
+			aPacket.TrimStart(4);
+			TUint num = BigEndian::Get32(aPacket.First()->Ptr());
+			if (num==iRemMagicNumber)
+				{
+				aPacket.TrimStart(4);
+				iRecvTimeNotification.UniversalTime();
+				iRecvTimeRemaining = BigEndian::Get32(aPacket.First()->Ptr());
+				delete iRecvTimeRemMessage;
+				iRecvTimeRemMessage=NULL;
+				if (aLength>12)
+					{
+					iRecvTimeRemMessage = HBufC8::New(aLength-12);
+					if(!iRecvTimeRemMessage)
+						return ETrue;
+					TPtr8 des = iRecvTimeRemMessage->Des();
+					aPacket.CopyOut(des, 4);
+					}
+				}
+			return ETrue;
+			}
+		else
+			return EFalse;
+
+	case KPppLcpEchoRequest:
+		{
+		if(aLength < 8)  //Packet's length is less than the Min 8 bytes for a echo request.
+			return ETrue;
+		RMBufPacket pkt;
+		RMBufPktInfo* info=NULL;
+		TRAPD(ret, info = pkt.NewInfoL());
+		if (ret!=KErrNone)
+			return ETrue;
+		// Reuse the existing packet buffer for our reply
+		pkt.Assign(aPacket);
+		TUint8* ptr = pkt.First()->Ptr();
+		//check if the magic number matches the negotiated value.
+		TUint magicNumber= BigEndian::Get32(ptr+4);
+		if(magicNumber != iRemMagicNumber)
+			{
+			LOG( iPppLcp->iLogger->Printf(_L("PPP detected a wrong magic number in echo request.")); )
+			return ETrue; //Just discard this echo request.
+			}
+		info->iLength = BigEndian::Get16(ptr+2);
+		TPppAddr::Cast(info->iDstAddr).SetProtocol(iPppId);
+		BigEndian::Put32(ptr+4, iLocMagicNumber);
+		*ptr = KPppLcpEchoReply;
+		// If the frame to be sent is too large, lop off the end to make it fit.
+ 		__ASSERT_DEBUG(iPppLcp->MaxTransferSize() > 0, PppPanic(EPppPanic_InvalidData));
+ 		if (info->iLength > iPppLcp->MaxTransferSize())
+ 			{
+ 			pkt.TrimEnd(iPppLcp->MaxTransferSize());
+ 			info->iLength = iPppLcp->MaxTransferSize();
+  			}
+		pkt.Pack();
+		SendFrame(pkt);
+		}
+		return ETrue;
+	case KPppLcpEchoReply:
+		{
+		// Call CPppLrd::RecvEchoReply
+		iPppLrd->RecvEchoReply(aId);
+		return ETrue;
+		}
+	case KPppLcpDiscardRequest:
+		return ETrue;
+	default:
+		break;
+		}
+	return EFalse;
+	}
+
+//
+// Other methods
+//
+
+void CPppLcp::NewMagicNumberL(TUint& aMagicNumber)
+/**
+Generate a new magic number, based upon existing number,
+machine unique ID and tick count.
+
+@param aMagicNumber Magic number to update
+*/
+	{
+
+	TPckg<TUint> randDes(aMagicNumber);
+	do
+		{
+		TRandom::RandomL(randDes);
+		}
+		while (aMagicNumber==0);
+	}
+
+void CPppLcp::CancelRead()
+/**
+Unused
+*/
+	{
+	}
+
+TUint8 CPppLcp::SendEchoRequest()
+/**
+Send an LCP Echo Request frame.
+Called by CPppLrd::TimerComplete periodically
+
+@return On success, the Identifier that was selected
+so CPppLrd can match the answer to the request.
+On failure, 0 (safe because the identifier can't be 0)
+*/
+	{
+	TUint8	returnValue = 0;
+	RMBufPacket pkt;
+	const TUint pktLen = 4+4;
+	TUint8* ptr = NewPacket(pkt, pktLen);
+	if (ptr == NULL)
+		{
+		return returnValue;
+		}
+	*ptr++ = (TUint8)KPppLcpEchoRequest;
+	*ptr++ = (returnValue = FsmNewId());
+	BigEndian::Put16(ptr, (TUint16)pktLen);
+	BigEndian::Put32(ptr+2, (TUint32)iLocMagicNumber);
+	pkt.Pack();
+	SendFrame(pkt);
+	return returnValue;
+	}
+
+void CPppLcp::SendIdentification()
+/**
+Send an LCP Identification frame (RFC 1570).
+*/
+	{
+	if(!DoLcpExts())
+		return;
+	TPtrC8 id = _L8("Symbian Epoc");
+	RMBufPacket pkt;
+	const TUint pktLen = 4+4+id.Length();
+	TUint8* ptr = NewPacket(pkt, pktLen);
+	if (ptr == NULL)
+		{
+		return;
+		}
+	*ptr++ = (TUint8)KPppLcpIdentification;
+	*ptr++ = FsmNewId();
+	BigEndian::Put16(ptr, (TUint16)pktLen);
+	BigEndian::Put32(ptr+2, (TUint32)iLocMagicNumber);
+
+	pkt.CopyIn(id, 4+4);
+	pkt.Pack();
+	SendFrame(pkt);
+	}
+
+void CPppLcp::StopProtocol(TUint aProtocol)
+/**
+One of the NCP protocols has been shut down, so kill it.
+Searches for the registered protocol handler based on the protocol ID.
+
+@param aProtocol PPP protocol number
+*/
+	{
+	MPppRecvr* rcvr;
+
+
+	TDblQueIter<MPppRecvr> iter(iRecvrList);
+	while (rcvr = iter++, rcvr!=NULL)
+		{
+		if (aProtocol == rcvr->iPppId)
+			{
+			/*
+			*	Kill Me
+			*/
+			rcvr->KillProtocol();
+
+			}
+		}
+	}
+
+void CPppLcp::PppNewCompressor(const CPppCompressor* aCompressor)
+/**
+Indicate that the compression protocol handler is ready.
+Called from CPppCcp.
+
+@param aCompressor Compressor object, or NULL to indicate object is
+no longer available
+*/
+	{
+	if (iPppLink != NULL)
+		{
+		iPppLink->NewCompressor(aCompressor);
+		}
+	}
+
+void CPppLcp::PppUnloadCompressor()
+/**
+Unload the compression module after a compressed packet is rejected.
+Upcall from the FSM.
+*/
+	{
+	if (iPppCcp != NULL)
+		{
+		iPppCcp->UnloadCompressor();
+		}
+	}
+
+void CPppLcp::PppNewDeCompressor(const CPppDeCompressor* aDeCompressor)
+/**
+Indicate that the decompression protocol handler is ready.
+Called from CPppCcp.
+
+@param aDeCompressor Decompressor object, or NULL to indicate object is no longer available
+*/
+	{
+	if (iPppLink != NULL)
+		{
+		iPppLink->NewDeCompressor(aDeCompressor);
+		}
+	}
+
+TInt CPppLcp::Notification(TAgentToNifEventType aEvent, void * aInfo)
+/**
+Notification from Agent
+
+@param aEvent Event type
+@param aInfo Data relating to event
+
+@return Error code
+*/
+	{
+	switch (aEvent)
+		{
+	case EAgentToNifEventTypeModifyInitialTimer:
+
+		return KErrNone;
+	case EAgentToNifEventTypeDisableTimers:
+		iPppLrd->EnableOrDisableTimer(EFalse);
+		return KErrNone;
+	case EAgentToNifEventTypeEnableTimers:
+		iPppLrd->EnableOrDisableTimer(ETrue);
+		return KErrNone;
+	case EAgentToNifEventTypeGetDataTransfer:
+		{
+		//===========================================
+		// JGG PPP CHANGE
+		TPckg<RPacketContext::TDataVolume>* dataPackage = (TPckg<RPacketContext::TDataVolume>*) aInfo;
+		RPacketContext::TDataVolume& data = (*dataPackage)();
+		//TPckg<RGprsContext::TDataVolume>* dataPackage = (TPckg<RGprsContext::TDataVolume>*) aInfo;
+		//RGprsContext::TDataVolume& data = (*dataPackage)();
+		//===========================================
+		iPppLink->GetDataTransfer(data);
+		return KErrNone;
+		}
+	default:
+		break;
+		}
+		return KErrNotSupported;
+	}
+
+EXPORT_C TBool CPppLcp::FsmAckOptionsValid(RPppOptionList& aList, RPppOptionList& aRequestList)
+/**
+Check if the option list specified matches the original Config-Request option list.
+
+Used for conformance to RFC1661 sections 5.2 and 5.4 (the option list in a Config-Ack or
+Config-Reject must exactly match the option list in the original Config-Request - same
+option values in the same order with no new options appended).
+
+@param aList option list to check against (e.g. from a Config-Ack or Config-Reject etc).
+*/
+	{
+	return aList.EqualTo(aRequestList);
+	}
+
+EXPORT_C TBool CPppLcp::FsmRejectOptionsValid(RPppOptionList& aList, RPppOptionList& aRequestList)
+/**
+Check if the option list specified matches the original Config-Request option list.
+
+Used for conformance to RFC1661 sections 5.2 and 5.4 (the option list in a Config-Ack or
+Config-Reject must exactly match the option list in the original Config-Request - same
+option values in the same order with no new options appended).
+
+@param aList option list to check against (e.g. from a Config-Ack or Config-Reject etc).
+*/
+	{
+	return aList.IsSubsetOf(aRequestList);
+	}
+
+EXPORT_C TBool CPppLcp::FsmConfigRequestOptionsValid(RPppOptionList& aList)
+/**
+Check if any RFC1661 options are duplicated in the specified option list.
+
+Used for conformance to RFC1661 section 6:
+
+	"... (None of the Configuration Options in this specification can be listed more than once.)..."
+
+Note that this only checks for options in RFC1661 specification and not *all* PPP options
+(hence the "RFC1661" prefix to the method name).
+
+@param aList option list to check .
+*/
+	{
+	const TInt KMinOption = KPppLcpOptMaxRecvUnit;
+	const TInt KMaxOption = KPppLcpOptAddrCtrlCompress;
+
+	ASSERT(KMinOption >= 0 && KMaxOption >= 0 && KMinOption <= KMaxOption);	// sanity
+
+	TUint8 optionCount[KMaxOption + 1] = { 0 };
+
+	TMBufPktQIter iter(aList);
+	RPppOption opt;
+
+	opt = iter++;
+	while (!opt.IsEmpty())
+		{
+		TUint8 optType = opt.OptType();
+		if (optType >= KMinOption && optType <= KMaxOption)
+			{
+			if (++optionCount[optType] == 2)		// duplicated option...
+				{
+				switch (optType)					// ...is it one of the RFC1661 options ?
+					{
+				case KPppLcpOptMaxRecvUnit:
+				case KPppLcpOptAuthenticationProtocol:
+				case KPppLcpOptQualityProtocol:
+				case KPppLcpOptMagicNumber:
+				case KPppLcpOptProtocolCompress:
+				case KPppLcpOptAddrCtrlCompress:
+					return EFalse;
+				default:
+					break;
+					}
+				}
+			}
+		opt = iter++;
+		}
+	return ETrue;
+	}
+
+void CPppLcp::NcpUp()
+	{
+	++iNcpUpCount;
+	if (AllNcpsUp())
+		{
+		FlowUp();
+		}
+	}
+
+TBool CPppLcp::AllNcpsUp()
+	{
+	return (iNcpUpCount == iOpenCount);
+	}
+
+#ifdef __FLOG_ACTIVE
+const TText8* CPppLcp::GetMMStateName() const
+	{
+		switch(iMMState)
+			{
+			case EStopped:
+				return _S8("Stopped");
+	      	case EStarting:
+				return _S8("Starting");
+	      	case EStarted:
+				return _S8("Started");
+	      	case EStopping:
+				return _S8("Stopping");
+	      	default:
+				return _S8("<Unknown State>");
+			}
+	}
+#endif