telephonyprotocols/gprsumtsqosprt/src/context.cpp
branchopencode
changeset 24 6638e7f4bd8f
parent 0 3553901f7fa8
--- a/telephonyprotocols/gprsumtsqosprt/src/context.cpp	Mon May 03 13:37:20 2010 +0300
+++ b/telephonyprotocols/gprsumtsqosprt/src/context.cpp	Thu May 06 15:10:38 2010 +0100
@@ -1,845 +1,845 @@
-// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
-// All rights reserved.
-// This component and the accompanying materials are made available
-// under the terms of "Eclipse Public License v1.0"
-// which accompanies this distribution, and is available
-// at the URL "http://www.eclipse.org/legal/epl-v10.html".
-//
-// Initial Contributors:
-// Nokia Corporation - initial contribution.
-//
-// Contributors:
-//
-// Description:
-//
-
-#include <in_iface.h>
-
-#include "guqos.h"
-#include "iface.h"
-#include "tc.h"
-#include "parameters.h"
-#include "guqos_err.h"
-#include "async_request.h"
-#include "context.h"
-#include "guqos_log.h"
-
-#ifdef _LOG
-// *****************
-// Logging utilities
-// *****************
-
-// Return count of contiguous most significant 1-bits in TUint32
-static TInt MaskLength(TUint32 aAddr)
-	{
-	TInt count = 0;
-	// obviously, this is "brute force" counting
-	while (aAddr & 0x80000000)
-		{
-		count++;
-		aAddr <<= 1;
-		}
-	return count;
-	}
-
-//Return count of contiguous most significant 1-bits in IPv6 address.
-static TInt MaskLength(const TIp6Addr &aAddr)
-	{
-	TInt count = 0;
-	for (TUint i = 0; i < sizeof(aAddr.u.iAddr8) / sizeof(aAddr.u.iAddr8[0]); ++i)
-		if (aAddr.u.iAddr8[i] == 0xFF)
-			count += 8;
-		else
-			{
-			count += MaskLength(aAddr.u.iAddr8[i] << 24);
-			break;
-			}
-	return count;
-	}
-
-// A buffer to contain textual format of internet address
-class TAddressBuf : public TBuf<70>
-	{
-public:
-	TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort = 0);
-	};
-
-TAddressBuf::TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort)
-	{
-	TInetAddr addr(aAddr, 0);
-	addr.Output(*this);
-	if (aMask != 128)
-		{
-		if (aAddr.IsV4Mapped())
-			aMask -= 96;
-		_LIT(KFormat1, "/%u");
-		AppendFormat(KFormat1, aMask);
-		}
-	if (aPort)
-		{
-		_LIT(KFormat2, "#%u");
-		AppendFormat(KFormat2, (TInt)aPort);
-		}
-	}
-
-// Log packet filter address selector
-// Make this not "static", so that it can be used by other modules too...
-void LogPacketFilter(const TPacketFilter& aFilter)
-	{
-	TIp6Addr srcAddr;
-	Mem::Copy(&srcAddr,aFilter.iSrcAddr, sizeof(srcAddr));
-	TIp6Addr mask;
-	Mem::Copy(&mask,aFilter.iSrcAddrSubnetMask,sizeof(mask));
-	TAddressBuf addr(
-		srcAddr, 
-		MaskLength(mask),
-		aFilter.iSrcPortMin);
-	Log::Printf(_L("\t\t%u(%u) %S-%u dst#%u-%u SPI=%u TOS=%u FL=%u"),
-		aFilter.iId, aFilter.iEvaluationPrecedenceIndex,
-		&addr, (TInt)aFilter.iSrcPortMax,
-		(TInt)aFilter.iDestPortMin, (TInt)aFilter.iDestPortMax,
-		(TInt)aFilter.iIPSecSPI,
-		(TInt)aFilter.iTOSorTrafficClass,
-		(TInt)aFilter.iFlowLabel);
-	}
-#endif
-
-//	XPdpContextTimeoutLinkage
-//	************************
-//	Glue to bind timeout callback from the timeout manager into Timeout() call
-//	on the CPdpContext
-//
-//	*NOTE*
-//		This kludgery is all static and compile time, and only used in the constructor
-//		of CPdpContext.
-//
-
-// This ungainly manoevure is forced on us because the offset is not evaluated early enough by GCC3.4 to be
-// passed as a template parameter
-#if defined(__X86GCC__) || defined(__GCCE__)
-#define KPdpContextTimeoutOffset 716
-__ASSERT_COMPILE(KPdpContextTimeoutOffset == _FOFF(CPdpContext, iTimeout));
-#else
-#define KPdpContextTimeoutOffset _FOFF(CPdpContext, iTimeout)
-#endif
-
-class XPdpContextTimeoutLinkage : public TimeoutLinkage<CPdpContext, KPdpContextTimeoutOffset>
-	{
-public:
-	static void Timeout(RTimeout &aLink, const TTime & /*aNow*/, TAny * /*aPtr*/)
-		{
-		Object(aLink)->Timeout();
-		}
-	};
-
-
-CPdpContext* CPdpContext::NewL(CNif& aNifItem, const TContextType& aType, TUint8 aContextId)
-	{
-	CPdpContext* context = new (ELeave) CPdpContext(aNifItem, aType, aContextId);
-	CleanupStack::PushL(context);
-	context->ConstructL();
-	CleanupStack::Pop();
-	return context;
-	}
-
-CPdpContext::CPdpContext(CNif& aNifItem, TContextType aType, TUint8 aContextId) : 
-	iContextId(aContextId),
-	iNifItem(aNifItem),
-	iTimeout(XPdpContextTimeoutLinkage::Timeout)
-	{
-	iContextType = aType;
-	iContextStatus = RPacketContext::EStatusUnknown;
-	iFlows.SetOffset(_FOFF(CFlowData, iLink));
-	//iTrafficClass = -1;
-	}
-
-
-void CPdpContext::ConstructL()
-	{
-	}
-
-CPdpContext::~CPdpContext()
-	{
-	LOG(Log::Printf(_L("CPdpContext::~CPdpContext [ContextId=%d]"),iContextId));
-	while (!iFlows.IsEmpty())
-		{
-		// Any flows still attached to the PDP Context instance when
-		// we are in destructor, are deleted. If automatic move of
-		// flows to another context is the desired, it must be taken
-		// care before deleting the context (this destructor is also
-		// called from CNif destructor, and we cannot reference
-		// any other contexts on the CNif)
-		CFlowData* flow = iFlows.First();
-		// Deleting flow removes it from the list,
-		// and eventually the iFlows will become EMPTY!
-		delete flow;
-		}
-	iNifItem.CancelPendingRequest(this);
-	iTimeout.Cancel();	// ..if any active
-	}
-
-
-void CPdpContext::Timeout()
-	{
-	LOG(Log::Printf(_L("")));
-	if (Flows().IsEmpty())
-		{
-		LOG(Log::Printf(_L("CPdpContext::Timeout -- no flows, delete context")));
-		Delete();
-		Nif().DeletePdpContext(this);
-		}
-	else
-		{
-		LOG(Log::Printf(_L("CPdpContext::Timeout -- flows have re-appeared, keep context")));
-		// Some flows have come back, context is not
-		// deleted after all. But, because TFT's are
-		// not updated when the last flow leaves the
-		// context and this callback is scheduled, we
-		// now may have garbage TFT's left on the
-		// context. To cleanup the situation, schedule
-		// a CClose request.
-		CClose* request = CClose::New(*this);
-		if (request)
-			Nif().AddRequest(*request);
-		// If allocating request object fails, just
-		// ignore the issue of extra TFT's. It will
-		// eventually fix itself next time some flow
-		// leaves the context or context is deleted.
-		}
-	}
-	
-void CPdpContext::NotifyBlockingState(TUint aOldBlocking)
-	{
-	const TUint blocked = IsFlowBlocked();
-	if (blocked == aOldBlocking)
-		{
-		LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking unchanged (%d)"), ContextId(), ChannelId(), blocked));
-		return;		// No Change, no need to notify anyone.
-		}
-	LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking changed to (%d)"), ContextId(), ChannelId(), blocked));
-
-	MEventInterface *notifier = Nif().Module().QoSEvent();
-	if (!notifier)
-		{
-		LOG(Log::Printf(_L("\tOops -- QoS has not setup the MEventInterface")));
-		return;
-		}
-	
-	// Set all flows associated with this context into blocked or unblocked state
-	TDblFlowIter iter(iFlows);
-	CFlowData *flow;
-	//?? Potentially dangerout iterator, becuase BlockFlow upcall
-	//?? may call back and modify the list!
-	while ((flow = iter++) != NULL)
-		{
-		// Throw away "const". The MEventInterface is misdeclared to
-		// use non-const reference parameter, when const reference
-		// would be the correct way...
-		if (blocked)
-			notifier->BlockFlow((CFlowContext &)flow->FlowContext());
-		else
-			notifier->UnBlockFlow((CFlowContext &)flow->FlowContext());
-		}
-	}
-
-// Block flows on this context, no packets are sent to these flows after this.
-void CPdpContext::Block()
-	{
-	const TUint blocked = IsFlowBlocked(); // get old state
-	iBlocked = ETrue;
-	NotifyBlockingState(blocked);
-	}
-
-
-// Unblock flows on this context. Re-enable packet sending for these flows.
-void CPdpContext::UnBlock()
-	{
-	LOG(Log::Printf(_L("\tCPdpContext::UnBlock()")));
-	const TUint blocked = IsFlowBlocked(); // get old state
-	iBlocked = EFalse;
-	NotifyBlockingState(blocked);
-	}
-
-
-// Check if CFlowContext matches with packet filter attributes
-TBool CPdpContext::MatchPacketFilter(const TPacketFilter& aFlow, const TPacketFilter& aFilter) const
-	{
-	if (Mem::Compare(aFlow.iSrcAddr, 16, aFilter.iSrcAddr, 16) != 0)
-		return EFalse;
-	
-	if (Mem::Compare(aFlow.iSrcAddrSubnetMask, 16, aFilter.iSrcAddrSubnetMask, 16) != 0)
-		return EFalse;
-
-	if (aFlow.iProtocolNumberOrNextHeader != (TUint)aFilter.iProtocolNumberOrNextHeader)
-		return EFalse;
-
-	if (aFlow.iDestPortMin < aFilter.iDestPortMin || aFlow.iDestPortMax > aFilter.iDestPortMax)
-		return EFalse;
-
-	if (aFlow.iSrcPortMin < aFilter.iSrcPortMin || aFlow.iSrcPortMax > aFilter.iSrcPortMax)
-		return EFalse;
-
-	if (aFlow.iFlowLabel != aFilter.iFlowLabel)
-		return EFalse;
-
-	if (aFlow.iTOSorTrafficClass != aFilter.iTOSorTrafficClass)
-		return EFalse;
-
-	return ETrue;
-	}
-
-
-// Return QoS ranking according to TS 23.107
-//
-// (only used for turning some secondary context into new default/primary context)
-TInt CPdpContext::GetQoSRanking()
-	{
-	TInt ranking = 6;
-	switch (TrafficClass())
-		{
-	case RPacketQoS::ETrafficClassConversational:
-		ranking = 2;
-		break;
-
-	case RPacketQoS::ETrafficClassStreaming:
-		ranking = 3;
-		break;
-
-	case RPacketQoS::ETrafficClassInteractive:
-		{
-		const TInt priority = iNegotiated.iTrafficHandlingPriority;
-		if (priority == 1)
-			ranking = 1;
-		else if (priority == 2)
-			ranking = 4;
-		else
-			ranking = 5;
-		}
-		break;
-
-	default:
-	case RPacketQoS::ETrafficClassBackground:
-		ranking = 6;
-		break;
-		}
-	return ranking;
-	}
-
-
-TInt CPdpContext::FindPacketFilterId()
-	{
-	// Valid filter id's are from 1 - 8, find one which
-	// is not yet in use: First find out used id's into mask
-	
-	// Note: 3GPP specification uses 0-7 as the filter id.
-	// The etelpckt.h range [1-8] is adjusted to [0-7] at
-	// lower layers.
-	TUint mask = 0;
-	for (TInt i = iNumFilters; --i >= 0;)
-		{
-		const TPacketFilter& f = iFilters[i];
-		// Note silly naked constants, but there are no symbols for these?
-		if (f.iId > 0 && f.iId < 9)
-			{
-			mask |= (1 << f.iId);
-			}
-		}
-	// Find an empty id slot.
-	for (TInt j = 0; ++j < 9; )
-		{
-		if ((mask & (1 << j)) == 0)
-			return j;
-		}
-	//??What error is supposed to be returned?
-	//return KErrNotFound;
-	return KErrOverflow;
-	}
-
-
-// Add packet filter to TFT, return error or number of filters added
-TInt CPdpContext::AddPacketFilter(CFlowData& aFlow, TTFTInfo& aTft)
-	{
-	TInt ret = KErrNone;
-
-	LOG(Log::Printf(_L("\t\tCPdpContext::AddPacketFilter")));
-
-
-	TPacketFilter& flow_filter = aFlow.PacketFilter();
-
-	for (TInt i = iNumFilters; --i >= 0; )
-		if (MatchPacketFilter(flow_filter, iFilters[i]))
-			{
-			// The flow is already covered by an existing filter,
-			// no need to add anything, return 0.
-			return 0;
-			}
-
-	// Update flow filter with dynamic fields.
-	// This only marks the Id and evaluation precedende as reserved. It
-	// does not add the filter to the context object (iNumFilters is not
-	// incremented).
-	// It is assumed that once NIF completes the request, it will return
-	// the complete state of the context, including all currently active
-	// filters. At that point GUQOS state is recomputed to match the
-	// actual reality.
-	
-	// Not touching the iNumFilters works for now, because there is at
-	// most one negotiation open on any interface, and because negoatiation
-	// currently adds at most one new filter.
-	// If above changes, and some negotiation would need to add multiple
-	// filters, then additional logic needs to remember the to-be-added
-	// filters and assigned ids.
-	ret = FindPacketFilterId();
-	if (ret < 0)
-		{
-		// All filter slots already used!
-		LOG(Log::Printf(_L("\t\tNo PacketFilterId -- all used")));
-		return ret;
-		}
-	flow_filter.iId = ret;
-	LOG(Log::Printf(_L("\t\tPacketFilterId: %d"), flow_filter.iId));
-
-	flow_filter.iEvaluationPrecedenceIndex = Nif().FindEvaluationPrecedence();
-	LOG(Log::Printf(_L("\t\tEvaluationPrecedenceIndex: %d"), flow_filter.iEvaluationPrecedenceIndex));
-	LOG(LogPacketFilter(flow_filter));
-	ret = aTft.AddPacketFilter(flow_filter);
-	return ret < 0 ? ret : 1;	// if OK, 1 filter added
-	}
-
-
-// Remove packet filter(s) from the TFT, return error or number of filters to remove
-TInt CPdpContext::RemovePacketFilter(TTFTInfo& aTft, const CFlowData* aFlow)
-	/**
-	* Find the set of unused filters.
-	*
-	* Scan all currently attached flows and match them against current set of
-	* filters. Return the list of filters that didn't match any flows.
-	*
-	* One optional flow can be treated as non-attached (even if it appears
-	* in the attached list) and excluded matching test. This allows caller
-	* to leave a flow in the attached list for later removal.
-	*
-	* @retval aTft The list of unused filters
-	* @par	aFlow Optional flow to exclude from the matching.
-	*
-	* @return Negative error code (< 0), or number of unsed filters (>= 0),
-	* which were added into.
-	*/
-	{
-	// Because filters can match multiple flows (if someone actually starts
-	// using the netmask and port ranges), this must test whether any of the
-	// current filters become unnecessary when the indicated flow has been
-	// removed.
-
-	LOG(Log::Printf(_L("\t\tCPdpContext::RemovePacketFilter")));
-	TUint mask = 0;
-
-	// If the context is current designated "primary", then all filters
-	// must be removed (there can be filters only if this primary is
-	// a secondary context that has been assigned as new default).
-	if (!IsPrimary())
-		{
-		TDblFlowIter iter(iFlows);
-		CFlowData *flow;
-		while ((flow = iter++) != NULL)
-			{
-			if (flow == aFlow)
-				continue;	// skip the flow being removed.
-			const TPacketFilter& flow_filter = flow->PacketFilter();
-			for (TInt i = iNumFilters; --i >= 0; )
-				if (MatchPacketFilter(flow_filter, iFilters[i]))
-					{
-					mask |= (1 << i);	// Mark this filter as used.
-					break;				// No need to test other filters for this flow.
-					}
-			}
-		}
-	// Schedule removal of all filters that were not used.
-	TInt count = 0;
-	for (TInt j = 0; j < iNumFilters; ++j, mask >>= 1)
-		{
-		if ((mask & 1) == 0)
-			{
-			// This filter is not needed anymore
-			LOG(LogPacketFilter(iFilters[j]));
-			TInt ret = aTft.AddPacketFilter(iFilters[j]);
-			if (ret != KErrNone)
-				return ret;
-			++count;
-			}
-		}
-	return count;
-	}
-
-//
-// Set QoS parameters for a Pdp context.
-// Note: Change is not signaled to network until Activate/ModifyActive is called.
-//
-TInt CPdpContext::SetQoS(const TQoSParameters& aGeneric, const TQoSRequested& aUmts)
-	{
-	LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d]"),iContextId));
-
-	TContextParameters& parameters(Nif().ContextParameters());
-	
-	TQoSRequested requested;
-	ParameterMapper::MapGenericToRel99(aGeneric, requested);
-
-	// If adapt flag set, minimum params are set to unspecified
-	if (aGeneric.AdaptMode())
-		requested.ClearMinimumParameters();
-
-	ParameterMapper::CombineOverride(aUmts, requested);
-
-	parameters.iContextConfig.SetUMTSQoSReq(requested);
-	parameters.iContextConfig.SetPdpCompression(requested.iHeaderCompression);
-	parameters.iContextInfo.iContextId = iContextId;
-	parameters.iContextType = iContextType;
-	TPckg<TContextParameters> options(parameters);
-	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options);
-	return ret == KErrNone ? parameters.iReasonCode : ret;
-	}
-
-
-// Set QoS parameters for a Pdp context from defaults
-// Note: Change is not signaled to network until Activate/ModifyActive is called.
-TInt CPdpContext::SetQoS()
-	{
-	LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d ChannelId=%d]"), iContextId, iChannelId));
-
-	TContextParameters& parameters(Nif().ContextParameters());
-	TQoSRequested policy;
-	Nif().Module().GetDefaultParameters(policy, Nif().IapId());
-	parameters.iContextConfig.SetUMTSQoSReq(policy);
-	parameters.iContextConfig.SetPdpCompression(policy.iHeaderCompression);
-	parameters.iContextInfo.iContextId = iContextId;
-	parameters.iContextType = iContextType;
-	TPckg<TContextParameters> options(parameters);
-	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options);
-	return ret == KErrNone ? parameters.iReasonCode : ret;
-	}
-
-
-// SetQoS response
-void CPdpContext::SetQoSReply(CRequestBase* aRequest, const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::SetQoSReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
-
-	// Note: Because Run may complete the request, and resulting upcall
-	// to QoS may delete anything within the GUQOS, don't assume "this"
-	// exists after Run! Any actions on this must be done before the
-	// Run call.
-	if (aRequest)
-		aRequest->Run(EPendingSetQoS, this, aParams);
-	}
-
-TInt CPdpContext::ModifyTft(const TTFTOperationCode& aTFTOperationCode, const TTFTInfo& aTft)
-	{
-	LOG(Log::Printf(_L("\t\tModifyTFT on PDP Context [ContextId=%d]"),iContextId));
-
-	TPckg<TContextParameters> options(Nif().ContextParameters());
-	options().iContextConfig.SetTFTInfo(aTft);
-	options().iContextInfo.iContextId = iContextId;
-	options().iContextType = iContextType;
-	options().iTFTOperationCode = aTFTOperationCode;
-
-	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextTFTModify, options);
-	return ret == KErrNone ? options().iReasonCode : ret;
-	}
-
-void CPdpContext::ModifyTftReply(CRequestBase* aRequest, const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::ModifyTftReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
-	if (!aRequest)
-		return;
-
-	// Translate operation code into "request code"...
-	TRequest code = EPendingAny;;
-	switch(aParams.iTFTOperationCode)
-		{
-	case KAddFilters:
-		code = EPendingPacketFilterAdd;
-		break;
-
-	case KRemoveFilters:
-		code = EPendingPacketFilterRemove;
-		break;
-
-	case KDeleteTFT:
-		code = EPendingTFTRemove;
-		break;
-
-	case KAddSblpParameter:
-		code = EPendingSblpParameterAdd;
-		break;
-			
-	case KRemoveSblpParameter:
-		code = EPendingSblpParameterRemove;
-		break;
-
-	default:
-		// Should not happen, but if it does, let the request state
-		// machine handle the problem (code is now EPendingAny!)
-		break;
-		}
-	// Note: Because Run may complete the request, and resulting upcall
-	// to QoS may delete anything within the GUQOS, don't assume "this"
-	// exists after Run! Any actions on this must be done before the
-	// Run call.
-	aRequest->Run(code, this, aParams);
-	}
-
-
-// Activate context
-TInt CPdpContext::Activate()
-	{
-	LOG(Log::Printf(_L("\t\tCPdpContext::Activate PDP Context [ContextId=%d]"),iContextId));
-
-	TContextParameters& parameters(Nif().ContextParameters());
-
-	// Activate only needs the context id.
-	parameters.iContextInfo.iContextId = iContextId;
-	//?? Does it need the "context type"?
-	parameters.iContextType = iContextType;
-	TPckg<TContextParameters> options(parameters);
-	const TInt ret =  Nif().Interface().Control(KSOLInterface, KContextActivate, options);
-	return ret == KErrNone ? parameters.iReasonCode : ret;
-	}
-
-// Activate context response
-void CPdpContext::ActivateReply(CRequestBase* aRequest, const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::ActivateReply() [ContextId=%d]"),iContextId));
-
-	Update(aParams);
-	// Must be done before Run (see below)!
-	if (ContextActive())
-		UnBlock();
-	// Note: Because Run may complete the request, and resulting upcall
-	// to QoS may delete anything within the GUQOS, don't assume "this"
-	// exists after Run! Any actions on this must be done before the
-	// Run call.
-	if (aRequest)
-		{
-		aRequest->Run(EPendingActivate, this, aParams);
-		}
-	}
-
-// Modify active Pdp context
-TInt CPdpContext::ModifyActive()
-	{
-	LOG(Log::Printf(_L("\t\tCPdpContext::ModifyActive [ContextId=%d]"),iContextId));
-
-	TContextParameters& parameters(Nif().ContextParameters());
-	parameters.iContextInfo.iContextId = iContextId;
-	TPckg<TContextParameters> options(parameters);
-
-	const TInt ret(Nif().Interface().Control(KSOLInterface, KContextModifyActive, options));
-	return ret == KErrNone ? parameters.iReasonCode : ret;
-	}
-
-void CPdpContext::ModifyActiveReply(CRequestBase* aRequest, const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::ModifyActiveReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
-	Update(aParams);
-
-	// Must be done before Run (see below)!
-	if (ContextActive())
-		UnBlock();
-	// Note: Because Run may complete the request, and resulting upcall
-	// to QoS may delete anything within the GUQOS, don't assume "this"
-	// exists after Run! Any actions on this must be done before the
-	// Run call.
-	if (aRequest)
-		aRequest->Run(EPendingModifyActive, this, aParams);
-	}
-
-// QoS parameters have changed
-void CPdpContext::ParametersChangedEvent(const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::ParametersChangedEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
-	Update(aParams);
-	// Notify applications about QoS change
-	GenerateEvent(KPfqosEventAdapt, aParams);
-	}
-
-void CPdpContext::DeleteEvent(const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("CPdpContext::DeleteEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
-	GenerateEvent(KPfqosEventFailure, aParams);
-	}
-
-// delete Pdp context
-TInt CPdpContext::Delete()
-	{
-	if (!IsPrimary())
-		{
-		LOG(Log::Printf(_L("\t\tCPdpContext::Delete [ContextId=%d]"),iContextId));
-
-		TContextParameters& parameters(Nif().ContextParameters());
-		parameters.iContextInfo.iContextId = iContextId;
-		TPckg<TContextParameters> options(parameters);
-		Nif().Interface().Control(KSOLInterface, KContextDelete, options);
-		}
-	return KErrNone;
-	}
-
-
-void CPdpContext::FlowAttached()
-	{
-	++iRefs;	
-	}
-
-void CPdpContext::FlowDetached()
-	{
-	--iRefs;
-	if (!IsPrimary() && iFlows.IsEmpty())
-		{
-		ASSERT(iRefs == 0);
-		iTimeout.Set(Nif().Module().TimeoutManager(), Nif().Module().Options().iTimeout);
-		}
-	}
-
-void CPdpContext::GenerateEvent(TUint aEventType, const TContextParameters& aParams)
-	{
-	// Generate event for channels
-	MEventInterface *notifier = Nif().Module().QoSEvent();
-	if (!notifier)
-		return;	// Nobody to notify!
-
-	RExtensionData extension;
-	TInt ret = extension.CreateExtension(aParams.iContextConfig, aParams.iReasonCode);
-	// if cannot generate full return information, try with plain reason code
-	if (ret != KErrNone)
-		(void)extension.SetErrorCode(aParams.iReasonCode);
-	
-	if (ChannelId())
-		{
-		// The PDP context represents a channel, one event for all joined flows
-		notifier->NotifyEvent(ChannelId(), aEventType, NULL, extension);
-		}
-	else
-		{
-		// Generate event for each flow
-		TDblFlowIter iter(iFlows);
-		CFlowData *flow;
-		while ((flow = iter++) != NULL)
-			{
-			// Throw away "const". The MEventInterface is misdeclared to
-			// use non-const reference parameter, when const reference
-			// would be the correct way...
-			notifier->NotifyEvent((CFlowContext &)flow->FlowContext(), aEventType, NULL, extension);
-			}
-		}
-	extension.Close();
-	}
-
-
-void CPdpContext::SetContextStatus(const RPacketContext::TContextStatus& aStatus)
-	{
-#ifdef _LOG
-	TBuf<40> statusBefore;
-
-	switch(iContextStatus)
-		{
-		case RPacketContext::EStatusUnknown:		statusBefore.Append(_L("EStatusUnknown"));		break;
-		case RPacketContext::EStatusInactive:		statusBefore.Append(_L("EStatusInactive"));		break;
-		case RPacketContext::EStatusActivating:		statusBefore.Append(_L("EStatusActivating"));	break;
-		case RPacketContext::EStatusActive:			statusBefore.Append(_L("EStatusActive"));		break;
-		case RPacketContext::EStatusDeactivating:	statusBefore.Append(_L("EStatusDeactivating"));	break;
-		case RPacketContext::EStatusSuspended:		statusBefore.Append(_L("EStatusSuspended"));	break;
-		case RPacketContext::EStatusDeleted:		statusBefore.Append(_L("EStatusDeleted"));		break;
-		default:									statusBefore.Append(_L("error"));				break;
-		}
-
-	TBuf<40> statusAfter;
-
-	switch(aStatus)
-		{
-		case RPacketContext::EStatusUnknown:		statusAfter.Append(_L("EStatusUnknown"));		break;
-		case RPacketContext::EStatusInactive:		statusAfter.Append(_L("EStatusInactive"));		break;
-		case RPacketContext::EStatusActivating:		statusAfter.Append(_L("EStatusActivating"));	break;
-		case RPacketContext::EStatusActive:			statusAfter.Append(_L("EStatusActive"));		break;
-		case RPacketContext::EStatusDeactivating:	statusAfter.Append(_L("EStatusDeactivating"));	break;
-		case RPacketContext::EStatusSuspended:		statusAfter.Append(_L("EStatusSuspended"));		break;
-		case RPacketContext::EStatusDeleted:		statusAfter.Append(_L("EStatusDeleted"));		break;
-		default:									statusAfter.Append(_L("error"));				break;
-		}
-
-	LOG(Log::Printf(_L("\tCPdpContext::SetContextStatus, iContextStatus before: {%S}, after: {%S}"), &statusBefore, &statusAfter));
-#endif
-
-	const TUint blocked = IsFlowBlocked();
-	iContextStatus = aStatus;
-	NotifyBlockingState(blocked);
-	}
-
-void CPdpContext::Update(const TContextParameters& aParams)
-	{
-	LOG(Log::Printf(_L("\tUpdate Context id = %d (channel=%d)"), ContextId(), ChannelId()));
-	// Save some basic negotiated values to the context instance.
-	aParams.iContextConfig.GetUMTSQoSNeg(iNegotiated);
-
-	// *NOTE* *ASSUMED*
-	// This function is called on completion of MofifyActive/Activate and
-	// in some other cases. Assume that the TContextParameters contains the
-	// current state of the context as seen by lower layers. The iReasonCode
-	// only indicates that the indicated operation failed or succeeded.
-	// The current state is provided even if iReasonCode != KErrNone.
-
-	LOG(Log::Printf(_L("\tCurrent TFT from NIF to PDP ContextId=%d"), ContextId()));
-	//?? The specification of TTFTInfo class is plain idiotic. There is no way to
-	//?? scan through filters with constant object. There is no way to get a
-	//?? const ref to filter inside TFTInfo, instead all scanning always requires
-	//?? inconvenient copying of the element (in addition to the fact that,
-	//?? you often have to copy the whole TTFTInfo structure to local store
-	//?? for a "modifiable copy" (which really should not be needed!)
-	
-	// Avoid some of the problems by *not* keeping TTFTInfo in CPdpContext, and
-	// maintain own simple array of TPacketFilters instead, which can at least
-	// be looked without needing to copy the elements each time...
-	TTFTInfo& tft = ((RContextConfig&)aParams.iContextConfig).TFTInfo();
-	tft.SetToFirst();
-	iNumFilters = 0;
-	while (iNumFilters < KMaxPacketFilters && tft.NextPacketFilter(iFilters[iNumFilters]) == KErrNone)
-		{
-		LOG(LogPacketFilter(iFilters[iNumFilters]));
-		++iNumFilters;
-		}
-	Nif().RecomputeEvaluationPrecedences();
-
-#ifdef _LOG
-	RPacketContext::CTFTMediaAuthorizationV3 *sblpParams;
-	TRAPD(err, sblpParams = RPacketContext::CTFTMediaAuthorizationV3::NewL());
-	if (err != KErrNone)
-		return;	// Blah!!
-	if (tft.GetSblpToken(*sblpParams) == KErrNone)
-		{
-		TBuf<KMaxFQDNLength> mat;
-		mat.Copy(sblpParams->iAuthorizationToken);
-		//coverity[leave_without_push]
-		Log::Printf(_L("\t\tMedia authorization: '%S'"),&mat);
-		for( TInt i = 0; i < sblpParams->iFlowIds.Count(); i++ )
-			{
-			//coverity[leave_without_push]
-			Log::Printf(_L("\t\tFlowId %d.  Media <%d> Flow <%d>"),
-				i,
-				sblpParams->iFlowIds[i].iMediaComponentNumber,
-				sblpParams->iFlowIds[i].iIPFlowNumber);
-			}
-		}
-	else
-		//coverity[leave_without_push]
-		Log::Printf(_L("\t\tNo SBLP"));
-	delete sblpParams;
-#endif
-	// Do the status change last, because it may generate events
-	// and callbacks. Now all the context state is updated...
-	SetContextStatus(aParams.iContextInfo.iStatus);
-	}
-
-// Rename: IsDefaultContext()
-TBool CPdpContext::IsPrimary() const
-	{
-	return (iNifItem.DefaultPdpContext() == this);
-	}
-
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <in_iface.h>
+
+#include "guqos.h"
+#include "iface.h"
+#include "tc.h"
+#include "parameters.h"
+#include "guqos_err.h"
+#include "async_request.h"
+#include "context.h"
+#include "guqos_log.h"
+
+#ifdef _LOG
+// *****************
+// Logging utilities
+// *****************
+
+// Return count of contiguous most significant 1-bits in TUint32
+static TInt MaskLength(TUint32 aAddr)
+	{
+	TInt count = 0;
+	// obviously, this is "brute force" counting
+	while (aAddr & 0x80000000)
+		{
+		count++;
+		aAddr <<= 1;
+		}
+	return count;
+	}
+
+//Return count of contiguous most significant 1-bits in IPv6 address.
+static TInt MaskLength(const TIp6Addr &aAddr)
+	{
+	TInt count = 0;
+	for (TUint i = 0; i < sizeof(aAddr.u.iAddr8) / sizeof(aAddr.u.iAddr8[0]); ++i)
+		if (aAddr.u.iAddr8[i] == 0xFF)
+			count += 8;
+		else
+			{
+			count += MaskLength(aAddr.u.iAddr8[i] << 24);
+			break;
+			}
+	return count;
+	}
+
+// A buffer to contain textual format of internet address
+class TAddressBuf : public TBuf<70>
+	{
+public:
+	TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort = 0);
+	};
+
+TAddressBuf::TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort)
+	{
+	TInetAddr addr(aAddr, 0);
+	addr.Output(*this);
+	if (aMask != 128)
+		{
+		if (aAddr.IsV4Mapped())
+			aMask -= 96;
+		_LIT(KFormat1, "/%u");
+		AppendFormat(KFormat1, aMask);
+		}
+	if (aPort)
+		{
+		_LIT(KFormat2, "#%u");
+		AppendFormat(KFormat2, (TInt)aPort);
+		}
+	}
+
+// Log packet filter address selector
+// Make this not "static", so that it can be used by other modules too...
+void LogPacketFilter(const TPacketFilter& aFilter)
+	{
+	TIp6Addr srcAddr;
+	Mem::Copy(&srcAddr,aFilter.iSrcAddr, sizeof(srcAddr));
+	TIp6Addr mask;
+	Mem::Copy(&mask,aFilter.iSrcAddrSubnetMask,sizeof(mask));
+	TAddressBuf addr(
+		srcAddr, 
+		MaskLength(mask),
+		aFilter.iSrcPortMin);
+	Log::Printf(_L("\t\t%u(%u) %S-%u dst#%u-%u SPI=%u TOS=%u FL=%u"),
+		aFilter.iId, aFilter.iEvaluationPrecedenceIndex,
+		&addr, (TInt)aFilter.iSrcPortMax,
+		(TInt)aFilter.iDestPortMin, (TInt)aFilter.iDestPortMax,
+		(TInt)aFilter.iIPSecSPI,
+		(TInt)aFilter.iTOSorTrafficClass,
+		(TInt)aFilter.iFlowLabel);
+	}
+#endif
+
+//	XPdpContextTimeoutLinkage
+//	************************
+//	Glue to bind timeout callback from the timeout manager into Timeout() call
+//	on the CPdpContext
+//
+//	*NOTE*
+//		This kludgery is all static and compile time, and only used in the constructor
+//		of CPdpContext.
+//
+
+// This ungainly manoevure is forced on us because the offset is not evaluated early enough by GCC3.4 to be
+// passed as a template parameter
+#if defined(__X86GCC__) || defined(__GCCE__)
+#define KPdpContextTimeoutOffset 716
+__ASSERT_COMPILE(KPdpContextTimeoutOffset == _FOFF(CPdpContext, iTimeout));
+#else
+#define KPdpContextTimeoutOffset _FOFF(CPdpContext, iTimeout)
+#endif
+
+class XPdpContextTimeoutLinkage : public TimeoutLinkage<CPdpContext, KPdpContextTimeoutOffset>
+	{
+public:
+	static void Timeout(RTimeout &aLink, const TTime & /*aNow*/, TAny * /*aPtr*/)
+		{
+		Object(aLink)->Timeout();
+		}
+	};
+
+
+CPdpContext* CPdpContext::NewL(CNif& aNifItem, const TContextType& aType, TUint8 aContextId)
+	{
+	CPdpContext* context = new (ELeave) CPdpContext(aNifItem, aType, aContextId);
+	CleanupStack::PushL(context);
+	context->ConstructL();
+	CleanupStack::Pop();
+	return context;
+	}
+
+CPdpContext::CPdpContext(CNif& aNifItem, TContextType aType, TUint8 aContextId) : 
+	iContextId(aContextId),
+	iNifItem(aNifItem),
+	iTimeout(XPdpContextTimeoutLinkage::Timeout)
+	{
+	iContextType = aType;
+	iContextStatus = RPacketContext::EStatusUnknown;
+	iFlows.SetOffset(_FOFF(CFlowData, iLink));
+	//iTrafficClass = -1;
+	}
+
+
+void CPdpContext::ConstructL()
+	{
+	}
+
+CPdpContext::~CPdpContext()
+	{
+	LOG(Log::Printf(_L("CPdpContext::~CPdpContext [ContextId=%d]"),iContextId));
+	while (!iFlows.IsEmpty())
+		{
+		// Any flows still attached to the PDP Context instance when
+		// we are in destructor, are deleted. If automatic move of
+		// flows to another context is the desired, it must be taken
+		// care before deleting the context (this destructor is also
+		// called from CNif destructor, and we cannot reference
+		// any other contexts on the CNif)
+		CFlowData* flow = iFlows.First();
+		// Deleting flow removes it from the list,
+		// and eventually the iFlows will become EMPTY!
+		delete flow;
+		}
+	iNifItem.CancelPendingRequest(this);
+	iTimeout.Cancel();	// ..if any active
+	}
+
+
+void CPdpContext::Timeout()
+	{
+	LOG(Log::Printf(_L("")));
+	if (Flows().IsEmpty())
+		{
+		LOG(Log::Printf(_L("CPdpContext::Timeout -- no flows, delete context")));
+		Delete();
+		Nif().DeletePdpContext(this);
+		}
+	else
+		{
+		LOG(Log::Printf(_L("CPdpContext::Timeout -- flows have re-appeared, keep context")));
+		// Some flows have come back, context is not
+		// deleted after all. But, because TFT's are
+		// not updated when the last flow leaves the
+		// context and this callback is scheduled, we
+		// now may have garbage TFT's left on the
+		// context. To cleanup the situation, schedule
+		// a CClose request.
+		CClose* request = CClose::New(*this);
+		if (request)
+			Nif().AddRequest(*request);
+		// If allocating request object fails, just
+		// ignore the issue of extra TFT's. It will
+		// eventually fix itself next time some flow
+		// leaves the context or context is deleted.
+		}
+	}
+	
+void CPdpContext::NotifyBlockingState(TUint aOldBlocking)
+	{
+	const TUint blocked = IsFlowBlocked();
+	if (blocked == aOldBlocking)
+		{
+		LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking unchanged (%d)"), ContextId(), ChannelId(), blocked));
+		return;		// No Change, no need to notify anyone.
+		}
+	LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking changed to (%d)"), ContextId(), ChannelId(), blocked));
+
+	MEventInterface *notifier = Nif().Module().QoSEvent();
+	if (!notifier)
+		{
+		LOG(Log::Printf(_L("\tOops -- QoS has not setup the MEventInterface")));
+		return;
+		}
+	
+	// Set all flows associated with this context into blocked or unblocked state
+	TDblFlowIter iter(iFlows);
+	CFlowData *flow;
+	//?? Potentially dangerout iterator, becuase BlockFlow upcall
+	//?? may call back and modify the list!
+	while ((flow = iter++) != NULL)
+		{
+		// Throw away "const". The MEventInterface is misdeclared to
+		// use non-const reference parameter, when const reference
+		// would be the correct way...
+		if (blocked)
+			notifier->BlockFlow((CFlowContext &)flow->FlowContext());
+		else
+			notifier->UnBlockFlow((CFlowContext &)flow->FlowContext());
+		}
+	}
+
+// Block flows on this context, no packets are sent to these flows after this.
+void CPdpContext::Block()
+	{
+	const TUint blocked = IsFlowBlocked(); // get old state
+	iBlocked = ETrue;
+	NotifyBlockingState(blocked);
+	}
+
+
+// Unblock flows on this context. Re-enable packet sending for these flows.
+void CPdpContext::UnBlock()
+	{
+	LOG(Log::Printf(_L("\tCPdpContext::UnBlock()")));
+	const TUint blocked = IsFlowBlocked(); // get old state
+	iBlocked = EFalse;
+	NotifyBlockingState(blocked);
+	}
+
+
+// Check if CFlowContext matches with packet filter attributes
+TBool CPdpContext::MatchPacketFilter(const TPacketFilter& aFlow, const TPacketFilter& aFilter) const
+	{
+	if (Mem::Compare(aFlow.iSrcAddr, 16, aFilter.iSrcAddr, 16) != 0)
+		return EFalse;
+	
+	if (Mem::Compare(aFlow.iSrcAddrSubnetMask, 16, aFilter.iSrcAddrSubnetMask, 16) != 0)
+		return EFalse;
+
+	if (aFlow.iProtocolNumberOrNextHeader != (TUint)aFilter.iProtocolNumberOrNextHeader)
+		return EFalse;
+
+	if (aFlow.iDestPortMin < aFilter.iDestPortMin || aFlow.iDestPortMax > aFilter.iDestPortMax)
+		return EFalse;
+
+	if (aFlow.iSrcPortMin < aFilter.iSrcPortMin || aFlow.iSrcPortMax > aFilter.iSrcPortMax)
+		return EFalse;
+
+	if (aFlow.iFlowLabel != aFilter.iFlowLabel)
+		return EFalse;
+
+	if (aFlow.iTOSorTrafficClass != aFilter.iTOSorTrafficClass)
+		return EFalse;
+
+	return ETrue;
+	}
+
+
+// Return QoS ranking according to TS 23.107
+//
+// (only used for turning some secondary context into new default/primary context)
+TInt CPdpContext::GetQoSRanking()
+	{
+	TInt ranking = 6;
+	switch (TrafficClass())
+		{
+	case RPacketQoS::ETrafficClassConversational:
+		ranking = 2;
+		break;
+
+	case RPacketQoS::ETrafficClassStreaming:
+		ranking = 3;
+		break;
+
+	case RPacketQoS::ETrafficClassInteractive:
+		{
+		const TInt priority = iNegotiated.iTrafficHandlingPriority;
+		if (priority == 1)
+			ranking = 1;
+		else if (priority == 2)
+			ranking = 4;
+		else
+			ranking = 5;
+		}
+		break;
+
+	default:
+	case RPacketQoS::ETrafficClassBackground:
+		ranking = 6;
+		break;
+		}
+	return ranking;
+	}
+
+
+TInt CPdpContext::FindPacketFilterId()
+	{
+	// Valid filter id's are from 1 - 8, find one which
+	// is not yet in use: First find out used id's into mask
+	
+	// Note: 3GPP specification uses 0-7 as the filter id.
+	// The etelpckt.h range [1-8] is adjusted to [0-7] at
+	// lower layers.
+	TUint mask = 0;
+	for (TInt i = iNumFilters; --i >= 0;)
+		{
+		const TPacketFilter& f = iFilters[i];
+		// Note silly naked constants, but there are no symbols for these?
+		if (f.iId > 0 && f.iId < 9)
+			{
+			mask |= (1 << f.iId);
+			}
+		}
+	// Find an empty id slot.
+	for (TInt j = 0; ++j < 9; )
+		{
+		if ((mask & (1 << j)) == 0)
+			return j;
+		}
+	//??What error is supposed to be returned?
+	//return KErrNotFound;
+	return KErrOverflow;
+	}
+
+
+// Add packet filter to TFT, return error or number of filters added
+TInt CPdpContext::AddPacketFilter(CFlowData& aFlow, TTFTInfo& aTft)
+	{
+	TInt ret = KErrNone;
+
+	LOG(Log::Printf(_L("\t\tCPdpContext::AddPacketFilter")));
+
+
+	TPacketFilter& flow_filter = aFlow.PacketFilter();
+
+	for (TInt i = iNumFilters; --i >= 0; )
+		if (MatchPacketFilter(flow_filter, iFilters[i]))
+			{
+			// The flow is already covered by an existing filter,
+			// no need to add anything, return 0.
+			return 0;
+			}
+
+	// Update flow filter with dynamic fields.
+	// This only marks the Id and evaluation precedende as reserved. It
+	// does not add the filter to the context object (iNumFilters is not
+	// incremented).
+	// It is assumed that once NIF completes the request, it will return
+	// the complete state of the context, including all currently active
+	// filters. At that point GUQOS state is recomputed to match the
+	// actual reality.
+	
+	// Not touching the iNumFilters works for now, because there is at
+	// most one negotiation open on any interface, and because negoatiation
+	// currently adds at most one new filter.
+	// If above changes, and some negotiation would need to add multiple
+	// filters, then additional logic needs to remember the to-be-added
+	// filters and assigned ids.
+	ret = FindPacketFilterId();
+	if (ret < 0)
+		{
+		// All filter slots already used!
+		LOG(Log::Printf(_L("\t\tNo PacketFilterId -- all used")));
+		return ret;
+		}
+	flow_filter.iId = ret;
+	LOG(Log::Printf(_L("\t\tPacketFilterId: %d"), flow_filter.iId));
+
+	flow_filter.iEvaluationPrecedenceIndex = Nif().FindEvaluationPrecedence();
+	LOG(Log::Printf(_L("\t\tEvaluationPrecedenceIndex: %d"), flow_filter.iEvaluationPrecedenceIndex));
+	LOG(LogPacketFilter(flow_filter));
+	ret = aTft.AddPacketFilter(flow_filter);
+	return ret < 0 ? ret : 1;	// if OK, 1 filter added
+	}
+
+
+// Remove packet filter(s) from the TFT, return error or number of filters to remove
+TInt CPdpContext::RemovePacketFilter(TTFTInfo& aTft, const CFlowData* aFlow)
+	/**
+	* Find the set of unused filters.
+	*
+	* Scan all currently attached flows and match them against current set of
+	* filters. Return the list of filters that didn't match any flows.
+	*
+	* One optional flow can be treated as non-attached (even if it appears
+	* in the attached list) and excluded matching test. This allows caller
+	* to leave a flow in the attached list for later removal.
+	*
+	* @retval aTft The list of unused filters
+	* @par	aFlow Optional flow to exclude from the matching.
+	*
+	* @return Negative error code (< 0), or number of unsed filters (>= 0),
+	* which were added into.
+	*/
+	{
+	// Because filters can match multiple flows (if someone actually starts
+	// using the netmask and port ranges), this must test whether any of the
+	// current filters become unnecessary when the indicated flow has been
+	// removed.
+
+	LOG(Log::Printf(_L("\t\tCPdpContext::RemovePacketFilter")));
+	TUint mask = 0;
+
+	// If the context is current designated "primary", then all filters
+	// must be removed (there can be filters only if this primary is
+	// a secondary context that has been assigned as new default).
+	if (!IsPrimary())
+		{
+		TDblFlowIter iter(iFlows);
+		CFlowData *flow;
+		while ((flow = iter++) != NULL)
+			{
+			if (flow == aFlow)
+				continue;	// skip the flow being removed.
+			const TPacketFilter& flow_filter = flow->PacketFilter();
+			for (TInt i = iNumFilters; --i >= 0; )
+				if (MatchPacketFilter(flow_filter, iFilters[i]))
+					{
+					mask |= (1 << i);	// Mark this filter as used.
+					break;				// No need to test other filters for this flow.
+					}
+			}
+		}
+	// Schedule removal of all filters that were not used.
+	TInt count = 0;
+	for (TInt j = 0; j < iNumFilters; ++j, mask >>= 1)
+		{
+		if ((mask & 1) == 0)
+			{
+			// This filter is not needed anymore
+			LOG(LogPacketFilter(iFilters[j]));
+			TInt ret = aTft.AddPacketFilter(iFilters[j]);
+			if (ret != KErrNone)
+				return ret;
+			++count;
+			}
+		}
+	return count;
+	}
+
+//
+// Set QoS parameters for a Pdp context.
+// Note: Change is not signaled to network until Activate/ModifyActive is called.
+//
+TInt CPdpContext::SetQoS(const TQoSParameters& aGeneric, const TQoSRequested& aUmts)
+	{
+	LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d]"),iContextId));
+
+	TContextParameters& parameters(Nif().ContextParameters());
+	
+	TQoSRequested requested;
+	ParameterMapper::MapGenericToRel99(aGeneric, requested);
+
+	// If adapt flag set, minimum params are set to unspecified
+	if (aGeneric.AdaptMode())
+		requested.ClearMinimumParameters();
+
+	ParameterMapper::CombineOverride(aUmts, requested);
+
+	parameters.iContextConfig.SetUMTSQoSReq(requested);
+	parameters.iContextConfig.SetPdpCompression(requested.iHeaderCompression);
+	parameters.iContextInfo.iContextId = iContextId;
+	parameters.iContextType = iContextType;
+	TPckg<TContextParameters> options(parameters);
+	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options);
+	return ret == KErrNone ? parameters.iReasonCode : ret;
+	}
+
+
+// Set QoS parameters for a Pdp context from defaults
+// Note: Change is not signaled to network until Activate/ModifyActive is called.
+TInt CPdpContext::SetQoS()
+	{
+	LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d ChannelId=%d]"), iContextId, iChannelId));
+
+	TContextParameters& parameters(Nif().ContextParameters());
+	TQoSRequested policy;
+	Nif().Module().GetDefaultParameters(policy, Nif().IapId());
+	parameters.iContextConfig.SetUMTSQoSReq(policy);
+	parameters.iContextConfig.SetPdpCompression(policy.iHeaderCompression);
+	parameters.iContextInfo.iContextId = iContextId;
+	parameters.iContextType = iContextType;
+	TPckg<TContextParameters> options(parameters);
+	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options);
+	return ret == KErrNone ? parameters.iReasonCode : ret;
+	}
+
+
+// SetQoS response
+void CPdpContext::SetQoSReply(CRequestBase* aRequest, const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::SetQoSReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
+
+	// Note: Because Run may complete the request, and resulting upcall
+	// to QoS may delete anything within the GUQOS, don't assume "this"
+	// exists after Run! Any actions on this must be done before the
+	// Run call.
+	if (aRequest)
+		aRequest->Run(EPendingSetQoS, this, aParams);
+	}
+
+TInt CPdpContext::ModifyTft(const TTFTOperationCode& aTFTOperationCode, const TTFTInfo& aTft)
+	{
+	LOG(Log::Printf(_L("\t\tModifyTFT on PDP Context [ContextId=%d]"),iContextId));
+
+	TPckg<TContextParameters> options(Nif().ContextParameters());
+	options().iContextConfig.SetTFTInfo(aTft);
+	options().iContextInfo.iContextId = iContextId;
+	options().iContextType = iContextType;
+	options().iTFTOperationCode = aTFTOperationCode;
+
+	const TInt ret = Nif().Interface().Control(KSOLInterface, KContextTFTModify, options);
+	return ret == KErrNone ? options().iReasonCode : ret;
+	}
+
+void CPdpContext::ModifyTftReply(CRequestBase* aRequest, const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::ModifyTftReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
+	if (!aRequest)
+		return;
+
+	// Translate operation code into "request code"...
+	TRequest code = EPendingAny;;
+	switch(aParams.iTFTOperationCode)
+		{
+	case KAddFilters:
+		code = EPendingPacketFilterAdd;
+		break;
+
+	case KRemoveFilters:
+		code = EPendingPacketFilterRemove;
+		break;
+
+	case KDeleteTFT:
+		code = EPendingTFTRemove;
+		break;
+
+	case KAddSblpParameter:
+		code = EPendingSblpParameterAdd;
+		break;
+			
+	case KRemoveSblpParameter:
+		code = EPendingSblpParameterRemove;
+		break;
+
+	default:
+		// Should not happen, but if it does, let the request state
+		// machine handle the problem (code is now EPendingAny!)
+		break;
+		}
+	// Note: Because Run may complete the request, and resulting upcall
+	// to QoS may delete anything within the GUQOS, don't assume "this"
+	// exists after Run! Any actions on this must be done before the
+	// Run call.
+	aRequest->Run(code, this, aParams);
+	}
+
+
+// Activate context
+TInt CPdpContext::Activate()
+	{
+	LOG(Log::Printf(_L("\t\tCPdpContext::Activate PDP Context [ContextId=%d]"),iContextId));
+
+	TContextParameters& parameters(Nif().ContextParameters());
+
+	// Activate only needs the context id.
+	parameters.iContextInfo.iContextId = iContextId;
+	//?? Does it need the "context type"?
+	parameters.iContextType = iContextType;
+	TPckg<TContextParameters> options(parameters);
+	const TInt ret =  Nif().Interface().Control(KSOLInterface, KContextActivate, options);
+	return ret == KErrNone ? parameters.iReasonCode : ret;
+	}
+
+// Activate context response
+void CPdpContext::ActivateReply(CRequestBase* aRequest, const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::ActivateReply() [ContextId=%d]"),iContextId));
+
+	Update(aParams);
+	// Must be done before Run (see below)!
+	if (ContextActive())
+		UnBlock();
+	// Note: Because Run may complete the request, and resulting upcall
+	// to QoS may delete anything within the GUQOS, don't assume "this"
+	// exists after Run! Any actions on this must be done before the
+	// Run call.
+	if (aRequest)
+		{
+		aRequest->Run(EPendingActivate, this, aParams);
+		}
+	}
+
+// Modify active Pdp context
+TInt CPdpContext::ModifyActive()
+	{
+	LOG(Log::Printf(_L("\t\tCPdpContext::ModifyActive [ContextId=%d]"),iContextId));
+
+	TContextParameters& parameters(Nif().ContextParameters());
+	parameters.iContextInfo.iContextId = iContextId;
+	TPckg<TContextParameters> options(parameters);
+
+	const TInt ret(Nif().Interface().Control(KSOLInterface, KContextModifyActive, options));
+	return ret == KErrNone ? parameters.iReasonCode : ret;
+	}
+
+void CPdpContext::ModifyActiveReply(CRequestBase* aRequest, const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::ModifyActiveReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
+	Update(aParams);
+
+	// Must be done before Run (see below)!
+	if (ContextActive())
+		UnBlock();
+	// Note: Because Run may complete the request, and resulting upcall
+	// to QoS may delete anything within the GUQOS, don't assume "this"
+	// exists after Run! Any actions on this must be done before the
+	// Run call.
+	if (aRequest)
+		aRequest->Run(EPendingModifyActive, this, aParams);
+	}
+
+// QoS parameters have changed
+void CPdpContext::ParametersChangedEvent(const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::ParametersChangedEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
+	Update(aParams);
+	// Notify applications about QoS change
+	GenerateEvent(KPfqosEventAdapt, aParams);
+	}
+
+void CPdpContext::DeleteEvent(const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("CPdpContext::DeleteEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode));
+	GenerateEvent(KPfqosEventFailure, aParams);
+	}
+
+// delete Pdp context
+TInt CPdpContext::Delete()
+	{
+	if (!IsPrimary())
+		{
+		LOG(Log::Printf(_L("\t\tCPdpContext::Delete [ContextId=%d]"),iContextId));
+
+		TContextParameters& parameters(Nif().ContextParameters());
+		parameters.iContextInfo.iContextId = iContextId;
+		TPckg<TContextParameters> options(parameters);
+		Nif().Interface().Control(KSOLInterface, KContextDelete, options);
+		}
+	return KErrNone;
+	}
+
+
+void CPdpContext::FlowAttached()
+	{
+	++iRefs;	
+	}
+
+void CPdpContext::FlowDetached()
+	{
+	--iRefs;
+	if (!IsPrimary() && iFlows.IsEmpty())
+		{
+		ASSERT(iRefs == 0);
+		iTimeout.Set(Nif().Module().TimeoutManager(), Nif().Module().Options().iTimeout);
+		}
+	}
+
+void CPdpContext::GenerateEvent(TUint aEventType, const TContextParameters& aParams)
+	{
+	// Generate event for channels
+	MEventInterface *notifier = Nif().Module().QoSEvent();
+	if (!notifier)
+		return;	// Nobody to notify!
+
+	RExtensionData extension;
+	TInt ret = extension.CreateExtension(aParams.iContextConfig, aParams.iReasonCode);
+	// if cannot generate full return information, try with plain reason code
+	if (ret != KErrNone)
+		(void)extension.SetErrorCode(aParams.iReasonCode);
+	
+	if (ChannelId())
+		{
+		// The PDP context represents a channel, one event for all joined flows
+		notifier->NotifyEvent(ChannelId(), aEventType, NULL, extension);
+		}
+	else
+		{
+		// Generate event for each flow
+		TDblFlowIter iter(iFlows);
+		CFlowData *flow;
+		while ((flow = iter++) != NULL)
+			{
+			// Throw away "const". The MEventInterface is misdeclared to
+			// use non-const reference parameter, when const reference
+			// would be the correct way...
+			notifier->NotifyEvent((CFlowContext &)flow->FlowContext(), aEventType, NULL, extension);
+			}
+		}
+	extension.Close();
+	}
+
+
+void CPdpContext::SetContextStatus(const RPacketContext::TContextStatus& aStatus)
+	{
+#ifdef _LOG
+	TBuf<40> statusBefore;
+
+	switch(iContextStatus)
+		{
+		case RPacketContext::EStatusUnknown:		statusBefore.Append(_L("EStatusUnknown"));		break;
+		case RPacketContext::EStatusInactive:		statusBefore.Append(_L("EStatusInactive"));		break;
+		case RPacketContext::EStatusActivating:		statusBefore.Append(_L("EStatusActivating"));	break;
+		case RPacketContext::EStatusActive:			statusBefore.Append(_L("EStatusActive"));		break;
+		case RPacketContext::EStatusDeactivating:	statusBefore.Append(_L("EStatusDeactivating"));	break;
+		case RPacketContext::EStatusSuspended:		statusBefore.Append(_L("EStatusSuspended"));	break;
+		case RPacketContext::EStatusDeleted:		statusBefore.Append(_L("EStatusDeleted"));		break;
+		default:									statusBefore.Append(_L("error"));				break;
+		}
+
+	TBuf<40> statusAfter;
+
+	switch(aStatus)
+		{
+		case RPacketContext::EStatusUnknown:		statusAfter.Append(_L("EStatusUnknown"));		break;
+		case RPacketContext::EStatusInactive:		statusAfter.Append(_L("EStatusInactive"));		break;
+		case RPacketContext::EStatusActivating:		statusAfter.Append(_L("EStatusActivating"));	break;
+		case RPacketContext::EStatusActive:			statusAfter.Append(_L("EStatusActive"));		break;
+		case RPacketContext::EStatusDeactivating:	statusAfter.Append(_L("EStatusDeactivating"));	break;
+		case RPacketContext::EStatusSuspended:		statusAfter.Append(_L("EStatusSuspended"));		break;
+		case RPacketContext::EStatusDeleted:		statusAfter.Append(_L("EStatusDeleted"));		break;
+		default:									statusAfter.Append(_L("error"));				break;
+		}
+
+	LOG(Log::Printf(_L("\tCPdpContext::SetContextStatus, iContextStatus before: {%S}, after: {%S}"), &statusBefore, &statusAfter));
+#endif
+
+	const TUint blocked = IsFlowBlocked();
+	iContextStatus = aStatus;
+	NotifyBlockingState(blocked);
+	}
+
+void CPdpContext::Update(const TContextParameters& aParams)
+	{
+	LOG(Log::Printf(_L("\tUpdate Context id = %d (channel=%d)"), ContextId(), ChannelId()));
+	// Save some basic negotiated values to the context instance.
+	aParams.iContextConfig.GetUMTSQoSNeg(iNegotiated);
+
+	// *NOTE* *ASSUMED*
+	// This function is called on completion of MofifyActive/Activate and
+	// in some other cases. Assume that the TContextParameters contains the
+	// current state of the context as seen by lower layers. The iReasonCode
+	// only indicates that the indicated operation failed or succeeded.
+	// The current state is provided even if iReasonCode != KErrNone.
+
+	LOG(Log::Printf(_L("\tCurrent TFT from NIF to PDP ContextId=%d"), ContextId()));
+	//?? The specification of TTFTInfo class is plain idiotic. There is no way to
+	//?? scan through filters with constant object. There is no way to get a
+	//?? const ref to filter inside TFTInfo, instead all scanning always requires
+	//?? inconvenient copying of the element (in addition to the fact that,
+	//?? you often have to copy the whole TTFTInfo structure to local store
+	//?? for a "modifiable copy" (which really should not be needed!)
+	
+	// Avoid some of the problems by *not* keeping TTFTInfo in CPdpContext, and
+	// maintain own simple array of TPacketFilters instead, which can at least
+	// be looked without needing to copy the elements each time...
+	TTFTInfo& tft = ((RContextConfig&)aParams.iContextConfig).TFTInfo();
+	tft.SetToFirst();
+	iNumFilters = 0;
+	while (iNumFilters < KMaxPacketFilters && tft.NextPacketFilter(iFilters[iNumFilters]) == KErrNone)
+		{
+		LOG(LogPacketFilter(iFilters[iNumFilters]));
+		++iNumFilters;
+		}
+	Nif().RecomputeEvaluationPrecedences();
+
+#ifdef _LOG
+	RPacketContext::CTFTMediaAuthorizationV3 *sblpParams;
+	TRAPD(err, sblpParams = RPacketContext::CTFTMediaAuthorizationV3::NewL());
+	if (err != KErrNone)
+		return;	// Blah!!
+	if (tft.GetSblpToken(*sblpParams) == KErrNone)
+		{
+		TBuf<KMaxFQDNLength> mat;
+		mat.Copy(sblpParams->iAuthorizationToken);
+		//coverity[leave_without_push]
+		Log::Printf(_L("\t\tMedia authorization: '%S'"),&mat);
+		for( TInt i = 0; i < sblpParams->iFlowIds.Count(); i++ )
+			{
+			//coverity[leave_without_push]
+			Log::Printf(_L("\t\tFlowId %d.  Media <%d> Flow <%d>"),
+				i,
+				sblpParams->iFlowIds[i].iMediaComponentNumber,
+				sblpParams->iFlowIds[i].iIPFlowNumber);
+			}
+		}
+	else
+		//coverity[leave_without_push]
+		Log::Printf(_L("\t\tNo SBLP"));
+	delete sblpParams;
+#endif
+	// Do the status change last, because it may generate events
+	// and callbacks. Now all the context state is updated...
+	SetContextStatus(aParams.iContextInfo.iStatus);
+	}
+
+// Rename: IsDefaultContext()
+TBool CPdpContext::IsPrimary() const
+	{
+	return (iNifItem.DefaultPdpContext() == this);
+	}
+