diff -r 000000000000 -r af10295192d8 linklayerprotocols/pppnif/SPPP/PPPLCP.CPP --- /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 +#include +#include +#include +#include "PPPLOG.H" // must appear before ss_log.h +#include +#include // 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 +#include +#include "ncpip.h" +#include "ncpip6.h" +#include "PPPConfig.h" +#include "pppmessages.h" +#include +#include +#include +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#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(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(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(aMessage).iValue); + break; + case TCFDataClient::TProvisionConfig::EId: + ProvisionConfig(static_cast(aMessage).iConfig); + break; + case TCFDataClient::TBindTo::EId : + { + TCFDataClient::TBindTo& bindToReq = message_cast(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( + aConfigData.FindExtension(STypeId::CreateSTypeId(CBCAProvision::EUid, CBCAProvision::ETypeId))); + iPppNcpConfig = static_cast( + aConfigData.FindExtension(STypeId::CreateSTypeId(CIPConfig::EUid, CIPConfig::ETypeId))); + iPppLcpConfig = static_cast( + aConfigData.FindExtension(STypeId::CreateSTypeId(CPppLcpConfig::EUid, CPppLcpConfig::ETypeId))); + iPppAuthConfig = static_cast( + 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(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( + 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 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 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 iter(iRecvrList); + while (rcvr=iter++, rcvr!=NULL) + { + if (rcvr->iPppId==KPppIdLcp) + continue; + if (aNewPhase==rcvr->iActivePhase) + { + skip = EFalse; + + rcvr->LowerLayerUp(); + + } + else if (oldphaseiActivePhase && aNewPhase>rcvr->iActivePhase) + rcvr->LowerLayerUp(); + } + } + if (skip && aNewPhase>EPppPhaseEstablish && aNewPhasePrintf(_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 iter(iRecvrList); + while (rcvr=iter++, rcvr!=NULL) + { + if (rcvr->iPppId==KPppIdLcp) + continue; + + if (/*oldphase>=rcvr->iActivePhase &&*/ aNewPhaseiActivePhase/* || 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 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(aReasonPrintf(_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(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 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 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* dataPackage = (TPckg*) aInfo; + RPacketContext::TDataVolume& data = (*dataPackage)(); + //TPckg* dataPackage = (TPckg*) 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(""); + } + } +#endif