--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/secondarypdpcontextumtsdriver/spudman/src/spudman.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,3247 @@
+// Copyright (c) 2004-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:
+// SPUD event manager
+// WINSCW compiler has problems disambiguating TMetaDes8 and Meta::TMetaDes8 so
+// I prevent metabuffer.h from being recursively included from other headers
+// by defining its include guard.
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+#define METABUFFER_H
+
+#include "spudman.h"
+#include "bindman.h"
+#include "mux.h"
+
+#include <comms-infras/dbaccess.h>
+#include "rpdpfsminterface.h"
+using namespace SpudMan; // Access the SpudFsm event names
+
+#include <etelpckt.h>
+#include <comms-infras/commsdebugutility.h>
+#include <in_sock.h>
+#include <networking/qos_if.h>
+#include <nifman.h>
+#include <comms-infras/es_config.h>
+
+#include <networking/umtsgprs_subconnprovfactory.h>
+#include <ss_glob.h>
+#include <ss_subconnprov.h>
+
+const TUint KQosPlugInProtocolId = 360; //< Plug-in protocol ID
+
+static const TInt KMaxInetAddrPrintSize = 50; //This should be big enough for an IPv6 printout
+
+
+#ifdef __FLOG_ACTIVE
+
+_LIT(KSpudUnknownLit, "Unknown event");
+
+_LIT(KSpudSoIfControllerPlugInLit, "KSoIfControllerPlugIn");
+_LIT(KSpudLitKRegisterEventHandler, "KRegisterEventHandler");
+_LIT(KSpudContextSetEventsLit, "KContextSetEvents");
+_LIT(KSpudNifSetDefaultQoSLit, "KNifSetDefaultQoS");
+_LIT(KSpudContextCreateLit, "KContextCreate");
+_LIT(KSpudContextDeleteLit, "KContextDelete");
+_LIT(KSpudContextActivateLit, "KContextActivate");
+_LIT(KSpudContextQoSSetLit, "KContextQoSSet");
+_LIT(KSpudContextTFTModifyLit, "KContextTFTModify");
+_LIT(KSpudGetNegQoSLit, "KGetNegQoS");
+_LIT(KSpudContextModifyActiveLit, "KContextModifyActive");
+_LIT(KInitialisePdpFsmLit, "KInitialisePdpFsm");
+
+
+static const TDesC *SpudGuQoSEventToText(TInt aEvent)
+ {
+ switch(aEvent)
+ {
+ case KSoIfControllerPlugIn:
+ return &KSpudSoIfControllerPlugInLit;
+ case KRegisterEventHandler:
+ return &KSpudLitKRegisterEventHandler;
+ case KContextSetEvents:
+ return &KSpudContextSetEventsLit;
+ case KNifSetDefaultQoS:
+ return &KSpudNifSetDefaultQoSLit;
+ case KContextCreate:
+ return &KSpudContextCreateLit;
+ case KContextDelete:
+ return &KSpudContextDeleteLit;
+ case KContextActivate:
+ return &KSpudContextActivateLit;
+ case KContextQoSSet:
+ return &KSpudContextQoSSetLit;
+ case KContextTFTModify:
+ return &KSpudContextTFTModifyLit;
+ case KGetNegQoS:
+ return &KSpudGetNegQoSLit;
+ case KContextModifyActive:
+ return &KSpudContextModifyActiveLit;
+ case KInitialisePdpFsm:
+ return &KInitialisePdpFsmLit;
+ default:
+ return &KSpudUnknownLit;
+ }
+ }
+
+_LIT(KSpudContextDeleteEventLit, "KContextDeleteEvent");
+_LIT(KSpudContextActivateEventLit, "KContextActivateEvent");
+_LIT(KSpudContextParametersChangeEventLit, "KContextParametersChangeEvent");
+_LIT(KSpudContextBlockedEventLit, "KContextBlockedEvent");
+_LIT(KSpudContextUnblockedEventLit, "KContextUnblockedEvent");
+_LIT(KSpudNetworkStatusEventLit, "KNetworkStatusEvent");
+_LIT(KSpudContextQoSSetEventLit, "KContextQoSSetEvent");
+_LIT(KSpudContextTFTModifiedEventLit, "KContextTFTModifiedEvent");
+_LIT(KSpudPrimaryContextCreatedLit, "KPrimaryContextCreated");
+_LIT(KSpudSecondaryContextCreatedLit, "KSecondaryContextCreated");
+_LIT(KSpudGetNegQoSEventLit,"KGetNegQoSEvent");
+_LIT(KSpudContextModifyActiveEventLit, "KContextModifyActiveEvent");
+_LIT(KPdpFsmShuttingDownLit, "KPdpFsmShuttingDown");
+
+static const TDesC *SpudFsmEventToText(TInt aEvent)
+ {
+ switch(aEvent)
+ {
+ case KContextDeleteEvent:
+ return &KSpudContextDeleteEventLit;
+ case KContextActivateEvent:
+ return &KSpudContextActivateEventLit;
+ case KContextParametersChangeEvent:
+ return &KSpudContextParametersChangeEventLit;
+ case KContextBlockedEvent:
+ return &KSpudContextBlockedEventLit;
+ case KContextUnblockedEvent:
+ return &KSpudContextUnblockedEventLit;
+ case KNetworkStatusEvent:
+ return &KSpudNetworkStatusEventLit;
+ case KContextQoSSetEvent:
+ return &KSpudContextQoSSetEventLit;
+ case KContextTFTModifiedEvent:
+ return &KSpudContextTFTModifiedEventLit;
+ case KPrimaryContextCreated:
+ return &KSpudPrimaryContextCreatedLit;
+ case KSecondaryContextCreated:
+ return &KSpudSecondaryContextCreatedLit;
+ case KGetNegQoSEvent:
+ return &KSpudGetNegQoSEventLit;
+ case KContextModifyActiveEvent:
+ return &KSpudContextModifyActiveEventLit;
+ case KPdpFsmShuttingDown:
+ return &KPdpFsmShuttingDownLit;
+ default:
+ return &KSpudUnknownLit;
+ }
+ }
+
+_LIT(KSpudStateSpudInactiveLit, "ESpudInactive");
+_LIT(KSpudStateSpudHaveQosLit, "ESpudHaveQos");
+_LIT(KSpudStateSpudCreatingPrimary, "ESpudCreatingPrimary");
+_LIT(KSpudStateSpudStartingPrimaryLit, "ESpudStartingPrimary");
+_LIT(KSpudStateSpudStartingPrimaryLowerNifLit, "ESpudStartingPrimaryLowerNif");
+_LIT(KSpudStateSpudStartingSecondaryLit, "ESpudStartingSecondary");
+_LIT(KSpudStateSpudStartingSecondaryLowerNifLit, "ESpudStartingSecondaryLowerNif");
+_LIT(KSpudStateSpudGettingNegQoSLit, "ESpudGettingNegQoS");
+_LIT(KSpudStateSpudUpLit, "ESpudUp");
+_LIT(KSpudStateSpudFlowOffLit, "ESpudFlowOff");
+_LIT(KSpudStateSpudSuspendedLit, "ESpudSuspended");
+_LIT(KSpudStateSpudFlowOffAndSuspendedLit, "ESpudFlowOffAndSuspended");
+_LIT(KSpudStateSpudLinkDownLit, "ESpudLinkDown");
+_LIT(KSpudStateSpudContextDeleteLit, "ESpudContextDelete");
+_LIT(KSpudStateSpudWaitLinkDownLit, "ESpudWaitLinkDown");
+_LIT(KSpudStateSpudWaitBinderDeleteLit, "ESpudWaitBinderDelete");
+_LIT(KSpudStateUnknownLit, "Unknown spud state");
+
+static const TDesC *SpudStateToText(TSpudContextStates aState)
+ {
+ switch(aState)
+ {
+ case ESpudInactive:
+ return &KSpudStateSpudInactiveLit;
+ case ESpudHaveQos:
+ return &KSpudStateSpudHaveQosLit;
+ case ESpudCreatingPrimary:
+ return &KSpudStateSpudCreatingPrimary;
+ case ESpudStartingPrimary:
+ return &KSpudStateSpudStartingPrimaryLit;
+ case ESpudStartingPrimaryLowerNif:
+ return &KSpudStateSpudStartingPrimaryLowerNifLit;
+ case ESpudStartingSecondary:
+ return &KSpudStateSpudStartingSecondaryLit;
+ case ESpudStartingSecondaryLowerNif:
+ return &KSpudStateSpudStartingSecondaryLowerNifLit;
+ case ESpudGettingNegQoS:
+ return &KSpudStateSpudGettingNegQoSLit;
+ case ESpudUp:
+ return &KSpudStateSpudUpLit;
+ case ESpudFlowOff:
+ return &KSpudStateSpudFlowOffLit;
+ case ESpudSuspended:
+ return &KSpudStateSpudSuspendedLit;
+ case ESpudFlowOffAndSuspended:
+ return &KSpudStateSpudFlowOffAndSuspendedLit;
+ case ESpudLinkDown:
+ return &KSpudStateSpudLinkDownLit;
+ case ESpudContextDelete:
+ return &KSpudStateSpudContextDeleteLit;
+ case ESpudWaitLinkDown:
+ return &KSpudStateSpudWaitLinkDownLit;
+ case ESpudWaitBinderDelete:
+ return &KSpudStateSpudWaitBinderDeleteLit;
+ default:
+ return &KSpudStateUnknownLit;
+ }
+ }
+
+#endif
+
+CSpudMan::CSpudMan(CNifIfFactory& aFactory, MNifIfNotify* aNotify)
+ : CNifIfLink(aFactory),
+ iContextStatusOverride(RPacketContext::EStatusUnknown)
+ {
+ iNotify = aNotify;
+ ASSERT(iNotify);
+ __FLOG_OPEN(KSpudFirstTag,KSpudLog);
+ __FLOG_0(_L("CSpudMan::CSpudMan"));
+ }
+
+CSpudMan::~CSpudMan()
+ {
+ if (iBindMan)
+ {
+ // Only log if ConstructL() was called, where logger was initialized
+ __FLOG_0(_L("CSpudMan::~CSpudMan"));
+ }
+
+
+ if (AreQoSEventsEnabled())
+ {
+ // Spud is being destroyed by Nifman. Tell GUQoS to stop bothering SPUD.
+ // GUQoS returns the favour by turning off the NIF events within this very call.
+ // *********************************************************************************************
+ // N.B.: "DEF055691 GUQoS crashes at shutdown": This defect results in GUQoS crash if the stack
+ // closes flows after the NIF proxy was deleted by GUQoS, as a result of KNetworkInterfaceDown event.
+ // Because of this defect, we cannot signal KNetworkInterfaceDown from anywhere but here. Once it is fixed,
+ // calls from the appropriate places will be enabled, and the line below will not be strictly necessary.
+ SendNetworkStatusEvent(KNetworkInterfaceDown, RPacketService::EStatusUnattached);
+ // For safety, we should call this from here in any case.
+ //**********************************************************************************************
+ }
+
+ delete iParkedDefaultQoS;
+ delete iBinderSweeperNotifierCb;
+
+ delete iBindMan;
+ iPdpFsmInterface.Close();
+ iSipServerAddr.Close();
+ __FLOG_CLOSE;
+ }
+
+/**
+Panics the current thread.
+
+@param aReason Panic reason code
+*/
+void CSpudMan::Panic(TInt aReason) const
+ {
+ __FLOG_1(_L("CSpudMan::Panic with reason %d"), aReason);
+ User::Panic(KSpudName, aReason);
+ }
+
+/**
+Construct the Link Protocol Object
+
+@param aBindMan Pointer to BindMan object (ownership is transferred)
+@leave leaves if could not allocate memory
+*/
+void CSpudMan::ConstructL(CBindMan* aBindMan)
+ {
+ __FLOG_1(_L("CSpudMan starting %x"), iNotify);
+
+
+ iBindMan = aBindMan;
+ ASSERT(iBindMan);
+
+ // The lower NIF binder deletion & Nifman notification callback
+ iBinderSweeperNotifierCb = new (ELeave) CBinderSweeperNotifierCb(*this);
+ }
+
+
+/**
+Implements the Control method of CNifBase - used for retrieval of the P-CSCF (Sip Server) address
+*/
+TInt CSpudMan::Control(TUint aLevel,TUint aName,TDes8& aOption, TAny*)
+ {
+ if (aLevel == KCOLConfiguration && aName == KConnGetSipServerAddr)
+ {
+ if (aOption.Length() != sizeof (SSipServerAddr))
+ {
+ __FLOG(_L("CSpudMan::Control - Invalid Descriptior - Descriptor Must contain an SSipServerAddr"));
+ Panic();
+ }
+ SSipServerAddr* sipServerAddr = reinterpret_cast<SSipServerAddr*>(const_cast<TUint8*>(aOption.Ptr()));
+ if (sipServerAddr->index < 0 || sipServerAddr->index >= iSipServerAddr.Count())
+ {
+ __FLOG_1(_L("CSpudMan::Control - Index out of range : value = %d"), sipServerAddr->index);
+ return KErrNotFound;
+ }
+ sipServerAddr->address = iSipServerAddr[sipServerAddr->index];
+#ifdef __FLOG_ACTIVE
+ TBuf<KMaxInetAddrPrintSize> buf;
+ sipServerAddr->address.Output(buf);
+ __FLOG_2(_L("CSpudMan::Control Address %S returned for index %d"), &buf, sipServerAddr->index);
+#endif
+ return KErrNone;
+ }
+ return KErrNotSupported;
+ }
+
+
+/**
+Retrieve any GPRS settings required from CommDB
+
+@param aConfigGprs Context configuration parameters to be filled in
+*/
+void CSpudMan::RetrieveGprsConfig(RPacketContext::TContextConfigGPRS& aConfigGprs) const
+ {
+ TUint32 pdpType(0);
+ Notify()->ReadInt(TPtrC(GPRS_PDP_TYPE), pdpType);
+ __FLOG_1(_L8("ReadInt GPRS_PDP_TYPE [%d]"), pdpType);
+ aConfigGprs.iPdpType = STATIC_CAST(RPacketContext::TProtocolType, pdpType);
+
+ Notify()->ReadDes(TPtrC(GPRS_APN), aConfigGprs.iAccessPointName);
+ __FLOG_1(_L8("ReadDes GPRS_APN [%S]"), &aConfigGprs.iAccessPointName);
+
+
+ TBool fromServer;
+ aConfigGprs.iPdpAddress.SetLength(0);
+ Notify()->ReadBool(TPtrC(GPRS_IP_ADDR_FROM_SERVER), fromServer);
+ if (!fromServer)
+ {
+ Notify()->ReadDes(TPtrC(GPRS_IP_ADDR), aConfigGprs.iPdpAddress);
+ }
+
+
+ // We can only use IPv4 or IPv6 - we use the first one listed in the IfNetworks field
+ TBuf<KCommsDbSvrMaxFieldLength> networks;
+ Notify()->ReadDes(TPtrC(LAN_IF_NETWORKS), networks);
+
+ ASSERT(networks.Length() > 0); // If the IfNetworks field is empty there is a serious misconfiguration
+
+ TInt pos = networks.Find(_L(","));
+ if (pos == KErrNotFound)
+ {
+ pos = networks.Length();
+ }
+ TPtrC protocol(networks.Ptr(), pos);
+ _LIT(KIp4, "ip");
+ _LIT(KIp6, "ip6");
+ if (protocol.CompareF(KIp4) == 0)
+ {
+ // IPv4 settings
+ Notify()->ReadBool(TPtrC(GPRS_IP_DNS_ADDR_FROM_SERVER), fromServer);
+ if (!fromServer)
+ {
+ Notify()->ReadDes(TPtrC(GPRS_IP_NAME_SERVER1), aConfigGprs.iProtocolConfigOption.iDnsAddresses.iPrimaryDns);
+ Notify()->ReadDes(TPtrC(GPRS_IP_NAME_SERVER2), aConfigGprs.iProtocolConfigOption.iDnsAddresses.iSecondaryDns);
+ }
+ }
+ else if (protocol.CompareF(KIp6) == 0)
+ {
+ // IPv6 settings
+ Notify()->ReadBool(TPtrC(GPRS_IP6_DNS_ADDR_FROM_SERVER), fromServer);
+ if (!fromServer)
+ {
+ Notify()->ReadDes(TPtrC(GPRS_IP6_NAME_SERVER1), aConfigGprs.iProtocolConfigOption.iDnsAddresses.iPrimaryDns);
+ Notify()->ReadDes(TPtrC(GPRS_IP6_NAME_SERVER2), aConfigGprs.iProtocolConfigOption.iDnsAddresses.iSecondaryDns);
+ }
+ }
+ else
+ {
+ // Anything else is a serious misconfiguration
+ ASSERT(0);
+ }
+
+ RetrieveGprsCompression(aConfigGprs.iPdpCompression);
+ __FLOG_1(_L8("Read GprsCompression [%d]"), aConfigGprs.iPdpCompression);
+
+ RetrieveGprsAnonymousAccess(aConfigGprs.iAnonymousAccessReqd);
+ __FLOG_1(_L8("Read AnonymousAccess [%d]"), aConfigGprs.iAnonymousAccessReqd);
+
+ TBuf<KCommsDbSvrMaxUserIdPassLength> readBuf;
+ Notify()->ReadDes(TPtrC(SERVICE_IF_AUTH_NAME), readBuf);
+ aConfigGprs.iProtocolConfigOption.iAuthInfo.iUsername.Copy(readBuf);
+ readBuf.Zero();
+ Notify()->ReadDes(TPtrC(SERVICE_IF_AUTH_PASS), readBuf);
+ aConfigGprs.iProtocolConfigOption.iAuthInfo.iPassword.Copy(readBuf);
+ __FLOG_2(_L8("ReadDes SERVICE_IF_AUTH_NAME [%S] and SERVICE_IF_AUTH_PASS [%S]"), &aConfigGprs.iProtocolConfigOption.iAuthInfo.iUsername,
+ &aConfigGprs.iProtocolConfigOption.iAuthInfo.iPassword);
+
+ aConfigGprs.iUseEdge = EFalse;
+ }
+
+void CSpudMan::RetrieveGprsCompression(TUint& aCompression) const
+ {
+ aCompression = 0;
+ TBool isCompression = EFalse;
+ Notify()->ReadBool(TPtrC(GPRS_DATA_COMPRESSION), isCompression);
+ if (isCompression)
+ {
+ aCompression |= RPacketContext::KPdpDataCompression;
+ }
+
+ isCompression = EFalse;
+ Notify()->ReadBool(TPtrC(GPRS_HEADER_COMPRESSION), isCompression);
+ if (isCompression)
+ {
+ aCompression |= RPacketContext::KPdpHeaderCompression;
+ }
+ }
+
+void CSpudMan::RetrieveGprsAnonymousAccess(RPacketContext::TAnonymousAccess& aAnonymous) const
+ {
+ TBool isAnonymous = EFalse;
+ Notify()->ReadBool(TPtrC(GPRS_ANONYMOUS_ACCESS),isAnonymous);
+ if (isAnonymous)
+ aAnonymous = RPacketContext::ERequired;
+ else
+ aAnonymous = RPacketContext::ENotRequired;
+ }
+
+
+
+/**
+Indicates whether QoS has been enabled or not.
+
+@return ETrue if QoS has been enabled for this NIF.
+*/
+TBool CSpudMan::AreQoSEventsEnabled() const
+ {
+ return iQosEventHandler != NULL;
+ }
+
+
+/**
+Returns pointer to BindMan.
+
+@return Pointer to BindMan object
+*/
+CBindMan* CSpudMan::BindMan() const
+ {
+ return iBindMan;
+ }
+
+/**
+Returns pointer to the MNifIfNotify object in NIFMAN.
+
+@return Pointer to MNifIfNotify object
+*/
+MNifIfNotify* CSpudMan::Notify() const
+ {
+ ASSERT(iNotify);
+ return iNotify;
+ }
+
+/**
+Set default QoS parameters from the values in CommDb.
+
+@param aQos QoS parameters filled in on exit
+*/
+void CSpudMan::ReadDefaultQoS(RPacketQoS::TQoSR99_R4Requested& aQos) const
+ {
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+1> columnName;
+ _LIT(KFormatText,"%s\\%s");
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_TRAFFIC_CLASS);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqTrafficClass));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_TRAFFIC_CLASS);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinTrafficClass));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_DELIVERY_ORDER);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqDeliveryOrderReqd));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_DELIVERY_ORDER);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinDeliveryOrderReqd));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_DELIVER_ERRONEOUS_SDU);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqDeliverErroneousSDU));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_DELIVER_ERRONEOUS_SDU);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinDeliverErroneousSDU));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_MAX_SDUSIZE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqMaxSDUSize));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_ACCEPTABLE_MAX_SDU_SIZE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinAcceptableMaxSDUSize));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_MAX_UPLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqMaxRate.iUplinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_MIN_UPLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinAcceptableMaxRate.iUplinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_MAX_DOWNLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqMaxRate.iDownlinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_MIN_DOWNLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinAcceptableMaxRate.iDownlinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_BER);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqBER));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MAX_BER);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMaxBER));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_SDU_ERROR_RATIO);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqSDUErrorRatio));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MAX_SDU_ERROR_RATIO);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMaxSDUErrorRatio));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_TRAFFIC_HANDLING_PRIORITY);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqTrafficHandlingPriority));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_TRAFFIC_HANDLING_PRIORITY);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinTrafficHandlingPriority));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_TRANSFER_DELAY);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqTransferDelay));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MAX_TRANSFER_DELAY);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMaxTransferDelay));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_GUARANTEED_UPLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqGuaranteedRate.iUplinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_GUARANTEED_UPLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinGuaranteedRate.iUplinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_REQ_GUARANTEED_DOWNLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iReqGuaranteedRate.iDownlinkRate));
+
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_MIN_GUARANTEED_DOWNLINK_RATE);
+ Notify()->ReadInt (columnName, reinterpret_cast<TUint32&>(aQos.iMinGuaranteedRate.iDownlinkRate));
+ }
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+/**
+Set default R5 QoS parameters from the values in CommDb.
+
+@param aQos R5 QoS parameters filled in on exit
+*/
+void CSpudMan::ReadDefaultR5QoS(RPacketQoS::TQoSR5Requested& aQos) const
+ {
+ ReadDefaultQoS(aQos);
+
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+2> columnName;
+ _LIT(KFormatText,"%s\\%s");
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_SIGNALLING_INDICATION);
+ Notify()->ReadBool (columnName, aQos.iSignallingIndication);
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_SOURCE_STATISTICS_DESCRIPTOR);
+ Notify()->ReadInt(columnName, reinterpret_cast<TUint32&>(aQos.iSourceStatisticsDescriptor));
+ }
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+
+
+/**
+Reads TSY name from CommDb.
+
+@param aTsyName TSY name filled in on exit
+*/
+void CSpudMan::ReadTsyName(TName& aTsyName) const
+ {
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+1> columnName;
+ _LIT(KFormatText,"%s\\%s");
+ columnName.Format(KFormatText,MODEM_BEARER,MODEM_TSY_NAME);
+ Notify()->ReadDes(columnName, aTsyName); // ignore error
+ }
+
+/**
+Sets the error code to use for termination, unless it is already set.
+
+@param aError Error code to use when notifying NIFMAN
+*/
+void CSpudMan::SetTerminateError(TInt aError)
+ {
+ if (iTerminateError == KErrNone)
+ {
+ iTerminateError = aError;
+ __FLOG_1(_L("Set SPUD termination error to [%d]"), aError);
+
+ // There is no specific context associated with this termination
+ // So prevent a later overwrite of the error by the ETel error
+ if (iETelTerminateError == KErrNone)
+ {
+ iETelTerminateError = aError;
+ }
+ }
+ }
+
+/**
+Sets the error code to use for termination, unless it is already set.
+
+@param aContextId context ID
+@param aError Error code to use when notifying NIFMAN
+*/
+void CSpudMan::SetTerminateError(TContextId aContextId, TInt aError)
+ {
+ if (iTerminateError == KErrNone)
+ {
+ iTerminateError = aError;
+
+ // Now check to see if ETel was the originator of this error
+ if (iETelTerminateError == KErrNone)
+ {
+ // ask for the last ETel error received - ignore return code
+ iPdpFsmInterface.GetLastErrorCause(aContextId, iETelTerminateError);
+ }
+
+ if (iETelTerminateError != KErrNone)
+ {
+ // Overwrite with the most likely original error code!
+ iTerminateError = iETelTerminateError;
+ }
+
+ __FLOG_1(_L("Set SPUD termination error to [%d]"), iTerminateError);
+ }
+
+ }
+
+//*****************************************************************************
+// Events receivers
+//*****************************************************************************
+
+/**
+Receives events from SpudFsm.
+
+@param aContextId context ID
+@param aEvent event ID
+@param aParam optional parameter to event
+*/
+void CSpudMan::Input(TContextId aContextId, TInt aEvent, TInt aParam)
+ {
+ __FLOG_4(_L("SpudMan::Input: SpudFsm event %S(%d) param[%d] context[%d]"), SpudFsmEventToText(aEvent), aEvent, aParam, aContextId);
+ ASSERT(aContextId == KAllContexts || (aContextId >=0 && aContextId < KMaxPdpContexts));
+
+ switch (aEvent)
+ {
+ case KPrimaryContextCreated:
+ {
+ HandlePrimaryContextCreatedEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextDeleteEvent:
+ {
+ HandleContextDeleteEvent(aContextId, aParam);
+ break;
+ }
+
+ case KSecondaryContextCreated:
+ {
+ HandleSecondaryContextCreatedEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextActivateEvent:
+ {
+ HandleContextActivateEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextQoSSetEvent:
+ {
+ HandleContextQoSSetEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextTFTModifiedEvent:
+ {
+ HandleContextTFTModifiedEvent(aContextId, aParam);
+ break;
+ }
+
+ case KGetNegQoSEvent:
+ {
+ HandleGetNegQoSEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextModifyActiveEvent:
+ {
+ HandleContextModifyActiveEvent(aContextId, aParam);
+ break;
+ }
+
+ case KNetworkStatusEvent:
+ {
+ HandleNetworkStatusEvent();
+ break;
+ }
+
+ case KContextParametersChangeEvent:
+ {
+ HandleContextParametersChangeEvent(aContextId, aParam);
+ break;
+ }
+
+ case KContextBlockedEvent:
+ {
+ HandleContextBlockedEvent(aContextId);
+ break;
+ }
+
+ case KContextUnblockedEvent:
+ {
+ HandleContextUnblockedEvent(aContextId);
+ break;
+ }
+
+
+ case KPdpFsmShuttingDown:
+ {
+ __FLOG_0(_L("UmtsGprsSCPR has shutdown the PDP Fsm Interface"));
+ iPdpFsmInterface.Close();
+ break;
+ }
+
+ default:
+ __FLOG_1(_L("Unhandled event %d"), aEvent);
+ ASSERT(EFalse);
+ break;
+ }
+ }
+
+void CSpudMan::InitPdpFsmInterfaceL()
+ {
+ class XAssociatedNifConnectionProviderQuery : public MFactoryQuery
+ /** Finds the connection provider associated with the specified Nif.
+ @internalTechnology
+ */
+ {
+ public:
+ XAssociatedNifConnectionProviderQuery( const TDesC& aName, ::TMetaDes8& aNameBuffer ) : iNifName( aName ), iNifNameBuffer( aNameBuffer )
+ {
+ }
+
+ virtual TMatchResult Match( TFactoryObjectInfo& aObjectInfo )
+ {
+ TConnInterfaceName& name = *reinterpret_cast<TConnInterfaceName*>( const_cast<TUint8*>( iNifNameBuffer.iDes->Ptr() ) );
+ name.iIndex = 1;
+
+ TInt err = KErrNone;
+ TMatchResult result = EContinue;
+
+ // Check each of the connection provider interfaces' names to see if it
+ // is associated with this NIF.
+ while( ETrue )
+ {
+ TRAP( err, static_cast<CConnectionProviderBase*>( aObjectInfo.iInfo.iFactoryObject )->ControlL(KCOLProvider, KConnGetInterfaceName, iNifNameBuffer, NULL) );
+
+ if( err == KErrNone )
+ {
+ if( name.iName == iNifName )
+ {
+ result = EMatch;
+
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ name.iIndex ++;
+ }
+
+ return result;
+ }
+
+ private:
+ const TDesC& iNifName;
+ ::TMetaDes8& iNifNameBuffer;
+ };
+
+ const TUint KShimConnectionProviderFactoryId = 0x10207104; //the same as CSubConnectionProviderFactoryShim
+
+ TSockManData* sockManData = SockManGlobals::Get();
+ ASSERT(sockManData);
+
+ CConnectionFactoryContainer* connectionFactories = sockManData->iConnectionFactories;
+ ASSERT(connectionFactories);
+
+ CConnectionProviderFactoryBase *factory = connectionFactories->FindFactory(KShimConnectionProviderFactoryId);
+ if(!factory)
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CSpudMux* mux = iBindMan->SpudMux();
+
+ // Get the name of our SPUDMUX interface - it uniquely identifies this SPUD object assembly.
+ TNifIfInfo info;
+ mux->Info( info );
+
+ // Create a buffer to hold the name of each interface we check to see if the interface is our SPUDMUX.
+ TPckgBuf<TConnInterfaceName> name;
+ TPtrC8 desC( name );
+ ::TMetaDes8* des = ::TMetaDes8::NewL( &desC );
+
+ XAssociatedNifConnectionProviderQuery connProviderQuery( info.iName, *des );
+
+ // Find the connection provider associated with this NIF.
+ CConnectionProviderBase* connectionProvider = factory->FindProvider(connProviderQuery);
+ delete des;
+ if(!connectionProvider)
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CSubConnectionFactoryContainer* subConnectionFactories = sockManData->iSubConnectionFactories;
+ ASSERT(subConnectionFactories);
+
+ TDataClientQuery subConnProviderQuery(connectionProvider, ESubConnPlane, RSubConnection::EAttachToDefault);
+
+ // Find the default subconnection provider.
+ CSubConnectionProviderBase* subConnProvider = subConnectionFactories->FindOrCreateProviderL(connectionProvider->CanDoSubConnection(RSubConnection::EAttachToDefault), subConnProviderQuery);
+ if(!subConnProvider || subConnProvider->Factory().Id() != KUmtsGprsSubConnectionProviderFactoryId)
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ // Initialise the PDP FSM interface.
+ TPckg<CNifIfBase*> nifPckg(mux);
+ User::LeaveIfError(subConnProvider->Control(KSOLInterface, KInitialisePdpFsm, nifPckg));
+ }
+
+void CSpudMan::HandlePrimaryContextCreatedEvent(TContextId aContextId, TInt aError)
+ {
+
+ // Save the contextId for later
+ iPrimaryContextId = aContextId;
+
+ // Primary context has been created; Start the lower NIF
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __FLOG_2(_L("Got lower NIF binder for context[%d] with error[%d]"), aContextId, rc);
+ if (rc == KErrNone)
+ {
+ // Make sure context was created successfully
+ rc = aError;
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ }
+
+ if (KErrNone == rc) // Context created successfully.
+ {
+ // Get the details of the P-CSCF
+ RPacketContext::TContextConfigGPRS config;
+
+ if (iPdpFsmInterface.Get(aContextId, config) == KErrNone)
+ {
+ TRAP(rc, SetSipServerAddrL(config.iProtocolConfigOption););
+ {
+ __FLOG_1(_L("CSpudMan::HandlePrimaryContextCreatedEvent -Error occurred extracting the sip server address: %d"),rc);
+ //rc is now non zero, therefore should fail gracefully
+ }
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ // Since the value or IMCN Signalling flag also comes in PCO IE buffer along with the SipAddress, we
+ // need to extract the value here and set it to Parameter Bundle of SCPR
+ TBool imcn = EFalse;
+ TRAPD(err,imcn=GetIMCNSignallingFlagPcoL(config.iProtocolConfigOption););
+ __FLOG_1(_L("CSpudMan::GetIMCNSignallingFlagPcoL - returns eror=%d"),err);
+ if (err == KErrNone)
+ {
+ iPdpFsmInterface.SetIMCNSignalling(imcn); //imcn contains ETrue or Efalse
+#ifdef __FLOG_ACTIVE
+ if (imcn)
+ {
+ __FLOG_0(_L("CSpudMan::HandlePrimaryContextCreatedEvent - Network ACCEPTS the request for dedicated IMCN Signalling Flag "));
+ }
+ else
+ {
+ __FLOG_0(_L("CSpudMan::HandlePrimaryContextCreatedEvent - Network REJECTS the request for dedicated IMCN Signalling Flag "));
+ }
+#endif
+ }
+ else
+ {
+
+#ifdef __FLOG_ACTIVE
+ __FLOG_1(_L("CSpudMan::HandlePrimaryContextCreatedEvent -Leave Error occurred %d"),err);
+#endif
+ }
+#endif // SYMBIAN_NETWORKING_UMTSR5
+ }
+ }
+
+ if (KErrNone == rc) // Sip server address retrieved
+ {
+ ASSERT(ref->State() == ESpudCreatingPrimary);
+ ref->SetState(ESpudStartingPrimary);
+ // Start the lower NIF and wait for the LinkLayerUp call
+ rc = ref->NifLink()->Start();
+ if(KErrNone == rc)
+ {
+ ref->SetState(ESpudStartingPrimaryLowerNif);
+ }
+ // Lower NIF may still report failure to Start by signalling LinkLayerDown with error.
+ // E.G. PPP negotiation may fail.
+ __FLOG_2(_L("Lower NIF for Primary Context[%d] started with error[%d]."), aContextId, rc);
+ }
+
+
+ // Catch-all error handling: Could not create context, or could not start lower NIF.
+ if(KErrNone != rc)
+ {
+ SetTerminateError(rc);
+
+ SendPrimaryContextCreated(aContextId, rc); // Notify GUQoS of error
+
+ if(ESpudStartingPrimary == ref->State()) // Context created
+ {
+ ref->SetState(ESpudWaitLinkDown); // We've just notified GUQoS.
+ // Delete context via SpudFsm
+ __FLOG_2(_L("Failed to start lower NIF for Primary PDP context[%d] due to error[%d]. Deleting Primary via SpudFsm."), aContextId, rc);
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ ASSERT(rc == KErrNone);
+ }
+ else // Context was not created, else we would not be here. There is nothing to stop and delete.
+ {
+ __FLOG_1(_L("Failed to create Primary context[%d]. Spud will shut down."), aContextId);
+
+ if (AreQoSEventsEnabled())
+ {
+ // At this point we know that SPUD is about to shut down, because we are
+ // deleting the last context. We want to indicate to the upper layers early that
+ // data can no longer be sent to SPUD.
+
+ // Tell GUQoS to stop bothering SPUD.
+ // GUQoS returns the favour by turning off the NIF events within this very call.
+ // This means we won't send KNetworkInterfaceDown, even if we try.
+ // *********************************************************************************************
+ // N.B.: "DEF055691 GUQoS crashes at shutdown": This defect results in GUQoS crash if the stack
+ // closes flows after the NIF proxy was deleted by GUQoS, as a result of KNetworkInterfaceDown event.
+ // As a temporary workaround, this call is disabled, and KNetworkInterfaceDown event is signalled only
+ // from the destructor. Once this defect is fixed, the following line must be uncommented:
+ // SendNetworkStatusEvent(KNetworkInterfaceDown, RPacketService::EStatusUnattached);
+ //**********************************************************************************************
+ }
+ // We are about to delete the primary context NIF: this will notify Nifman that SPUD is finished.
+ DisposeOfBinder(ref);
+ }
+ }
+ }
+
+void CSpudMan::HandleContextDeleteEvent(TContextId aContextId, TInt aError)
+ {
+ aError = aError; // suppress compiler warning
+ // Ignore error on delete--nothing we can do, anyway
+ // For the upper layers, we treat this event as KErrDisconnected, because the network has torn down an
+ // existing context.
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+ __FLOG_4(_L("Network deleted context %d, in state %S(%d). Deletion error=%d"),
+ aContextId, SpudStateToText(ref->State()), ref->State(), aError);
+
+ // Are we about to shut down after this context is deleted?
+ TBool shutdownStarted(BindMan()->IsLastContext(aContextId));
+ // We must determine this before we make any state transitions. But we can act on this
+ // only after we've done all GUQoS notifications to make sure shutdown is graceful.
+
+ switch (ref->State())
+ {
+ case ESpudUp:
+ case ESpudFlowOff:
+ case ESpudSuspended:
+ case ESpudFlowOffAndSuspended:
+ ref->SetState(ESpudWaitLinkDown);
+ SendContextDeleteEvent(aContextId);
+ ref->NifLink()->Stop(KErrConnectionTerminated, MNifIfNotify::EDisconnect);
+ break;
+
+ case ESpudStartingPrimaryLowerNif:
+ ref->SetState(ESpudWaitLinkDown);
+ SendPrimaryContextCreated(aContextId, KErrDisconnected);
+ SendContextDeleteEvent(aContextId);
+ ref->NifLink()->Stop(KErrConnectionTerminated, MNifIfNotify::EDisconnect);
+ break;
+
+ case ESpudGettingNegQoS: // Context was activated. It is assumed that QoS retrieval would be cancelled by deletion.
+ case ESpudStartingSecondaryLowerNif:
+ ref->SetState(ESpudStartingSecondary);
+ FillInContextConfig(iTempContextConfig, aContextId);
+ SendContextActivateEvent(aContextId, iTempContextConfig, KErrDisconnected);
+ SendContextDeleteEvent(aContextId);
+ ref->NifLink()->Stop(KErrConnectionTerminated, MNifIfNotify::EDisconnect);
+ break;
+
+ case ESpudStartingPrimary:
+ // this should never happen
+ SendPrimaryContextCreated(aContextId, KErrDisconnected);
+ SendContextDeleteEvent(aContextId);
+ DisposeOfBinder(ref);
+ break;
+
+ case ESpudStartingSecondary:
+ // This should never happen, and may cause problems if it does because there could be
+ // another outstanding request from GUQoS that never gets completed.
+ __FLOG_0(_L("Network should not have deleted context in ESpudStartingSecondary state!"));
+ // Fall through and treat the same as ESpudLinkDown
+
+ case ESpudLinkDown:
+ SendContextDeleteEvent(aContextId);
+ DisposeOfBinder(ref);
+ break;
+
+ case ESpudWaitLinkDown:
+ DisposeOfBinder(ref);
+ break;
+
+
+ default:
+ __FLOG_2(_L("Unexpected state %S(%d)"), SpudStateToText(ref->State()), ref->State());
+ ASSERT(EFalse);
+ break;
+ }
+
+ if(shutdownStarted) // Additional steps if we are shutting down as as result of this deletion.
+ {
+ SetTerminateError(KErrDisconnected);
+ // We don't reuse errorForGuqos, because we may want to keep Nifman errors and GUQoS errors separate.
+ if (AreQoSEventsEnabled())
+ {
+ // At this point we know that SPUD is about to shut down, because the last context
+ // was just deleted. We want to indicate to the upper layers early that
+ // data can no longer be sent to SPUD.
+
+ // Tell GUQoS to stop bothering SPUD.
+ // GUQoS returns the favour by turning off the NIF events within this very call.
+ // This means we send KNetworkInterfaceDown only once.
+ // *******************************************************************************************
+ // N.B.: "DEF055691 GUQoS crashes at shutdown": This defect results in GUQoS crash if the stack
+ // closes flows after the NIF proxy was deleted by GUQoS, as a result of KNetworkInterfaceDown event.
+ // As a temporary workaround, this call is disabled, and KNetworkInterfaceDown event is signalled only
+ // from the destructor. Once this defect is fixed, the following line must be uncommented:
+ // SendNetworkStatusEvent(KNetworkInterfaceDown, RPacketService::EStatusUnattached);
+ //**********************************************************************************************
+ }
+ }
+ }
+
+void CSpudMan::HandleSecondaryContextCreatedEvent(TContextId aContextId, TInt aError)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ if (rc == KErrNone)
+ {
+ ASSERT(ref->IsBound());
+ __FLOG_4(_L("Network created secondary context[%d] in state %S(%d). Creation error=%d "),aContextId, SpudStateToText(ref->State()), ref->State(), aError);
+ if (ref->State() != ESpudStartingSecondary)
+ {
+ __FLOG_3(_L("KSecondaryContextCreated context %d is in unexpected state %S(%d)"),
+ aContextId, SpudStateToText(ref->State()), ref->State());
+ }
+ ref = ref; // Eliminate compiler warning in release builds
+
+ // Make sure context was created successfully
+ rc = aError;
+ if(KErrNone != rc) // Creation failed: we don't have the context, only the binder. Delete it.
+ {
+ DisposeOfBinder(ref);
+ }
+ }
+ SendSecondaryContextCreated(aContextId, rc);
+ }
+
+void CSpudMan::HandleContextActivateEvent(TContextId aContextId, TInt aError)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ if (rc == KErrNone)
+ {
+ // Make sure context was activated successfully
+ rc = aError;
+
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ }
+
+ if (rc == KErrNone)
+ {
+ ASSERT(ref->State() == ESpudStartingSecondary);
+ // Start the lower NIF
+ rc = ref->NifLink()->Start();
+ // Even if we get KErrNone here, we may still get LinkLayerDown with error later.
+ __FLOG_2(_L("KContextActivateEvent: Start on lower NIF returned for Context[%d] returned error[%d]"),aContextId, rc);
+ }
+
+ if(KErrNone == rc) // Start OK.
+ {
+
+ ref->SetState(ESpudStartingSecondaryLowerNif);
+ }
+ else
+ {
+ // Error activating PDP context
+ FillInContextConfig(iTempContextConfig, aContextId);
+ SendContextActivateEvent(aContextId, iTempContextConfig, rc);
+ }
+ }
+
+void CSpudMan::HandleContextQoSSetEvent(TContextId aContextId, TInt aError)
+ {
+ // Notify GUQoS of success or failure
+ SendContextQoSSetEvent(aContextId, aError);
+ }
+
+void CSpudMan::HandleContextTFTModifiedEvent(TContextId aContextId, TInt aError)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ ref = ref; // Eliminate compiler warning in release builds
+
+ // Notify GUQoS of success or failure
+ TTFTOperationCode opCode;
+ iPdpFsmInterface.Get(aContextId, opCode);
+ SendContextTFTModifiedEvent(aContextId, opCode, aError);
+ }
+
+void CSpudMan::HandleGetNegQoSEvent(TContextId aContextId, TInt aError)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+
+ ASSERT(ref->IsBound());
+ __FLOG_4(_L("CSpudMan: Retrieved Negotiated QoS, error=%d: context %d is in state %S(%d)"), aError, aContextId, SpudStateToText(ref->State()), ref->State());
+ if (ref->State() == ESpudGettingNegQoS)
+ {
+ // Negotiated QoS retrieved successfully. At this point the ctx is up both on control and data paths.
+ if(KErrNone == aError)
+ {
+ // Context is now fully up. Notify GUQoS.
+ ref->SetState(ESpudUp);
+ // Notify GUQoS of success or failure
+ FillInContextConfig(iTempContextConfig, aContextId);
+ SendContextActivateEvent(aContextId, iTempContextConfig, aError);
+
+ if(ref->State() == ESpudUp) // GUQoS can delete the context from the activation notification.
+ {
+ BindMan()->SpudProtocol()->DoStartSending();
+ SendContextUnblockedEvent(aContextId);
+ }
+ }
+ // If the QoS could not be retrieved, we remain in ESpudGettingNegQoS and wait for
+ // the network to delete the context. The rest would be handled from the deletion event.
+
+ // N.B. CRITICAL ASSUMPTION:
+ // The network / TSY will delete the ctx if the negotiated QoS could not be retrieved.
+ // (The idea is that if QoS negotiation is errored out, then everything is errored out.
+ // So we either do not get to this point at all, or will be errored out soon after this handler completes.)
+ // This leaves the issue of internal ETel/TSY errors such as OOM conditions.)
+ // At this point Spud is idle (no requests outstanding), so nothing will drive us
+ // forward to clean up this failure. GUQoS does NOT time out on PDP context creation failure.
+ }
+ else
+ {
+ // If we are not getting negotiated QoS, but we receive this notification, then:
+ // - ETel has sent us a stray notification totally uncalled for, i.e. it's a bug in ETel or more likely a TSY.
+ if(KErrNone == aError)
+ {
+ __FLOG(_L("WARNING! Negotiated QoS retrieval completed successfully, but totally out of order! See the comments in the code.)"));
+ }
+ // We don't assert, because it can be a race condition outside of ETel's control:
+ // - ETel, lower NIF, GUQoS, Nifman has errored the context out (e.g. ctx deleted by network), so there was a
+ // state transition as a result of that, and now the QoS retrieval has completed after that with KErrNone.
+ }
+ }
+
+
+void CSpudMan::HandleContextModifyActiveEvent(TContextId aContextId, TInt aError)
+ {
+ // Notify GUQoS of success or failure
+ FillInContextConfig(iTempContextConfig, aContextId);
+ SendContextModifyActiveEvent(aContextId, iTempContextConfig, aError);
+ }
+
+void CSpudMan::HandleNetworkStatusEvent()
+ {
+ // This is a network status change
+ RPacketService::TStatus status;
+ iPdpFsmInterface.Get(status);
+
+ // Assume that anything other than EStatusUnattached means the network
+ // is still up, so just ignore this event.
+ if (status == RPacketService::EStatusUnattached)
+ {
+ // Notify GUQoS
+ SendNetworkStatusEvent(KNetworkConnectionLost, status);
+ }
+ else
+ {
+ __FLOG_1(_L("Ignoring KNetworkStatusEvent with status %d (NOT EStatusUnattached)"),
+ status);
+ }
+ }
+
+void CSpudMan::HandleContextParametersChangeEvent(TContextId aContextId, TInt aError)
+ {
+ // This is a status change on an individual context
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ if (ref->State() == ESpudGettingNegQoS || ref->State() == ESpudUp || ref->State() == ESpudFlowOff || ref->State() == ESpudSuspended || ref->State() == ESpudFlowOffAndSuspended)
+ {
+ // Only pass on context changes while the context is up
+ FillInContextConfig(iTempContextConfig, aContextId);
+ SendContextParametersChangeEvent(aContextId, iTempContextConfig, aError);
+ }
+ else
+ {
+ __FLOG_3(_L("KContextParametersChangeEvent ignored on context %d because of nonoperational state %S(%d)"),
+ aContextId, SpudStateToText(ref->State()), ref->State());
+ SetTerminateError(aContextId, aError);
+ }
+ }
+
+void CSpudMan::HandleContextBlockedEvent(TContextId aContextId)
+ {
+ // Context is suspended (see StopSending)
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ switch (ref->State())
+ {
+ case ESpudUp:
+ {
+ ref->SetState(ESpudSuspended);
+ if (AreQoSEventsEnabled())
+ {
+ SendContextBlockedEvent(aContextId);
+ }
+
+ // Send an IfProgress to Nifman so that RConnection::ProgressNotification reports the blockage etc.
+ Notify()->IfProgress(KDataTransferTemporarilyBlocked, KErrNone);
+ break;
+ }
+
+ case ESpudFlowOff:
+ ref->SetState(ESpudFlowOffAndSuspended);
+
+ // Send an IfProgress to Nifman so that RConnection::ProgressNotification reports the blockage etc.
+ Notify()->IfProgress(KDataTransferTemporarilyBlocked, KErrNone);
+ break;
+
+ case ESpudSuspended:
+ case ESpudFlowOffAndSuspended:
+ // Ignore this since we're already suspended
+ break;
+
+ default:
+ // Ignore this since we're still starting up or shutting down
+ __FLOG_1(_L("Can't send blocked event now on context %d"), aContextId);
+ break;
+ }
+
+ // TODO: Probably need to send IfProgress here where aStage==KDataTransferTemporarilyBlocked
+ // or Notification with aEvent=EAgentToNifEventTypeDisableTimers
+ //
+ // NOTE: The IfProgress has now been implemented so that callers of RConnection::ProgressNotification
+ // expecting to receive KDataTransferTemporarilyBlocked actually get it if the PDP context is
+ // suspended (details of problem in INC107930).
+ }
+
+void CSpudMan::HandleContextUnblockedEvent(TContextId aContextId)
+ {
+ // Context is suspended (see StartSending)
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ switch (ref->State())
+ {
+ case ESpudUp:
+ case ESpudFlowOff:
+ // Ignore this since we're already in an unsuspended state
+ break;
+
+ case ESpudSuspended:
+ {
+ ref->SetState(ESpudUp);
+
+ BindMan()->SpudProtocol()->DoStartSending();
+
+ if (AreQoSEventsEnabled())
+ {
+ SendContextUnblockedEvent(aContextId);
+ }
+ Notify()->IfProgress(KLinkLayerOpen, KErrNone);
+ break;
+ }
+
+ case ESpudFlowOffAndSuspended:
+ {
+ ref->SetState(ESpudFlowOff);
+ Notify()->IfProgress(KLinkLayerOpen, KErrNone);
+ break;
+ }
+
+ default:
+ // Ignore this since we're still starting up or shutting down
+ __FLOG_1(_L("Can't send unblocked event now on context %d; this may cause problems"), aContextId);
+ break;
+ }
+ }
+
+/**
+Receives event from GUQoS.
+
+@param aName event identification
+@param aOption optional data associated with event
+@return error code
+*/
+TInt CSpudMan::GuqosInput(TUint aName, TDes8& aOption)
+ {
+ __FLOG_2(_L("SpudMan::GuqosInput: GUQoS event %S(%d)"), SpudGuQoSEventToText(aName), aName);
+ switch (aName)
+ {
+ case KSoIfControllerPlugIn:
+ {
+ // Indicate that we want GUQoS
+ TSoIfControllerInfo& opt = *reinterpret_cast<TSoIfControllerInfo*>(const_cast<TUint8*>(aOption.Ptr()));
+ _LIT(KQosPlugInName, "guqos");
+ opt.iPlugIn = KQosPlugInName;
+ opt.iProtocolId = KQosPlugInProtocolId;
+ return KErrNone;
+ }
+
+ case KRegisterEventHandler:
+ {
+ // GUQoS has passed a pointer to its event handler
+ const TEvent *handler = reinterpret_cast<const TEvent *>(aOption.Ptr());
+ iQosEventHandler = static_cast<MNifEvent *>(handler->iEvent);
+ ASSERT(iQosEventHandler);
+ return KErrNone;
+ }
+
+ case KContextSetEvents:
+ {
+ if (!AreQoSEventsEnabled())
+ {
+ // Event handler must be registered first
+ return KErrGeneral;
+ }
+ const TBool* eventsEnabledPtr = reinterpret_cast<const TBool *>(aOption.Ptr());
+ ASSERT(eventsEnabledPtr);
+ iQosEventsEnabled = *eventsEnabledPtr;
+
+ // Has a primary PDP context has already been created?
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = BindMan()->GetAnyRefL());
+ const TBool havePrimary(rc == KErrNone && (ref->State() == ESpudUp || ref->State() == ESpudFlowOff || ref->State() == ESpudSuspended || ref->State() == ESpudFlowOffAndSuspended));
+
+ if (iQosEventsEnabled && havePrimary)
+ {
+ // iPrimaryContextId == KPrimaryContextId == 0 at startup
+ SendPrimaryContextCreated(iPrimaryContextId, KErrNone);
+ }
+ return KErrNone;
+ }
+
+ case KNifSetDefaultQoS:
+ {
+ ASSERT(aOption.Ptr());
+ const TContextParameters& opt = *reinterpret_cast<const TContextParameters*>(aOption.Ptr());
+
+ if (!iPdpFsmInterface.IsInitialised())
+ {
+ __FLOG_0(_L("CSpudMan::GuqosInput: iPdpFsmInterface not initialised, parking KNifSetDefaultQoS."));
+
+ if (iParkedDefaultQoS == NULL)
+ {
+ TRAPD(err, iParkedDefaultQoS = HBufC8::NewL (sizeof (TContextParameters)));
+ if (err != KErrNone)
+ {
+ __FLOG_0(_L("CSpudMan::GuqosInput: Failed to park default QoS."));
+ return err;
+ }
+ }
+
+ iParkedDefaultQoS->Des().Copy (aOption);
+
+ return KErrNone;
+ }
+
+ CSpudBinderRef* ref = NULL;
+ // Lower NIF for primary context has already been loaded by factory
+ TRAPD(rc, ref = BindMan()->GetRefL(iPrimaryContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+
+ ASSERT(ref->State() == ESpudInactive);
+ ref->SetState(ESpudHaveQos);
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ // Store R5 QoS parameters
+ RPacketQoS::TQoSR5Requested qos;
+#else
+ // Store QoS parameters
+ RPacketQoS::TQoSR99_R4Requested qos;
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+
+ opt.iContextConfig.GetUMTSQoSReq(qos);
+ rc = iPdpFsmInterface.Set(iPrimaryContextId, qos);
+
+ if (rc != KErrNone)
+ {
+ __FLOG_1(_L("Setting default QoS on primary context failed with error [%d]. SPUD will shut down."), rc);
+ SetTerminateError(iPrimaryContextId, rc);
+
+ SendPrimaryContextCreated(iPrimaryContextId, rc); // Notify GUQoS of error
+
+ // At this point we know that SPUD is about to shut down, because we could not bring the
+ // primary context UP.
+
+ //**********************************************************************************************
+ // Tell GUQoS to stop bothering SPUD.
+ // GUQoS returns the favour by turning off the NIF events within this very call.
+ // N.B.: "DEF055691 GUQoS crashes at shutdown": This defect results in GUQoS crash if the stack
+ // closes flows after the NIF proxy was deleted by GUQoS, as a result of KNetworkInterfaceDown event.
+ // As a temporary workaround, this call is disabled, and KNetworkInterfaceDown event is signalled only
+ // from the destructor. Once this defect is fixed, the following line must be uncommented:
+ // SendNetworkStatusEvent(KNetworkInterfaceDown, RPacketService::EStatusUnattached);
+ //**********************************************************************************************
+
+ __FLOG_1(_L("Setting default QoS on primary context failed: mark lower NIF binder for context[%d] for async deletion."), iPrimaryContextId);
+ // We are about to delete the primary context NIF: this will notify Nifman that SPUD is finished.
+ DisposeOfBinder(ref);
+ }
+
+ return KErrNone;
+ }
+
+ case KContextCreate:
+ {
+ ASSERT(aOption.Ptr());
+ TContextParameters& opt=*reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ ASSERT(opt.iContextType == ESecondaryContext);
+
+ TContextId id(KAllContexts); // placeholder context ID
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = BindMan()->GetNewRefForSecondaryL(id););
+ if(KErrNone != rc)
+ {
+ __FLOG_1(_L("Error %d creating a binder for the lower NIF"), rc);
+ opt.iReasonCode = rc; // The error code is the only argument we can pass to GUQoS, because there is no context.
+ return KErrNone;
+ }
+
+
+ TRAP(rc, BindMan()->LoadNifL(iName, *ref);)
+ if (rc != KErrNone)
+ {
+ __FLOG_1(_L("Error %d loading the lower NIF"), rc);
+ FillInParameters(opt, id, rc);
+ return KErrNone;
+ }
+
+ ASSERT(ref->IsBound());
+ ref->SetState(ESpudStartingSecondary);
+
+
+ // Reset the default QoS and TFT here. KContextQoSSet should arrive soon
+ // with the proper values.
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ RPacketQoS::TQoSR5Requested qos;
+#else
+ RPacketQoS::TQoSR99_R4Requested qos;
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+ rc = iPdpFsmInterface.Set(id, qos);
+
+ TTFTInfo tft;
+ rc = iPdpFsmInterface.Set(id, tft);
+
+ // Pass in the new context ID to SpudFsm to use for the new context
+
+ // Notify SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event ECreateSecondaryPDPContext context %d"), id);
+ rc = iPdpFsmInterface.Input(id, ECreateSecondaryPDPContext);
+
+ // Set up the synchronous response
+ FillInParameters(opt, id, rc);
+ return KErrNone;
+ }
+
+ case KContextDelete:
+ {
+ ASSERT(aOption.Ptr());
+ TContextParameters& opt = *reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = BindMan()->GetRefL(opt.iContextInfo.iContextId));
+ if (rc != KErrNone)
+ {
+ __FLOG_1(_L("Error: KContextDelete specifies context %d which does not exist"), opt.iContextInfo.iContextId);
+ opt.iReasonCode = rc; // The error code is the only argument we can pass to GUQoS, because there is no context.
+ return KErrNone;
+ }
+
+ ASSERT(ref->IsBound());
+ __FLOG_3(_L("KContextDelete context[%d] in state %S(%d)"), opt.iContextInfo.iContextId, SpudStateToText(ref->State()), ref->State());
+
+ switch (ref->State())
+ {
+ // NIF is up: need to stop the NIF first, then delete the binder.
+ case ESpudGettingNegQoS:
+ case ESpudStartingSecondaryLowerNif:
+ // Assumption: GUQoS will never delete primary context.
+ case ESpudUp:
+ case ESpudFlowOff:
+ case ESpudSuspended:
+ case ESpudFlowOffAndSuspended:
+ ref->SetState(ESpudContextDelete);
+
+ if(BindMan()->IsLastContext(opt.iContextInfo.iContextId)) // Are we about to shutdown after this?
+ {
+ SetTerminateError(KErrCancel); // KErrCancel is normally used to indicate "graceful"
+ } // user-initiated shutdown.
+
+ // GUQoS ordered the shutdown: Network is still OK: initiate graceful shutdown of the lower NIF.
+ ref->NifLink()->Stop(KErrCancel, MNifIfNotify::EDisconnect);
+ break;
+
+ case ESpudStartingSecondary: // NIF not started: need to delete the context.
+ ref->SetState(ESpudWaitLinkDown);
+
+ // Delete context via SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextDelete context %d"), opt.iContextInfo.iContextId);
+ rc = iPdpFsmInterface.Input(opt.iContextInfo.iContextId, EContextDelete);
+ ASSERT(rc == KErrNone);
+ break;
+
+ case ESpudWaitLinkDown:
+ // We're in the middle of deleting. Ignore this request.
+ break;
+
+ case ESpudLinkDown:
+ // We're in the middle of deleting, but we no longer need to notify
+ // GUQoS when done.
+ ref->SetState(ESpudWaitLinkDown);
+ break;
+
+ case ESpudWaitBinderDelete: // context deleted, NIF about to be deleted: ignore.
+ break;
+
+ default:
+ __FLOG_2(_L("Unexpected state %S(%d)"), SpudStateToText(ref->State()), ref->State());
+ ASSERT(EFalse);
+ break;
+ }
+
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ case KContextActivate:
+ {
+ ASSERT(aOption.Ptr());
+ TContextParameters& opt=*reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ CSpudBinderRef* ref = NULL;
+ // Validate context ID
+ TRAPD(rc, ref = BindMan()->GetRefL(opt.iContextInfo.iContextId));
+ if (KErrNone != rc)
+ {
+ opt.iReasonCode = rc; // Can supply error code only, as the context does not exist.
+ __FLOG_1(_L("Error: KContextActivate specifies context %d which does not exist."), opt.iContextInfo.iContextId);
+ return KErrNone;
+ }
+
+ if(!ref->IsBound() || ref->State() == ESpudWaitBinderDelete)
+ {
+ __FLOG_1(_L("Error: KContextActivate specifies context %d which is not bound to lower NIF."), opt.iContextInfo.iContextId);
+ rc = KErrNotReady; // that's what the GuQoS docs say
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ __FLOG_3(_L("KContextActivate context %d in state %S(%d)"), opt.iContextInfo.iContextId, SpudStateToText(ref->State()), ref->State());
+
+ ASSERT(ref->State() == ESpudStartingSecondary || ref->State() == ESpudUp);
+
+
+ // Notify SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextActivate context %d"), opt.iContextInfo.iContextId);
+ rc = iPdpFsmInterface.Input(opt.iContextInfo.iContextId, EContextActivate);
+ // Set up the synchronous response
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ case KContextQoSSet:
+ {
+ TContextParameters& opt=*reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ CSpudBinderRef* ref = NULL;
+ // Validate context ID
+ TRAPD(rc, ref = BindMan()->GetRefL(opt.iContextInfo.iContextId));
+ if (KErrNone != rc)
+ {
+ __FLOG_1(_L("Error: KContextQoSSet specifies context %d which does not exist"), opt.iContextInfo.iContextId);
+ opt.iReasonCode = rc; // Can only supply error code, as the context does not exist.
+ return KErrNone;
+ }
+
+ if(!ref->IsBound() || ref->State() == ESpudWaitBinderDelete)
+ {
+ __FLOG_1(_L("Error: KContextQoSSet specifies context %d which is not bound to the lower NIF."), opt.iContextInfo.iContextId);
+ rc = KErrNotReady; // that's what the GuQoS docs say
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+ __FLOG_3(_L("KContextQoSSet context %d in state %S(%d)"), opt.iContextInfo.iContextId, SpudStateToText(ref->State()), ref->State());
+
+ ASSERT(ref->State() == ESpudStartingSecondary
+ || ref->State() == ESpudUp
+ || ref->State() == ESpudFlowOff
+ || ref->State() == ESpudSuspended
+ || ref->State() == ESpudFlowOffAndSuspended
+ || ref->State() == ESpudLinkDown );
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ RPacketQoS::TQoSR5Requested qos;
+#else
+ RPacketQoS::TQoSR99_R4Requested qos;
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+
+ // Store QoS parameters
+ opt.iContextConfig.GetUMTSQoSReq(qos);
+ rc = iPdpFsmInterface.Set(opt.iContextInfo.iContextId, qos);
+
+ // Notify SpudFsm
+ if (rc == KErrNone)
+ {
+ __FLOG_1(_L("Sending SpudFsm event EContextQoSSet context %d"), opt.iContextInfo.iContextId);
+ rc = iPdpFsmInterface.Input(opt.iContextInfo.iContextId, EContextQoSSet);
+ }
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ case KContextTFTModify:
+ {
+ TContextParameters& opt=*reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ CSpudBinderRef* ref = NULL;
+ // Validate context ID
+ TRAPD(rc, ref = BindMan()->GetRefL(opt.iContextInfo.iContextId));
+ if (KErrNone != rc)
+ {
+ __FLOG_1(_L("Error: KContextTFTModify specifies context %d which does not exist"), opt.iContextInfo.iContextId);
+ opt.iReasonCode = rc; // Can only supply error code as the context does not exist.
+ return KErrNone;
+ }
+
+ // keep local reference to Primary Context up to date
+ if (opt.iContextType == EPrimaryContext)
+ {
+ iPrimaryContextId = opt.iContextInfo.iContextId;
+ }
+
+ if(!ref->IsBound() || ref->State() == ESpudWaitBinderDelete)
+ {
+ __FLOG_1(_L("Error: KContextTFTModify specifies context %d which is not bound to the lower NIF."), opt.iContextInfo.iContextId);
+ rc = KErrNotReady; // that's what the GuQoS docs say
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+ __FLOG_3(_L("KContextTFTModify context %d in state %S(%d)"), opt.iContextInfo.iContextId, SpudStateToText(ref->State()), ref->State());
+
+ ASSERT(ref->State() == ESpudStartingSecondary ||
+ ref->State() == ESpudUp ||
+ ref->State() == ESpudWaitLinkDown ||
+ ref->State() == ESpudLinkDown ||
+ ref->State() == ESpudGettingNegQoS);
+ // It is assumed that the TFT can be modified before the ctx reported activation
+
+ // Store TFT parameters
+ TTFTInfo tft;
+ opt.iContextConfig.GetTFTInfo(tft);
+
+ rc = iPdpFsmInterface.Set(opt.iContextInfo.iContextId, tft);
+ if (rc != KErrNone)
+ {
+ __FLOG_1(_L("Error %d setting TFT"), rc);
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+ rc = iPdpFsmInterface.Set(opt.iContextInfo.iContextId, opt.iTFTOperationCode);
+ if (rc != KErrNone)
+ {
+ __FLOG_1(_L("Error %d setting TFT operation code"), rc);
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ // Notify SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextTFTModify context %d"), opt.iContextInfo.iContextId);
+ rc = iPdpFsmInterface.Input(opt.iContextInfo.iContextId, EContextTFTModify);
+
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ case KContextModifyActive:
+ {
+ TContextParameters& opt=*reinterpret_cast<TContextParameters*>(const_cast<TUint8*>(aOption.Ptr()));
+ CSpudBinderRef* ref = NULL;
+ // Validate context ID
+ TRAPD(rc, ref = BindMan()->GetRefL(opt.iContextInfo.iContextId));
+ if (KErrNone != rc)
+ {
+ __FLOG_1(_L("Error: KContextModifyActive specifies context %d which does not exist"), opt.iContextInfo.iContextId);
+ opt.iReasonCode = rc;
+ return KErrNone;
+ }
+
+ if(!ref->IsBound() || ref->State() == ESpudWaitBinderDelete)
+ {
+ __FLOG_1(_L("Error: KContextModifyActive specifies context %d which is not bound to the lower NIF."), opt.iContextInfo.iContextId);
+ rc = KErrNotReady; // that's what the GuQoS docs say
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ // Notify SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextModifyActive context %d"), opt.iContextInfo.iContextId);
+ rc = iPdpFsmInterface.Input(opt.iContextInfo.iContextId, EContextModifyActive);
+
+ FillInParameters(opt, opt.iContextInfo.iContextId, rc);
+ return KErrNone;
+ }
+
+ case KInitialisePdpFsm:
+ {
+ MPdpFsmInterface* pdpFsm = *reinterpret_cast<MPdpFsmInterface**>(const_cast<TUint8*>(aOption.Ptr()));
+ iPdpFsmInterface.Init(pdpFsm);
+ return KErrNone;
+ }
+
+ default:
+ __FLOG_1(_L("Unhandled event %d"), aName);
+ break;
+ }
+ return KErrNotSupported;
+ }
+
+/**
+Receives link up indication from a lower NIF.
+
+@param aContextId PDP context ID of the associated lower NIF
+*/
+void CSpudMan::LinkLayerUp(TContextId aContextId)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound() && ref->State() != ESpudWaitBinderDelete);
+
+ __FLOG_3(_L("Lower NIF LinkLayerUp on context[%d], in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ switch (ref->State())
+ {
+ case ESpudStartingPrimaryLowerNif:
+ {
+ ref->SetState(ESpudUp);
+ if (AreQoSEventsEnabled())
+ {
+ SendPrimaryContextCreated(aContextId, KErrNone);
+ }
+ // If QoS is not yet enabled, SendPrimaryContextCreated() will be called when it is
+
+ Notify()->LinkLayerUp();
+
+ // If mobile IP is enabled, this progress notification should not be sent here.
+ // This will need to be addressed if MIP is ever enabled for UMTS.
+ Notify()->IfProgress(KLinkLayerOpen, KErrNone);
+ }
+ break;
+
+ case ESpudStartingSecondaryLowerNif:
+ {
+ // lower nif is up, now get the Negotiated QoS
+ ref->SetState(ESpudGettingNegQoS);
+
+ TInt rc = iPdpFsmInterface.Input(aContextId, EGetNegQoS);
+ ASSERT(rc == KErrNone);
+ // Now wait for retrieval of negotiated QoS.
+ // The following 2 functions will be fired from CSpudMan::HandleGetNegQoSEvent():
+ // FillInContextConfig(iTempContextConfig, aContextId);
+ // SendContextActivateEvent(aContextId, iTempContextConfig, KErrNone);
+ }
+ break;
+
+ default:
+ __FLOG_3(_L("Lower NIF LinkLayerUp on context[%d], in unexpected state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ ASSERT(EFalse);
+ }
+ }
+
+/**
+Receives link down indication from a lower NIF.
+
+@param aContextId Valid PDP context ID of the associated lower NIF
+@param aReason A Symbian OS error code indicating the reason for the link closing down
+@param aAction The action that should be taken as a result of link layer down being signalled
+*/
+void CSpudMan::LinkLayerDown(TContextId aContextId, TInt aReason, MNifIfNotify::TAction aAction)
+ {
+ __FLOG_3(_L("CSpudMan::LinkLayerDown: context %d reason %d action %d"), aContextId, aReason, aAction);
+
+ if (aAction == MNifIfNotify::ENoAction)
+ {
+ // This call indicates a renegotiation of the lower link, not that the link has
+ // actually gone down. This is of no interest to SPUD.
+ __FLOG_0(_L("Ignoring MNifIfNotify::ENoAction"));
+ return;
+ }
+
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+
+
+ TBool isUpperFlowOn = EFalse; // Can GUQoS attempt to send on this PDP context?
+
+ switch (ref->State())
+ {
+ case ESpudUp:
+ isUpperFlowOn = ETrue; // ESpudUp is the only state where GUQoS is allowed to send on us.
+ // Fall through
+ case ESpudFlowOff:// NIF & context were activated succcessfully.
+ case ESpudSuspended:
+ case ESpudFlowOffAndSuspended:
+ ref->SetState(ESpudLinkDown); // Must Notify GUQoS that context is down.
+
+ // Must inform upper layers they can no longer send on this context.
+ if (isUpperFlowOn && AreQoSEventsEnabled())
+ {
+ // At this point the context status does not indicate to GUQoS that the context is about to go down.
+ // Most likely, the status is EStatusActive, indicating that the context can handle requests.
+ // Since the lower NIF is down, we are about to delete the context, so logically, this context
+ // is EStatusDeactivating.(From spudman's PoV, a context is a union of lower NIF and ETel's RPacketContext)
+ // GUQoS does not know this, it may try to issue requests,
+ // such as send packets on this context, modify TFT, modify QoS, etc.
+ // Note: this does not seem to happen, but it is feasible.
+
+ // N.B. Ideally, we should signal context change status in not just in EStateUp, but in
+ // EStateFlowOff etc, i.e. any state in which the context is alive. Unfortunately, GUQoS
+ // does not allow us to do this - there is no pure "ContextStatusChange" upcall on GUQoS.
+ // Context Parameters Change upcall should not be used, because GUQoS interprets it as a
+ // QoS parameters change, and sends QoSEventAdapt to the QoS framework. This is wrong.
+ //
+ // We could send ContextBlocked in FlowOff / Suspended states, however, this is problematic,
+ // because GUQoS has already received one of these notifications. We could "trick" it and cycle
+ // the state (send Flow On / Resume, then Flow Off / Suspend again), but this hackery should be
+ // avoided unless absolutely necessary. So far, GUQoS does not seem to do anything beside sending
+ // a packet on a deactivaing context, so we only worry about it.
+
+ // N.B. SpudFSM is asynchronous, it will not issue a an actual deletion request on ETel until this RunL
+ // returns. This means that the context status will not be updated to EStatusDeactiving in ETel
+ // until then, so when we fill in context paramters, the status is going to be EStatusActive.
+ // We "sneak in" the correct status by overriding it. Doing it in SpudFSM would be wrong, because
+ // SpudFSM reflects the ETel side of the context, so overriding the status there is misleading,
+ // because it can be used internally by SpudFSM / SpudTel.
+
+ __FLOG_0(_L("Upper flow on the context is On: flow Off GUQoS to prevent it from sending on a context with dead lower NIF."));
+ iContextStatusOverride = RPacketContext::EStatusDeactivating;
+ SendContextBlockedEvent(aContextId); // resets the override
+ isUpperFlowOn = EFalse;
+ }
+
+ // The only way we can notify GUQoS once the context has been activated is
+ // to delete it via the SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextDelete context %d"), aContextId);
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ __FLOG_1(_L("SpudFsm::Input() returned status %d"), rc);
+ if (rc == KErrNotReady) //This is becuase the FSM has been shut down via UMTSGPRSSCPR
+ {
+ HandleContextDeleteEvent(aContextId, aReason); //Just pretend that the fsm returned something sensible
+ }
+ ASSERT(rc == KErrNone || rc == KErrNotReady);
+ break;
+
+ case ESpudGettingNegQoS: // CNifIfLink::Stop will handle this just as if the NIF was still being CNifIfLink::Start'ed.
+ case ESpudStartingSecondaryLowerNif: // Attempt to bring up the lower NIF was made.
+ ref->SetState(ESpudStartingSecondary); // GUQoS should delete us later.
+ // Notify GUQoS that Activation failed. It will take the control from here, most likely deleting the context.
+ FillInContextConfig(iTempContextConfig, aContextId);
+ if(ref->Error() != KErrNone)
+ {
+ SendContextActivateEvent(aContextId, iTempContextConfig, ref->Error());
+ }
+ else
+ {
+ SendContextActivateEvent(aContextId, iTempContextConfig, aReason);
+ }
+ break;
+
+ case ESpudContextDelete:
+ ref->SetState(ESpudWaitLinkDown); // GUQoS triggered us: don't need to notify it.
+
+ // Delete context via SpudFsm
+ __FLOG_1(_L("Sending SpudFsm event EContextDelete context %d"), aContextId);
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ __FLOG_1(_L("SpudFsm::Input() returned status %d"), rc);
+ ASSERT(rc == KErrNone);
+ break;
+
+ case ESpudStartingSecondary:
+ case ESpudLinkDown: // Added for INC066156.
+ case ESpudWaitLinkDown:
+ // Link has finally gone down. Context is already deleted.
+ __FLOG_1(_L("Lower NIF reported LinkLayerDown: mark the binder for context[%d] for async deletion"), aContextId);
+ DisposeOfBinder(ref);
+ break;
+
+ case ESpudStartingPrimaryLowerNif:
+ {
+ SetTerminateError(aContextId, aReason); // SPUD is going to terminate.
+ SetTerminateError(KErrCouldNotConnect);
+
+ // The primary context is managed by SPUD. We delete it ourselves.
+ __FLOG_1(_L("Sending SpudFsm event EContextDelete context %d"), aContextId);
+ ref->SetState(ESpudWaitLinkDown);
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ __FLOG_1(_L("SpudFsm::Input() returned status %d"), rc);
+ ASSERT(rc == KErrNone);
+
+ // Meanwhile, notify GUQoS about the failed primary creation
+ if (AreQoSEventsEnabled())
+ {
+ SendPrimaryContextCreated(aContextId, aReason);
+ }
+ break;
+ }
+
+ default:
+ __FLOG_2(_L("Unexpected state %S(%d)"), SpudStateToText(ref->State()), ref->State());
+ ASSERT(EFalse);
+ break;
+ }
+ }
+
+/**
+Receives flow off indication from a lower NIF.
+
+@param aContextId Valid PDP context ID of the associated lower NIF
+*/
+void CSpudMan::StopSending(TContextId aContextId)
+ {
+ __FLOG_1(_L("CSpudMan::StopSending context %d"), aContextId);
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ switch (ref->State())
+ {
+ case ESpudUp:
+ ref->SetState(ESpudFlowOff);
+ if (AreQoSEventsEnabled())
+ {
+ SendContextBlockedEvent(aContextId);
+ }
+ break;
+
+ case ESpudSuspended:
+ ref->SetState(ESpudFlowOffAndSuspended);
+ break;
+
+ case ESpudContextDelete:
+ case ESpudWaitLinkDown:
+ case ESpudLinkDown: //sometimes this leaks in
+ // ignore
+ break;
+
+ default:
+ // error
+ __FLOG_2(_L("Unexpected state %S(%d)"), SpudStateToText(ref->State()), ref->State());
+ ASSERT(EFalse);
+ break;
+ }
+ }
+
+/**
+Receives flow on indication from a lower NIF.
+
+@param aContextId Valid PDP context ID of the associated lower NIF
+*/
+void CSpudMan::StartSending(TContextId aContextId)
+ {
+ __FLOG_1(_L("CSpudMan::StartSending context %d"), aContextId);
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ __FLOG_3(_L("context %d is in state %S(%d)"), aContextId, SpudStateToText(ref->State()), ref->State());
+ switch (ref->State())
+ {
+ case ESpudGettingNegQoS: // Lower NIF for the 2ndary ctx is up, waiting for negotiated QoS.
+ break; // GUQoS, TCP/IP stack will be notified when negotiated QoS is retrieved.
+ // Notes:
+ // 1.there is a *potential* race condition where the negotiated QoS is retrived before lower NIF signals StartSending.
+ // This does not seem to happen with PPP. If this happens somehow, the ctx will be in the "UP" state and it will be handled correctly.
+ // 2. Theoretically, the lower NIF may report LinkLayerUp (triggering retrieval of negotiated QoS), then signal
+ // StartSending much later (e.g. a PPP implementation singalling LinkLayerUp from LCP, but StartSending from NCP).
+ // SPUD CANNOT HANDLE THIS.
+ // Existing Raw IP and PPP NIFs signal StartSending immediately after LinkLayerUp, so this has no consequences.
+
+ case ESpudUp:
+ // This can happen for the initial StartSending after the lower NIF comes up
+ // Treat it the same as ESpudFlowOff and fall through.
+ case ESpudFlowOff:
+ ref->SetState(ESpudUp);
+
+ // This must only be done AFTER the KPrimaryContextCreated event is sent (which in this state it is)
+ // It's not clear if StartSending is needed/allowed in addition to the GUQoS event.
+ BindMan()->SpudProtocol()->DoStartSending();
+
+ if (AreQoSEventsEnabled())
+ {
+ SendContextUnblockedEvent(aContextId);
+ }
+ break;
+
+ case ESpudFlowOffAndSuspended:
+ ref->SetState(ESpudSuspended);
+ break;
+
+ case ESpudSuspended:
+ case ESpudContextDelete:
+ case ESpudWaitLinkDown:
+ // ignore
+ __FLOG_1(_L("Ignored StartSending on context %d (this should be OK)"), aContextId);
+ break;
+
+ default:
+ // We have encountered a serious problem. If we get StartSending before reaching the ESpudUp
+ // state, we'll lose it and the upper networking protocol will never be notified.
+ // As long as the lower NIF calls LinkLayerUp before StartSending, we'll be fine.
+ __FLOG_1(_L("Can't send unblocked event now on context %d; this may cause problems"), aContextId);
+ ASSERT(EFalse);
+ break;
+ }
+ }
+
+
+//*****************************************************************************
+// Event senders to GUQoS
+//*****************************************************************************
+
+/**
+Sends event to GUQoS.
+
+@param aName event identifier
+@param aOption TPckg<> event data
+*/
+void CSpudMan::RaiseEvent(TUint aName, TDes8& aOption) const
+ {
+ __FLOG_2(_L("Sending event %S(%d) to GUQoS"), SpudFsmEventToText(aName), aName);
+ iQosEventHandler->Event(reinterpret_cast<CProtocolBase*>(iBindMan->SpudMux()), aName, aOption);
+ }
+
+/**
+Fills in common event parameters for the given context.
+
+@param aParams parameter structure
+@param aContextId Valid PDP context ID
+*/
+void CSpudMan::FillInParameters(TContextParameters& aParams, TContextId aContextId, TInt aError) const
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = BindMan()->GetRefL(aContextId));
+ ASSERT(rc == KErrNone);
+
+ TContextType type(EContextTypeUnknown);
+ if (rc == KErrNone)
+ {
+ switch (ref->State())
+ {
+ case ESpudHaveQos:
+ case ESpudCreatingPrimary:
+ case ESpudStartingPrimary:
+ type = EPrimaryContext;
+ break;
+
+ case ESpudStartingSecondary:
+ type = ESecondaryContext;
+ break;
+
+ default:
+ type = (aContextId == iPrimaryContextId) ? EPrimaryContext : ESecondaryContext;;
+ break;
+ }
+ }
+ aParams.iContextType = type; // Context type
+ aParams.iReasonCode = aError; // Error code
+ //aParams.iContextInfo.iStatus = StateToStatus(*ref);
+ iPdpFsmInterface.Get(aContextId, aParams.iContextInfo.iStatus);
+ aParams.iContextInfo.iContextId = aContextId;
+ }
+
+/**
+Fill in context configuration parameter structure using SpudFsm's parameters.
+
+@param aConfig parameter structure
+@param aContextId PDP context ID
+*/
+void CSpudMan::FillInContextConfig(TContextConfig& aConfig, TContextId aContextId) const
+ {
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ RPacketQoS::TQoSR5Negotiated qos;
+#else
+ RPacketQoS::TQoSR99_R4Negotiated qos;
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+
+ iPdpFsmInterface.Get(aContextId, qos);
+ aConfig.SetUMTSQoSNeg(qos);
+
+ iPdpFsmInterface.Get(aContextId, iTempTftInfo);
+ aConfig.SetTFTInfo(iTempTftInfo);
+
+ iPdpFsmInterface.Get(aContextId, iTempGprsContext);
+ aConfig.SetContextConfig(iTempGprsContext);
+ }
+
+/**
+Sends KPrimaryContextCreated event to GUQoS.
+*/
+void CSpudMan::SendPrimaryContextCreated(TContextId aContextId, TInt aError)
+ {
+ __FLOG_2(_L("SendPrimaryContextCreated context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+ // We make this assumption in various places
+ ASSERT(aContextId == 0);
+
+ TContextParameters primaryContextCreatedEvent;
+ FillInParameters(primaryContextCreatedEvent, aContextId, aError);
+ TPckg<TContextParameters> event(primaryContextCreatedEvent);
+ RaiseEvent(KPrimaryContextCreated, event);
+ }
+
+
+/**
+Sends KSecondaryContextCreated event to GUQoS.
+
+@param aContextId Context ID
+@param aError error code
+*/
+void CSpudMan::SendSecondaryContextCreated(TContextId aContextId, TInt aError)
+ {
+ __FLOG_2(_L("SendSecondaryContextCreated context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ // We make this assumption in various places
+ ASSERT(aContextId != 0);
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KSecondaryContextCreated, eventPckg);
+ }
+
+
+/**
+Sends KContextBlockedEvent event to GUQoS.
+*/
+void CSpudMan::SendContextBlockedEvent(TContextId aContextId)
+ {
+ __FLOG_2(_L("SendContextBlockedEvent context %d error %d"), aContextId, KErrNone);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId);
+
+ /** The status we want to signal to GUQoS may be different from the context status we get from SpudFSM
+ E.g., if we are about to deactivate the context, the logical status of the context is EStatusDeactivating, rather than
+ EStatusActive, even though that's what SpudFSM will tell us */
+ if(RPacketContext::EStatusUnknown != iContextStatusOverride)
+ {
+ __FLOG_2(_L("SendContextBlockedEvent: context status overriden to %d, original: %d."),
+ iContextStatusOverride, event.iContextInfo.iStatus);
+
+ event.iContextInfo.iStatus = iContextStatusOverride;
+ iContextStatusOverride = RPacketContext::EStatusUnknown;
+ }
+
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextBlockedEvent, eventPckg);
+ }
+
+/**
+Sends KContextUnblockedEvent event to GUQoS.
+*/
+void CSpudMan::SendContextUnblockedEvent(TContextId aContextId)
+ {
+ __FLOG_2(_L("SendContextUnblockedEvent context %d error %d"), aContextId, KErrNone);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId);
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextUnblockedEvent, eventPckg);
+ }
+
+/**
+Sends KContextQoSSetEvent event to GUQoS.
+
+@param aContextId Context ID
+@param aError error code
+*/
+void CSpudMan::SendContextQoSSetEvent(TContextId aContextId, TInt aError)
+ {
+ __FLOG_2(_L("SendContextQoSSetEvent context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextQoSSetEvent, eventPckg);
+ }
+
+/**
+Sends KContextTFTModifiedEvent event to GUQoS.
+
+@param aContextId Context ID
+#param aTFTOperationCode TFT operation code
+@param aError error code
+*/
+void CSpudMan::SendContextTFTModifiedEvent(TContextId aContextId, TTFTOperationCode aTFTOperationCode, TInt aError)
+ {
+ __FLOG_2(_L("SendContextTFTModifiedEvent context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ // Also need to fill in TTFTOperationCode, an undocumented requirement
+ event.iTFTOperationCode = aTFTOperationCode;
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextTFTModifiedEvent, eventPckg);
+ }
+
+/**
+Sends KContextModifyActiveEvent event to GUQoS.
+
+@param aContextId Context ID
+@param aContextConfig Configuration parameters for this context
+@param aError error code
+*/
+void CSpudMan::SendContextModifyActiveEvent(TContextId aContextId, TContextConfig& aContextConfig, TInt aError)
+ {
+ __FLOG_2(_L("SendContextModifyActiveEvent context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ event.iContextConfig = aContextConfig;
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextModifyActiveEvent, eventPckg);
+ }
+
+/**
+Sends KContextActivateEvent event to GUQoS.
+
+@param aContextId Context ID
+@param aContextConfig Configuration parameters for this context
+@param aError error code
+*/
+void CSpudMan::SendContextActivateEvent(TContextId aContextId, TContextConfig& aContextConfig, TInt aError)
+ {
+ __FLOG_2(_L("SendContextActivateEvent context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ event.iContextConfig = aContextConfig;
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextActivateEvent, eventPckg);
+ }
+
+/**
+Sends KContextParametersChangeEvent event to GUQoS.
+
+@param aContextId Context ID
+@param aContextConfig Configuration parameters for this context
+@param aError error code
+*/
+void CSpudMan::SendContextParametersChangeEvent(TContextId aContextId, TContextConfig& aContextConfig, TInt aError)
+ {
+ __FLOG_2(_L("SendContextParametersChangeEvent context %d error %d"), aContextId, aError);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId, aError);
+ event.iContextConfig = aContextConfig;
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextParametersChangeEvent, eventPckg);
+ }
+
+/**
+Sends KContextDeleteEvent event to GUQoS.
+
+@param aContextId Context ID
+*/
+void CSpudMan::SendContextDeleteEvent(TContextId aContextId)
+ {
+ __FLOG_2(_L("SendContextDeleteEvent context %d error %d"), aContextId, KErrNone);
+
+ if (!iQosEventsEnabled)
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TContextParameters event;
+ FillInParameters(event, aContextId);
+ TPckg<TContextParameters> eventPckg(event);
+ RaiseEvent(KContextDeleteEvent, eventPckg);
+ }
+
+/**
+Sends KNetworkStatusEvent event to GUQoS.
+
+@param aEventCode Event code
+@param aStatus Network status
+*/
+void CSpudMan::SendNetworkStatusEvent(TNetworkEventCode aEventCode, RPacketService::TStatus aStatus)
+ {
+ __FLOG_2(_L("SendNetworkStatusEvent event code %d status %d"), aEventCode, aStatus);
+
+ if (!iQosEventsEnabled) // QoS events not turned on yet, or have been turned off by GUQoS
+ {
+ __FLOG_0(_L("Error: sending events is disabled - GuQoS not present ?"));
+ return;
+ }
+
+ TNetworkParameters event;
+ event.iNetworkEventCode = aEventCode;
+ event.iNetworkStatus = aStatus;
+ TPckg<TNetworkParameters> eventPckg(event);
+ RaiseEvent(KNetworkStatusEvent, eventPckg);
+ }
+
+
+//*****************************************************************************
+// CNifIfLink methods
+//*****************************************************************************
+
+
+/**
+Return the link protocol handler object.
+
+@param aName Protocol name desired
+@return Pointer to link protocol handler (ownership is transferred)
+*/
+CNifIfBase* CSpudMan::GetBinderL(const TDesC& aName)
+ {
+ __FLOG_1(_L("CSpudMan::GetBinderL %S"), &aName);
+ iName = aName;
+ return static_cast<CNifIfBase*>(iBindMan->TransferSpudMux());
+ }
+
+/**
+Return information about the SPUD NIF.
+
+@param aInfo Receives the NIF interface info
+*/
+void CSpudMan::Info(TNifIfInfo& aInfo) const
+ {
+ CSpudBinderRef* ref = NULL;
+ // Get the binder for the first (default) lower NIF.
+ TRAPD(err, ref = iBindMan->GetAnyRefL());
+ if (err == KErrNone)
+ {
+ // Read the protocol supported value from the lower NIF
+ ref->NifLink()->Info(aInfo);
+ ASSERT(aInfo.iFlags == (KNifIfIsBase | KNifIfUsesNotify | KNifIfIsLink | KNifIfCreatedByFactory | KNifIfCreatesBinder));
+ }
+ else
+ {
+ aInfo.iProtocolSupported=KProtocolUnknown;
+ }
+
+ aInfo.iVersion = TVersion(KSpudMajorVersionNumber, KSpudMinorVersionNumber, KSpudBuildVersionNumber);
+ aInfo.iFlags = KNifIfIsBase |
+ KNifIfUsesNotify |
+ KNifIfIsLink |
+ KNifIfCreatedByFactory |
+ KNifIfCreatesBinder;
+ aInfo.iName = KSpudName;
+ }
+
+/**
+Processes notifications from Agent
+
+@param aEvent Event type
+@param aInfo Data relating to event
+
+@return Error code
+*/
+TInt CSpudMan::Notification(TAgentToNifEventType aEvent, void * aInfo)
+ {
+ __FLOG_1(_L("CSpudMan::Notification event %d"), aEvent);
+ TInt rc = KErrNotSupported;
+ switch (aEvent)
+ {
+ case EAgentToNifEventTypeModifyInitialTimer:
+ case EAgentToNifEventTypeDisableTimers:
+ case EAgentToNifEventTypeEnableTimers:
+ case EAgentToNifEventTsyConfig:
+ case EAgentToNifEventTsyConnectionSpeed:
+ // Send notification to all lower NIFs
+ rc = KErrNotReady;
+ TContextId i;
+ for (i=0; i < KMaxPdpContexts; ++i)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAP(rc, ref = iBindMan->GetRefL(i));
+ if (rc == KErrNone)
+ {
+ rc = ref->NifLink()->Notification(aEvent, aInfo);
+ }
+ }
+ break;
+
+ case EAgentToNifEventTypeGetDataTransfer:
+ {
+ TPckg<RPacketContext::TDataVolume>* totalDataPackage = (TPckg<RPacketContext::TDataVolume>*) aInfo;
+ RPacketContext::TDataVolume& totalData = (*totalDataPackage)();
+ totalData.iBytesSent = 0;
+ totalData.iOverflowCounterSent = 0;
+ totalData.iBytesReceived = 0;
+ totalData.iOverflowCounterReceived = 0;
+
+ RPacketContext::TDataVolume data;
+ TPckg<RPacketContext::TDataVolume> dataPackage(data);
+
+ // Add up data reported by all NIFs
+ rc = KErrNotReady;
+ TContextId i;
+ for (i=0; i < KMaxPdpContexts; ++i)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAP(rc, ref = iBindMan->GetRefL(i));
+ if (rc == KErrNone)
+ {
+ rc = ref->NifLink()->Notification(aEvent, &dataPackage);
+ if (rc == KErrNone)
+ {
+ totalData.iBytesSent += data.iBytesSent;
+ totalData.iOverflowCounterSent += data.iOverflowCounterSent;
+ totalData.iBytesReceived += data.iBytesReceived;
+ totalData.iOverflowCounterReceived += data.iOverflowCounterReceived;
+ }
+ }
+ }
+ break;
+ }
+
+ case EAgentToNifEventTypeDisableConnection:
+ // TODO: what to do with this?
+ default:
+ __FLOG_1(_L("Notification event %d was ignored"), aEvent);
+ break;
+ }
+
+ return rc;
+ }
+
+
+/**
+Start the link.
+At this point only the primary PDP context is valid.
+
+@return Error code
+*/
+TInt CSpudMan::Start()
+ {
+ __FLOG_1(_L("CSpudMan::Start(0x%x)"), this);
+
+ // SpudTel needs TSY name from CommDb
+ TName tsyName;
+ ReadTsyName(tsyName);
+
+ // Initialise SpudFsm
+ TRAPD(err, InitPdpFsmInterfaceL());
+ if (err != KErrNone)
+ {
+ __FLOG_1(_L("CSpudMan::Start: Failed to initialise the PDP Fsm Interface,Error = %d"),err);
+ return err;
+ }
+
+ // Open SpudFsm
+ TRAP(err, iPdpFsmInterface.OpenL(this, tsyName));
+ if (err != KErrNone)
+ {
+ __FLOG_1(_L("CSpudMan::Start: Failed to open the PDP Fsm Interface,Error = %d"),err);
+ return err;
+ }
+
+
+ // re-initialise the temporary data structure before retrieving
+ // GPRS config parameters from CommDB
+ __FLOG_0(_L("CSpudMan::Start: Getting default GPRS settings from Commdb"));
+ RetrieveGprsConfig(iTempGprsContext);
+
+ TRAP(err, SetupSipServerAddrRetrievalL(iTempGprsContext.iProtocolConfigOption););
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ // Add the IMCN Signalling Status flag. IM CN status flag is retrieved from the Database
+ // Request For the status of IM CN dedicated signalling context
+ TRAP(err,SetIMCNSignallingFlagPcoL(iTempGprsContext.iProtocolConfigOption));
+
+ // Not sure what can be done after trapping the error, because its not an error condition for starting of
+ // Primary PDP context.
+#ifdef __FLOG_ACTIVE
+ if(err != KErrNone)
+ {
+ __FLOG_1(_L("CSpudMan::Start: Failed to set IM CN signalling Flag.Error = %d"),err);
+ }
+#endif
+#endif // SYMBIAN_NETWORKING_UMTSR5
+
+ iPdpFsmInterface.Set(iPrimaryContextId, iTempGprsContext);
+ if (err != KErrNone)
+ {
+ __FLOG_1(_L("CSpudMan::Start: Setup sip server address retrieval. Failed with %d"),err);
+ return err;
+ }
+
+ if (iParkedDefaultQoS != NULL)
+ {
+ __FLOG_0(_L("CSpudMan::Start: Found parked QoS settings from GuQoS"));
+
+ TPtr8 qos(iParkedDefaultQoS->Des());
+ GuqosInput (KNifSetDefaultQoS, qos);
+
+ delete iParkedDefaultQoS;
+ iParkedDefaultQoS = NULL;
+ }
+
+ CSpudBinderRef* ref = NULL;
+ // Get the binder for the first (default) lower NIF.
+ TRAP(err, ref = iBindMan->GetRefL(iPrimaryContextId));
+ if (err != KErrNone)
+ {
+ __FLOG_0(_L("CSpudMan::Start: Error - no context could be found"));
+ return err;
+ }
+
+ ASSERT(ref->State() == ESpudInactive || ref->State() == ESpudHaveQos);
+ ASSERT(ref->State() != ESpudWaitBinderDelete);
+
+ if (ref->State() == ESpudWaitBinderDelete)
+ {
+ return KErrNotReady;
+ }
+
+ if (ref->State() != ESpudHaveQos)
+ {
+ __FLOG_0(_L("CSpudMan::Start: No QoS parameters have been set - is GuQoS present?"));
+
+ // Sets default QoS parameters because either
+ // 1) they weren't supplied by GUQoS - this shouldn't happen
+ // 2) or GuQoS has been configured out
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ // Sets default R5 QoS parameters because they weren't supplied by GUQoS.
+ RPacketQoS::TQoSR5Requested qos;
+ ReadDefaultR5QoS(qos);
+#else
+ RPacketQoS::TQoSR99_R4Requested qos;
+ ReadDefaultQoS(qos);
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+ iPdpFsmInterface.Set(iPrimaryContextId, qos); // ignore any error
+
+ }
+
+ // Set default TFT
+ TTFTInfo tft;
+ iPdpFsmInterface.Set(iPrimaryContextId, tft); // ignore any error
+
+
+ // Have Etel create a context
+ ref->SetState(ESpudCreatingPrimary);
+ __FLOG_1(_L("CSpudMan::Start: Sending SpudFsm event ECreatePrimaryPDPContext context %d"), iPrimaryContextId);
+ TInt rc = iPdpFsmInterface.Input(iPrimaryContextId, ECreatePrimaryPDPContext);
+ // TODO: handle errors properly
+ ASSERT(rc == KErrNone);
+ rc = rc; // Eliminate compiler warning in release builds
+
+ return KErrNone;
+ }
+
+/**
+Cleanly stop the link.
+
+@param aReason The reason the link is going down
+@param aAction The action to take once the link is down
+*/
+void CSpudMan::Stop(TInt aReason, MNifIfNotify::TAction aAction)
+ {
+ __FLOG_3(_L("CSpudMan::Stop: reason %d action %d. %d contexts exist."), aReason, aAction, BindMan()->NumContexts());
+ ASSERT(BindMan()->NumContexts()); // Primary PDP context is created in the factory.
+
+ SetTerminateError(aReason); // Store this error code for use when the SPUD goes down
+ if (AreQoSEventsEnabled())
+ {
+ // Spud was administratively stopped. It can be some time before SPUD signals LinkLayerDown.
+ // In the meanwhile, we can receive requests from GUQoS that can interfere with the shutdown.
+ // To prevent this, we tell GUQoS to stop bothering SPUD.
+ // GUQoS returns the favour by turning off the NIF events within this very call.
+ // This means we will not send KNetworkInterfaceDown again, even though we'll try.
+ // *********************************************************************************************
+ // N.B.: "DEF055691 GUQoS crashes at shutdown": This defect results in GUQoS crash if the stack
+ // closes flows after the NIF proxy was deleted by GUQoS, as a result of KNetworkInterfaceDown event.
+ // As a temporary workaround, this call is disabled, and KNetworkInterfaceDown event is signalled only
+ // from the destructor. Once this defect is fixed, the following line must be uncommented:
+ // SendNetworkStatusEvent(KNetworkInterfaceDown, RPacketService::EStatusUnattached);
+ //**********************************************************************************************
+ }
+
+
+ // Send Stop to all lower NIFs that were started but not stopped yet
+ TContextId i;
+ for (i=0; i < KMaxPdpContexts; ++i)
+ {
+ StopContext(i, aReason, aAction);
+ }
+ // Eventually, the last lower NIF will call LinkLayerDown to trigger the final cleanup
+ }
+
+/**
+Cleanly stop a context.
+
+@param aReason The reason the link is going down
+@param aAction The action to take once the link is down
+@param aContextId context
+*/
+void CSpudMan::StopContext(TContextId aContextId, TInt aReason, MNifIfNotify::TAction aAction)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ if (rc == KErrNone && // Binder exists
+ ref->IsBound()) // Is bound to a lower NIF.
+ {
+
+ // Save the Context failure reason
+ if (ref->Error() == KErrNone)
+ {
+ ref->SetError(aReason);
+ }
+
+ switch(ref->State()) // NIFs in some states are not eligible for Stop.
+ {
+ // Context created and NIF started.
+ case ESpudStartingPrimaryLowerNif: // Waiting for LinkLayerUp/Down
+ case ESpudStartingSecondaryLowerNif:// Waiting for LinkLayerUp/Down
+ case ESpudGettingNegQoS: // Waiting for retrieval of negotiated QoS, context activated
+ case ESpudUp: // LinkLayerUp received, NIF is up.
+ case ESpudFlowOff: // LinkLayerUp received, NIF is up.
+ case ESpudSuspended: // LinkLayerUp received, NIF is up.
+ case ESpudFlowOffAndSuspended: // LinkLayerUp received, NIF is up.
+ __FLOG_2(_L("Lower NIF binder for context[%d] is in state[%S]: Stopping lower NIF."),aContextId,SpudStateToText(ref->State()));
+ // Stop the NIF and delete the context via SpudFsm:
+ ref->NifLink()->Stop(aReason, aAction);
+ // stay in the Up state so that that GUQoS is notified.
+ break;
+
+ // Context is being created
+ case ESpudCreatingPrimary:
+ // SpudFsm will clean up the context and generate a context created event with an error
+ rc = iPdpFsmInterface.Input(aContextId, ECancelContextCreate);
+ break;
+
+ // Context created, but NIF not started
+ case ESpudStartingPrimary:
+ ref->SetState(ESpudWaitLinkDown);
+ // Any outstanding SpudFsm request will be cancelled by this delete request.
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ aReason = (KErrNone != aReason) ? aReason : KErrCancel; // Must not be KErrNone.
+ SendPrimaryContextCreated(aContextId, aReason);
+ break;
+
+ case ESpudStartingSecondary:
+ // Delete the context via SpudFsm
+ ref->SetState(ESpudLinkDown); // We'll notify GUQoS from deletion event handler.
+ __FLOG_1(_L("Context[%d] created: Sending SpudFsm event EContextDelete"), aContextId);
+
+ // Any outstanding SpudFsm request will be cancelled by this delete request.
+ rc = iPdpFsmInterface.Input(aContextId, EContextDelete);
+ ASSERT(rc == KErrNone);
+ break;
+
+ // Can't call Stop: the NIF either not started, or stopped already
+ case ESpudContextDelete: // Context deleted by GUQoS, Stop was called.
+ case ESpudWaitLinkDown: // Stop was called, waiting for LinkLayerDown
+ case ESpudWaitBinderDelete: // LinkLayerDown received, queued for deletion
+ case ESpudLinkDown: // LinkLayerDown received, not queued for deletion.
+ __FLOG_2(_L("Lower NIF binder for context[%d] is in state[%S], and is not eligible for Stop."),aContextId,SpudStateToText(ref->State()));
+ break;
+
+ case ESpudHaveQos:
+ default:
+ __FLOG_2(_L("Lower NIF binder for context[%d] is in unexpected state[%S]."),aContextId,SpudStateToText(ref->State()));
+ ASSERT(EFalse);
+ break;
+ }
+ }
+ }
+
+/**
+Send a packet across the link.
+This function should not be called; the Mux is the one that should get the data.
+
+@param aPacket MBuf chain containing packet (ignored)
+@param aSource (ignored)
+
+@return Error code, or 1 if packet was queued,
+ or KErrNone to flow off sender
+*/
+TInt CSpudMan::Send(RMBufChain& /*aPacket*/, TAny* /*aSource*/)
+ {
+ _LIT(KPanicMsg, "CSpudMan");
+ User::Panic(KPanicMsg, KErrNotSupported);
+ return KErrNotSupported; // never reached
+ }
+
+
+/**
+Receives notification from NIFMAN that the authenticate data is ready.
+*/
+void CSpudMan::AuthenticateComplete(TInt aResult)
+ {
+ // Send AuthenticateComplete to all lower NIFs
+ TContextId i;
+ for (i=0; i < KMaxPdpContexts; ++i)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(i));
+ if (rc == KErrNone)
+ {
+ ref->NifLink()->AuthenticateComplete(aResult);
+ }
+ }
+ }
+
+void CSpudMan::Restart(CNifIfBase* /*aIf*/)
+ {
+ // TODO: Is it safe to simply ignore this?
+ __FLOG_0(_L("CSpudMan::Restart. Ignored."));
+ ASSERT(EFalse);
+ }
+
+
+//*****************************************************************************
+// SPUD methods
+//*****************************************************************************
+
+/**
+Receives progress notifications from lower NIF.
+
+@param aContextId Context ID of lower NIF
+@param aStage Progress stage
+@param aError Error code
+*/
+void CSpudMan::IfProgress(TContextId aContextId, TInt aStage, TInt aError)
+ {
+ __FLOG_3(_L("CSpudMan::IfProgress context ID %d received stage %d error %d"),
+ aContextId, aStage, aError);
+ // Eliminate compiler warnings in release builds
+ aContextId = aContextId;
+ aStage = aStage;
+ aError = aError;
+
+ // Drop all progress indications from lower NIFs on the floor because they'll just confuse NIFMAN.
+ // SpudMan generates its own progress notifications.
+ }
+
+/**
+Receives progress notifications from lower NIF.
+
+@param aContextId Context ID of lower NIF
+@param aSubConnectionUniqueId Subconnection ID
+@param aStage Progress stage
+@param aError Error code
+*/
+void CSpudMan::IfProgress(TContextId aContextId, TSubConnectionUniqueId aSubConnectionUniqueId, TInt aStage, TInt aError)
+ {
+ __FLOG_4(_L("CSpudMan::IfProgress context ID %d subconnection ID %d received stage %d error %d"),
+ aContextId, aSubConnectionUniqueId, aStage, aError);
+ // Eliminate compiler warnings in release builds
+ aContextId = aContextId;
+ aSubConnectionUniqueId = aSubConnectionUniqueId;
+ aStage = aStage;
+ aError = aError;
+
+ // Drop all progress indications from lower NIFs on the floor because they'll just confuse NIFMAN.
+ // SpudMan generates its own progress notifications.
+ }
+
+/**
+Receives notifications from lower NIF to agent.
+
+@param aContextId Valid context ID of lower NIF
+@param aEvent Event type
+@param aInfo Additional information for event (ignored)
+@return KErrNone on success, or KErrNotSupported
+*/
+TInt CSpudMan::Notification(TContextId aContextId, TNifToAgentEventType aEvent, void* /*aInfo*/)
+ {
+ __FLOG_2(_L("CSpudMan::Notification context ID %d event ID %d"), aContextId, aEvent);
+ switch (aEvent)
+ {
+ case ENifToAgentEventTsyConfig:
+ {
+ // Return GPRS context structure to lower NIF
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+
+ iPdpFsmInterface.Get(aContextId, iTempGprsContext);
+ ref->NifLink()->Notification(EAgentToNifEventTsyConfig, reinterpret_cast<void*>(&iTempGprsContext));
+ return KErrNone;
+ }
+
+ case ENifToAgentEventTsyConnectionSpeed:
+ {
+ // Return connection speed to lower NIF
+ CSpudBinderRef* ref = NULL;
+ TRAPD(rc, ref = iBindMan->GetRefL(aContextId));
+ __ASSERT_ALWAYS(rc == KErrNone, Panic());
+ ASSERT(ref->IsBound());
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+ RPacketQoS::TQoSR5Negotiated params;
+#else
+ RPacketQoS::TQoSR99_R4Negotiated params;
+#endif
+// SYMBIAN_NETWORKING_UMTSR5
+
+ iPdpFsmInterface.Get(aContextId, params);
+ ref->NifLink()->Notification(EAgentToNifEventTsyConnectionSpeed,
+ reinterpret_cast<void*>(static_cast<TUint>(params.iMaxRate.iUplinkRate)));
+
+ return KErrNone;
+ }
+
+ default:
+ // Just ignore all the other notifications
+ __FLOG_0(_L("Ignoring notification"));
+ break;
+ }
+
+ return KErrNotSupported;
+ }
+
+/**
+Read a boolean field from the connection settings provider.
+Intercepts reads of CommPort and returns the correct value.
+
+@param aContextId Valid context ID of lower NIF
+@param aField The name of the field to read
+@param aValue On return, contains the value of the field read
+@return KErrNone, if successful; otherwise one of the standard Symbian OS error codes
+*/
+TInt CSpudMan::ReadInt(TContextId aContextId, const TDesC& aField, TUint32& aValue)
+ {
+
+ //This fix is needed to ensure that multiple PPP channels can be used for different PDP contexts.
+ //The returned value of ECommDbCdmaNaiMobileIp will cause PPP to skip external IP configuration (NCPIP).
+ if ( (TPtrC(CDMA_NAI_TYPE) == aField) && (iPrimaryContextId != aContextId) )
+ {
+ __FLOG_2(_L("CSpudMan::ReadInt context ID %d field = CDMA_NAI_TYPE - Therefore explicitly setting Value to ECommDbCdmaNaiMobileIp"),
+ aContextId, &aField);
+ __FLOG(_L("No call to AgentRef Will be make"));
+ // Lower NIF is requesting the NAI type
+ aValue = ECommDbCdmaNaiMobileIp;
+ return KErrNone;
+ }
+ __FLOG_2(_L("CSpudMan::ReadInt context ID %d field %S"), aContextId, &aField);
+ // Read CommDB normally
+ return Notify()->ReadInt(aField, aValue);
+ }
+
+/**
+Read a 8-bit descriptor field from the connection settings provider.
+Intercepts reads of CommPort and returns the value returned from ETel.
+
+@param aContextId Valid context ID of lower NIF
+@param aField The name of the field to read
+@param aValue On return, contains the value of the field read
+@return KErrNone, if successful; otherwise one of the standard Symbian OS error codes
+*/
+TInt CSpudMan::ReadDes(TContextId aContextId, const TDesC& aField, TDes8& aValue)
+ {
+ __FLOG_2(_L("CSpudMan::ReadDes context ID %d field %S"), aContextId, &aField);
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+1> columnName;
+ _LIT(KFormatText,"%s\\%s");
+
+ columnName.Format(KFormatText,MODEM_BEARER,MODEM_PORT_NAME);
+ if (columnName == aField)
+ {
+ // Lower NIF is requesting the CSY port name
+ // Use the TDes16 version of ReadDes to retrieve the data
+ TBuf16<KCommsDbSvrMaxFieldLength> data;
+ TInt rc(ReadDes(aContextId, aField, data));
+ aValue.Copy(data);
+ return rc;
+ }
+
+ columnName.Format(KFormatText,MODEM_BEARER,MODEM_CSY_NAME);
+ if (columnName == aField)
+ {
+ // Lower NIF is requesting the CSY file name
+ // Use the TDes16 version of ReadDes to retrieve the data
+ TBuf16<KCommsDbSvrMaxFieldLength> data;
+ TInt rc(ReadDes(aContextId, aField, data));
+ aValue.Copy(data);
+ return rc;
+ }
+
+ // Read CommDB normally
+ return Notify()->ReadDes(aField, aValue);
+ }
+
+/**
+Read a 16-bit descriptor field from the connection settings provider.
+Intercepts reads of CommPort and returns the value returned from ETel.
+
+@param aContextId Valid context ID of lower NIF
+@param aField The name of the field to read
+@param aValue On return, contains the value of the field read
+@return KErrNone, if successful; otherwise one of the standard Symbian OS error codes
+*/
+TInt CSpudMan::ReadDes(TContextId aContextId, const TDesC& aField, TDes16& aValue)
+ {
+ __FLOG_2(_L("CSpudMan::ReadDes context ID %d field %S"), aContextId, &aField);
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+1> columnName;
+ _LIT(KFormatText,"%s\\%s");
+
+ columnName.Format(KFormatText,MODEM_BEARER,MODEM_PORT_NAME);
+ if (columnName == aField)
+ {
+ // Lower NIF is requesting the CSY port name
+ iPdpFsmInterface.Get(aContextId, iTempDataChannelV2);
+ __FLOG_1(_L("Returning ETel port name %S"), &iTempDataChannelV2.iPort);
+ aValue.Copy(iTempDataChannelV2.iPort);
+ return KErrNone;
+ }
+
+ columnName.Format(KFormatText,MODEM_BEARER,MODEM_CSY_NAME);
+ if (columnName == aField)
+ {
+ // Lower NIF is requesting the CSY file name
+ iPdpFsmInterface.Get(aContextId, iTempDataChannelV2);
+ __FLOG_1(_L("Returning ETel CSY name %S"), &iTempDataChannelV2.iCsy);
+ aValue.Copy(iTempDataChannelV2.iCsy);
+ return KErrNone;
+ }
+
+ return Notify()->ReadDes(aField, aValue);
+ }
+
+/**
+Marks the binder to the lower NIF for asynchronous deletion
+
+@param aRef the binder
+@pre the binder must be bound the lower NIF.
+*/
+void CSpudMan::DisposeOfBinder(CSpudBinderRef* aRef)
+ {
+ ASSERT(aRef);
+ ASSERT(aRef->IsBound()); // We can only mark - sweep bound instances
+ ASSERT(aRef->State() != ESpudWaitBinderDelete);
+ aRef->SetState(ESpudWaitBinderDelete);
+ iBinderSweeperNotifierCb->Call(); // Queue deletion of marked binders & optional Nifman notification.
+ }
+
+/**
+Sweeps the set of lower NIF binding, deleting the marked ones. If no contexts remain after,
+notifies Nifman that SPUD has gone down.
+
+@param aContextId The ID of the context to delete
+@param aReason error code that is passed to Nifman
+*/
+void CSpudMan::SweepBindersAndNotify()
+ {
+ const TUint KNumContextsRemaining(BindMan()->SweepBinders());
+ if (0 == KNumContextsRemaining)
+ {
+ SetTerminateError(KErrAbort); // This is a last ditched effort to provide termination
+ // error code. We cannot determine in all cases what has caused SPUD to terminate.
+ // E.g. if several secondary contexts were deleted by the network, which of them caused SPUD termination?
+ // In such case we say that SPUD is shutting down due to internal event (namely, last context deletion).
+
+ __FLOG_3(_L("Last lower NIF has been deleted: Notifying Nifman with action EDisconnect[%d], progress KLinkLayerClosed[%d], reason[%d]"),
+ MNifIfNotify::EDisconnect, KLinkLayerClosed, iTerminateError);
+
+ // Once we've notified LinkLayerDown & IfProgress, we are finished. Nifman will delete us any moment after
+ // the RunL we are working from returns.
+ __FLOG(_L("SPUD is finished, and expects to be deleted by Nifman. Reason: last PDP context has gone down, possibly due to Stop on SPUD."));
+
+ // Tell Nifman clients that SPUD is finished.
+ Notify()->LinkLayerDown(iTerminateError, MNifIfNotify::EDisconnect);
+ Notify()->IfProgress(KLinkLayerClosed, iTerminateError);
+ }
+ else
+ {
+ __FLOG_1(_L("There are [%d] contexts remaining."), KNumContextsRemaining);
+ }
+ }
+
+void CSpudMan::SetupSipServerAddrRetrievalL(RPacketContext::TProtocolConfigOptionV2& aPco)
+ {
+ __FLOG(_L("CSpudMan::SetupSipServerAddrRetrieval - Requesting the P-CSCF address from the PCO buffer"));
+
+ TPtr8 pcoPtr(const_cast<TUint8*>(aPco.iMiscBuffer.Ptr()),aPco.iMiscBuffer.Length(),aPco.iMiscBuffer.MaxLength());
+
+ // attach TTlv to the buffer
+ TTlvStruct<RPacketContext::TPcoId,RPacketContext::TPcoItemDataLength> tlv(pcoPtr,0);
+ tlv.AppendItemL(RPacketContext::TPcoId(RPacketContext::EEtelPcktPCSCFAddressRequest),
+ TPtr8(static_cast<TUint8*>(NULL), 0, 0));
+ aPco.iMiscBuffer.SetLength(pcoPtr.Length());
+ }
+
+
+#ifdef SYMBIAN_NETWORKING_UMTSR5
+
+void CSpudMan::SetIMCNSignallingFlagPcoL(RPacketContext::TProtocolConfigOptionV2& aPco)
+/**
+Put the value for IMCN Signalling flag in the pco buffer if it is set in database
+
+@param PCO IE Buffer
+*/
+ {
+ TBool imcn=EFalse;
+ TBuf<2*KCommsDbSvrMaxColumnNameLength+2> columnName;
+ _LIT(KFormatText,"%s\\%s");
+ columnName.Format(KFormatText,QOS_UMTS_R99_AND_ON_TABLE,GPRS_QOS_IM_CN_SIGNALLING_INDICATOR);
+ TRAPD(ret, Notify()->ReadBool(columnName,imcn););
+ __FLOG_1(_L("CSpudMan::SetIMCNSignallingFlagPcoL - Requesting IMCN Signalling status from Database: error = %d"),ret);
+
+ if (imcn && ret==KErrNone )
+
+ {
+ TPtr8 pcoPtr(const_cast<TUint8*>(aPco.iMiscBuffer.Ptr()),aPco.iMiscBuffer.Length(),aPco.iMiscBuffer.MaxLength());
+ TTlvStruct<RPacketContext::TPcoId,RPacketContext::TPcoItemDataLength> tlv(pcoPtr,0);
+ tlv.AppendItemL(RPacketContext::TPcoId(RPacketContext::EEtelPcktIMCNMSSubsystemSignallingFlag ),
+ TPtr8(static_cast<TUint8*>(NULL), 0, 0));
+ aPco.iMiscBuffer.SetLength(pcoPtr.Length());
+ }
+ }
+TBool CSpudMan::GetIMCNSignallingFlagPcoL(RPacketContext::TProtocolConfigOptionV2& aPco)
+/**
+Get the value for IMCN Signalling from the network pco buffer
+
+@param PCO IE Buffer
+*/
+ {
+
+ __FLOG(_L("CSpudMan::GetIMCNSignallingFlagPcoL - Retrieving the IMCN signalling Flag from the PCO buffer"));
+
+ TPtr8 pcoPtr(const_cast<TUint8*>(aPco.iMiscBuffer.Ptr()),aPco.iMiscBuffer.Length(),aPco.iMiscBuffer.MaxLength());
+ TTlvStruct<RPacketContext::TPcoId,RPacketContext::TPcoItemDataLength> tlv(pcoPtr,0);
+ tlv.ResetCursorPos();
+
+ TInt err = tlv.NextItemL(RPacketContext::EEtelPcktIMCNNetworkSubsystemSignallingFlag,pcoPtr);
+ return (err == KErrNone);
+
+ }
+
+#endif // SYMBIAN_NETWORKING_UMTSR5
+
+
+void CSpudMan::SetSipServerAddrL(const RPacketContext::TProtocolConfigOptionV2& aPco)
+ {
+ __FLOG(_L("CSpudMan::SetSipServerAddr - Retrieving the P-CSCF address from the PCO buffer"));
+ iSipServerAddr.Reset(); //Free all existing entries
+ TPtr8 pcoPtr(const_cast<TUint8*>(aPco.iMiscBuffer.Ptr()),aPco.iMiscBuffer.Length(),aPco.iMiscBuffer.MaxLength());
+ TTlvStruct<RPacketContext::TPcoId,RPacketContext::TPcoItemDataLength>
+ tlv(pcoPtr,0);
+
+ tlv.ResetCursorPos();
+ TIp6Addr addr;
+ TPtr8 addrPtr(NULL, 0);
+ TPckg<TIp6Addr> addrPckg(addr);
+
+ while (tlv.NextItemL(RPacketContext::EEtelPcktPCSCFAddress,addrPtr) == KErrNone)
+ {
+ TInetAddr inetAddr;
+ addrPckg.Copy(addrPtr);
+ inetAddr.SetAddress(addr);
+ TBuf<KMaxInetAddrPrintSize> testbuf;
+ inetAddr.Output(testbuf);
+ __FLOG_1(_L("CSpudMan::SetSipServerAddr - P-CSCF address ---> %S"),&testbuf);
+ if (testbuf.Length()) //ie the address is invalid
+ {
+ iSipServerAddr.AppendL(inetAddr);
+ }
+ }
+ }
+
+void CSpudMan::SetContextTerminationErrorAndStop(TContextId aContextId, TInt aErrorCode)
+ {
+ __FLOG_2(_L("SetContextTerminateError on StatusEvent: aContextId[%d], aErrorCode[%d]"),
+ aContextId, aErrorCode);
+
+ // If there is no error then simply return
+ if (KErrNone == aErrorCode) return;
+
+ // If secondary context, store error code in individual contexts reference
+ // and stop the secondary context
+ if(aContextId != iPrimaryContextId)
+ {
+ StopContext(aContextId, aErrorCode, MNifIfNotify::EDisconnect);
+ }
+ else
+ {
+ // This is a problem with the Primary context so stop and disconnect
+ // Now save the termination error code if not already set
+ if (iTerminateError == KErrNone)
+ {
+ iTerminateError = aErrorCode;
+ }
+
+ // This may be the first ETel error code so save it
+ if (iETelTerminateError == KErrNone)
+ {
+ iETelTerminateError = aErrorCode;
+ }
+
+ // Primary context has a problem so disconnect
+ Stop(aErrorCode, MNifIfNotify::EDisconnect);
+ }
+ }
+
+//*************************************************************************
+// CLowerNifBinderDeletionCb
+// Asynchronous deletion of CSpudBinderRefs and notification to Nifman
+//*************************************************************************
+// Use Spudman's logging.
+// Because we are owned by Spudman, we don't have to worry about the logger being deleted.
+#ifdef __FLOG_ACTIVE
+#define BINDER_SWEEPER_LOG(x) iSpudMan.x
+#else
+#define BINDER_SWEEPER_LOG(x)
+#endif
+
+// Construct a High-Priority AO that calls into the SPUD
+// This will work with any priority AO, but because we are releasing memory and
+// potentially notifying Nifman, we want to run ASAP.
+CBinderSweeperNotifierCb::CBinderSweeperNotifierCb(CSpudMan& aSpudMan)
+ :
+ CAsyncOneShot(CActive::EPriorityHigh),
+ iSpudMan(aSpudMan)
+ {
+ }
+
+// Queues the deletion callback
+void CBinderSweeperNotifierCb::Call()
+ {
+ if(!IsActive()) // We can be called again before we had a chance to run.
+ {
+ BINDER_SWEEPER_LOG(__FLOG(_L("CBinderSweeperNotifierCb: Queueing async deletion of dead lower NIF bindings."));)
+ CAsyncOneShot::Call();
+ return;
+ }
+ BINDER_SWEEPER_LOG(__FLOG(_L("CBinderSweeperNotifierCb: Async deletion of dead lower NIF bindings is already queued."));)
+ }
+
+
+// Called by ActiveScheduler.
+//
+// If the lower NIF deletion is attempted after Nifman deletes the SPUD
+// (from CNifAgentRef::DisconnectionComplete), the lower NIF deletion AO is corrupted in the
+// ActiveScheduler, causing ESock thread to crash. To prevent this, lower NIFs are deleted
+// before signalling LinkLayerDown to Nifman. When a lower NIF signals LinkLayerDown, a callback into Spudman is queued.
+// This callback deletes the lower NIFs that are eligible for deletion, and notifies Nifman, if necessary. */
+void CBinderSweeperNotifierCb::RunL()
+ {
+ iSpudMan.SweepBindersAndNotify();
+ }
+