telephonyprotocols/secondarypdpcontextumtsdriver/spudman/src/spudman.cpp
changeset 0 3553901f7fa8
--- /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();
+	}
+