telephonyprotocols/gprsumtsqosprt/src/async_request.cpp
changeset 0 3553901f7fa8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/gprsumtsqosprt/src/async_request.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1056 @@
+// 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 "iface.h"
+#include "context.h"
+#include "tc.h"
+#include <networking/qoserr.h>
+#include "guqos_err.h"
+#include "async_request.h"
+#include "guqos_log.h"
+
+
+
+// Open Channel Machine
+const SActionStep<COpenChannel> COpenChannel::iActionList[] =
+	{
+		&COpenChannel::ActionRemovePacketFilter,	// iState=0
+		&COpenChannel::ActionCommit,				// iState=1
+		&COpenChannel::ActionNewContext,			// iState=2
+		&COpenChannel::DoRememberCreatedContext,	// iState=3
+		&COpenChannel::ActionAddPacketFilter,		// iState=4
+		&COpenChannel::ActionAddSblpParameter,		// iState=5 == KStateReuseOldContext!
+		&COpenChannel::ActionSetQoS,
+		&COpenChannel::ActionCommit,
+		&COpenChannel::DoAddFlowToContext,
+		&COpenChannel::ActionNegotiationComplete
+	};
+const TInt KStateReuseOldContext = 5;	// *KEEP THIS IN SYNCH WITH ABOVE!*
+
+
+
+// Negotiate Channel Machine
+const SActionStep<CNegotiateChannel> CNegotiateChannel::iActionList[] =
+	{
+		&CNegotiateChannel::ActionAddSblpParameter,
+		&CNegotiateChannel::ActionSetQoS,
+		&CNegotiateChannel::ActionCommit,
+		&CNegotiateChannel::ActionNegotiationComplete,
+	};
+
+// Join Channel Machine
+const SActionStep<CJoinRequest> CJoinRequest::iActionList[] =
+	{
+		&CJoinRequest::ActionRemovePacketFilter,
+		&CJoinRequest::ActionCommit,
+		&CJoinRequest::DoStartWithTargetContext,
+		&CJoinRequest::ActionAddPacketFilter,
+		&CJoinRequest::DoAddFlowToContext,
+		&CJoinRequest::ActionRemovePacketFilter,	// Cleanup extra filters away, if present
+		&CJoinRequest::ActionCommit,
+		&CJoinRequest::ActionRequestComplete
+	};
+
+// Leave Channel Machine
+const SActionStep<CLeaveRequest> CLeaveRequest::iActionList[] =
+	{
+		&CLeaveRequest::ActionRemovePacketFilter,
+		&CLeaveRequest::ActionCommit,
+		&CLeaveRequest::ActionRequestComplete
+	};
+
+// Update Channel Machine (misnamed as "Close")
+const SActionStep<CClose> CClose::iActionList[] =
+	{
+		&CClose::ActionRemovePacketFilter,
+		&CClose::ActionCommit,
+		&CClose::ActionRequestComplete
+	};
+
+
+#ifdef _LOG
+//
+// Logging help classes
+//
+
+class TLogContextInfo : public TBuf<100>
+	{
+public:
+	TLogContextInfo(const CPdpContext* aContext);	
+	};
+
+TLogContextInfo::TLogContextInfo(const CPdpContext* aContext)
+	{
+	if (aContext)
+		{
+		Format(_L("context[%u] id=%d"), (TInt)aContext, aContext->ContextId()); // + 32
+		switch (aContext->ContextType())
+			{
+			case EPrimaryContext:	Append(_L(" primary")); break;
+			case ESecondaryContext:	Append(_L(" secondary")); break;			// + 10
+			case ENetworkInitiatedContext: Append(_L(" network")); break;
+			default: Append(_L(" unknown")); break;
+			}
+		switch (aContext->ContextStatus())
+			{
+			case RPacketContext::EStatusInactive: Append(_L(" inactive")); break;
+			case RPacketContext::EStatusActivating: Append(_L(" activating")); break;
+			case RPacketContext::EStatusActive: Append(_L(" active")); break;
+			case RPacketContext::EStatusDeactivating: Append(_L(" deactivating")); break;		// + 12
+			case RPacketContext::EStatusSuspended: Append(_L(" suspended")); break;
+			case RPacketContext::EStatusDeleted: Append(_L(" deleted")); break;
+			default: Append(_L(" unknown")); break;			
+			}
+		AppendFormat(_L("(%d)"), (TInt)aContext->ContextStatus());				// + 4
+
+		if (aContext->ChannelId())
+			{
+			AppendFormat(_L(" channel=%d"), aContext->ChannelId());				// + 18
+			}
+		AppendFormat(_L(", %d flows"), aContext->RefCount());					// + 11;
+		}
+	else
+		{
+		Append(_L("context NONE"));
+		}
+	}
+
+#endif
+
+
+CRequestBase::CRequestBase(CNif& aNif) : iNif(aNif)
+	{
+#ifdef _LOG
+	// This is only fallback, and should be overriden by the
+	//  derived classes!
+	_LIT(KLogName, "Base");
+	iName = &KLogName();
+#endif
+	}
+
+CRequestBase::~CRequestBase()
+	{
+	LOG(Log::Printf(_L("~\trequest %S[%u] destructed"), iName, (TInt)this));
+	}
+
+void CRequestBase::SetContext(CPdpContext *aContext)
+	/**
+	* Set/clear the current context for the state machine.
+	*/
+	{
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] -- %S set"), iName, (TInt)this, &info));
+	if (iContext != aContext)
+		{
+		iContext = aContext;
+		// Context has been changed, need to clear modified flag.
+		iContextModified = EFalse;	
+		}
+	iParams = NULL;	// Paremeters can only come from NIF event.
+	}
+
+void CRequestBase::SetExpected(const TRequest aRequest)
+	{
+	/**
+	* Define the expected result of the next asynchronous operation.
+	*/
+	iExpected = aRequest;
+	// Assume that SetExpected is only used when a request to NIF
+	// has been passed. Thus, any call to SetExpected implies that
+	// the context will be modified by NIF.
+	iContextModified = ETrue;
+	}
+	
+	
+static TBool CheckSblpErrorInPcoBuffer(const TContextParameters& aParams, TUint8& parsedSblpErrorValue)
+	{
+	TBool retValue = EFalse;
+	TInt ret = KErrNone;
+	
+	// create the PCO id for rejection code
+	RPacketContext::TPcoId sblpRejectionCodePcoId(
+				RPacketContext::EEtelPcktPolicyControlRejectionCode); 
+	/*
+	 *  get the value of the RPacketContext::TContextConfigGPRS 
+	 *  object from the TContextParameters object passed by the nif
+	 */
+	RPacketContext::TContextConfigGPRS configGPRS;
+	aParams.iContextConfig.GetContextConfig(configGPRS);
+
+	// adjust the PCO buffer 
+	TPtr8 pcoBufferPtr(const_cast<TUint8*>
+				(configGPRS.iProtocolConfigOption.iMiscBuffer.Ptr()),
+				configGPRS.iProtocolConfigOption.iMiscBuffer.Length(),
+				configGPRS.iProtocolConfigOption.iMiscBuffer.Length()); 
+
+	// attach TTlv  to the buffer 
+	TTlvStruct<RPacketContext::TPcoId,RPacketContext::TPcoItemDataLength> 
+												pcoTLV(pcoBufferPtr,pcoBufferPtr.Length());		 
+	
+	// Retreive the sblp rejection code value from the buffer
+	TBuf8<253> sblpRejectionCodeBuf; 
+	sblpRejectionCodeBuf.SetLength(pcoBufferPtr.Length());		 
+	TPtr8 sblpRejectionCodePtr(const_cast<TUint8*>(sblpRejectionCodeBuf.Ptr()),
+						sblpRejectionCodeBuf.Length(),sblpRejectionCodeBuf.MaxLength()); 
+	
+	pcoTLV.ResetCursorPos(); 
+	TRAPD(err1, ret=pcoTLV.NextItemL(sblpRejectionCodePcoId,sblpRejectionCodePtr) ); 
+	if (err1 !=KErrNone || ret!=KErrNone)
+		{
+		return EFalse;
+		}
+
+	// sblpRejectionCodeBuf[0] shall contain SBLP Rejection code ( values 1-7)) 
+	parsedSblpErrorValue = sblpRejectionCodePtr[0];
+	if(parsedSblpErrorValue >= ESblpSubErrorValueMinimum && 
+		parsedSblpErrorValue <= ESblpSubErrorValueMaximum)
+		{
+		retValue = ETrue;
+		}
+	return retValue;
+	}
+
+
+void CRequestBase::Run(const TRequest aRequest, CPdpContext* aContext, const TContextParameters& aParams)
+	{
+	LOG(const TDesC* const name(iName)); // because request can get destroyed from under us, save the name here!
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("Run\trequest %S[%u] Actions on event=%d reason=%d expected event=%d on %S"),
+		name, (TInt)this, (TInt)aRequest, aParams.iReasonCode, (TInt)iExpected, &info));
+
+	iContext = aContext;
+	iParams = &aParams;
+
+	if (iExpected != aRequest && iExpected != EPendingAny)
+		{
+		CompleteAndDestruct(KErrCancel, NULL);
+		}
+	else if (aParams.iReasonCode == KErrNone)
+		{
+		// Reset to accepting any, actions must use SetExpected,
+		// when they activate asynchronous operation with
+		// a specific responce.
+		iExpected = EPendingAny;
+		do
+			{
+			++iState;	// Last state done OK, try next one.
+			}
+		while (!Action(iContext, iParams));
+		// Note: there is no special terminating test, it is excepted that
+		// the builder of action list guarantees that it always ends with
+		// action which unconditionally returns ETrue.
+		}
+	else
+		{
+		// The expected request has failed.
+		TInt reason = aParams.iReasonCode;
+
+		iExtension.SetUmtsType();
+
+		/*
+		 *  if there is KErrGprsUserAuthenticationFailure error code returned by 
+		 *  the etel via nif, then we must check for the possible specific sblp 
+		 *  errors in the Protocol Configuration Option PCO buffer.
+		 *  
+		 *  If the buffer has a value for the 
+		 *  TPcoIDNetworkToMS::EEtelPcktPolicyControlRejectionCode id, then we can
+		 *  decide that sblp specific error has been occured if one of the the 
+		 *  possible sub error codes (totally six!) matches.
+		 */
+		
+		if (reason == KErrGprsUserAuthenticationFailure)
+			{
+			TUint8 parsedSblpErrorValue = KErrNone;
+			/*
+			 *  check if PCO buffer has sblp rejection code error value
+			 *  calling CheckSblpErrorInPcoBuffer() returns true only
+			 *  if there is error in the buffer and if the error range 
+			 *  is between (1-7)
+			 */
+			if (CheckSblpErrorInPcoBuffer(aParams,parsedSblpErrorValue))
+				{
+				/*
+				 *  it is definitely a sblp error
+				 *  Set the sblp error flag
+				 */
+		 		iExtension.SetSblpType();
+
+				// figure out the sub error type
+				switch (parsedSblpErrorValue)
+					{
+				case 1:
+					// Use the sblp error code to create Failure()
+					reason = EGuqosSblpAuthorizationFailureOfRequest;
+					break;
+				case 2:
+					reason = EGuqosSblpMissingBindingInfo;
+					break;
+				case 3:
+					reason = EGuqosSblpInvalidBindingInfo;
+					break;
+				case 4:
+					reason = EGuqosSblpBindingInfoNotAllowed;
+					break;
+				case 5:
+					reason = EGuqosSblpAuthorizingEntityTemporarilyUnavailable;
+					break;
+				case 6:
+					reason = EGuqosSblpNoCorrespondingSession;
+					break;
+				case 7:
+					reason = EGuqosSblpInvalidBundling;
+					break;
+				default:
+					/*
+					 *  it will never reach here!
+					 *  because the range checking is already done in
+					 *  CheckSblpErrorInPcoBuffer(aParams,parsedSblpErrorValue) 
+					 */
+					LOG(Log::Printf(_L("\trequest%S[%u] SBLP error value range fault!"), name, (TInt)this));
+					break;
+					}
+				}
+			}
+		// Deliver failure to the actual request implementation.
+		Failure(aContext, reason);
+		}
+	LOG(Log::Printf(_L("\trequest %S[%u] Run Actions Exit"), name, (TInt)this));
+	}
+
+
+void CRequestBase::Start()
+	{
+	LOG(const TDesC* const name(iName)); // because request can get destroyed from under us, save the name here!
+	LOG(TLogContextInfo info(iContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] Start Actions with %S"), name, (TInt)this, &info));
+	// Rely on C-class 0-fill. Initially all state variables
+	// are zero, e.g.
+	//   iContext = NULL;
+	//   iParams = NULL;
+	//   iExpected = EPendingAny;
+	//   iState = 0
+	// This start does not touch those values and allows derived
+	// class to override this function with something that may initialize
+	// state, before calling the base implementation of the Start.
+
+	// Excecute actions until something catches or request terminates.
+	while (!Action(iContext, iParams))
+		{
+		++iState;
+		}
+	// Note: there is no special terminating test, it is excepted that
+	// the builder of action list guarantees that it always ends with
+	// action which unconditionally returns ETrue.
+	LOG(Log::Printf(_L("\trequest %S[%u] Start Actions Exit"), name, (TInt)this));
+	}
+
+void CRequestBase::CompleteAndDestruct(TInt aErrorCode, const TQoSParameters* aParams, const TExtensionData& aExtension)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] CompleteAndDestruct ErrorCode=%d"), iName, (TInt)this, aErrorCode));
+	// Remove all references to this request...
+	iNif.CloseRequest(this);
+	// ...before delivering the completion. The delivery may call
+	// back, and this request must be totally removed by then, or
+	// bad things can happen (like, duplicate delete).
+	if (iNotify)
+		iNotify->RequestComplete(aErrorCode, aParams, aExtension);
+	delete this;
+	}
+
+
+TBool CRequestBase::IsOk(TInt aResult, CPdpContext *aContext)
+	{
+	if (aResult >= 0)
+		return ETrue;
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] IsOk(%d) is not OK %S"), iName, (TInt)this, aResult, &info));
+	Failure(aContext, aResult);
+	return EFalse;
+	}
+
+TBool CRequestBase::ActionRemovePacketFilter(CPdpContext* aContext, const TContextParameters*)
+	/**
+	* Activate leaving flow from a context.
+	*/
+	{
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRemovePacketFilter from %S"), iName, (TInt)this, iState, &info));
+	if (aContext)
+		{
+		// This branch is needed for the primary too, but only in rare case
+		// where a secondary is being changed into a primary.
+		if (iFlow)
+			{
+			// Move the flow to default context. If remove
+			// fails, it is higly likely that this flow was
+			// not included in TFT.
+			iFlow->SetContext(iNif.DefaultPdpContext());
+			}
+		if (aContext->RefCount() > 0 || aContext->IsPrimary())
+			{
+			// Context has remaining flows or is a Primary, collect unused filters.
+			// (in case of primary, all filters will be unused, if any present).
+			TTFTInfo tft;
+			TInt ret = aContext->RemovePacketFilter(tft, iFlow);
+			if (ret > 0)
+				{
+				LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRemovePacketFilter -- removing %d filter(s)"), iName, (TInt)this, iState, ret));
+				SetExpected(EPendingPacketFilterRemove);
+				(void)IsOk(aContext->ModifyTft(KRemoveFilters, tft), aContext);
+				return ETrue;
+				}
+			else if (ret < 0)
+				{
+				LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRemovePacketFilter -- TFT construct failed with %d"), iName, (TInt)this, iState, ret));
+				CompleteAndDestruct(ret, NULL);
+				return ETrue;
+				}
+			}
+		else
+			{
+			// All flows have been removed from the context. In the current implementation
+			// the context has been scheduled for destruction, and there is no need for
+			// removing any existing TFT...
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRemovePacketFilter -- No flows left"), iName, (TInt)this, iState));
+			}
+		}
+	// No TFT changes need to be done,
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRemovePacketFilter -- no filters to remove"), iName, (TInt)this, iState));
+	return EFalse;
+	}
+	
+
+TBool CRequestBase::ActionAddPacketFilter(CPdpContext* aContext, const TContextParameters* /*aParams*/)
+	{
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddPacketFilter on %S"), iName, (TInt)this, iState, &info));
+	if (aContext && iFlow)
+		{
+		TTFTInfo tft;
+		TInt err = aContext->AddPacketFilter(*iFlow, tft);
+		if (err < 0)
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddPacketFilter -- TFT construct failed with %d"), iName, (TInt)this, iState, err));
+			Failure(aContext, err);
+			return ETrue;
+			}
+		else if (err > 0)
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddPacketFilter -- adding %d filter(s)"), iName, (TInt)this, iState, err));
+			SetExpected(EPendingPacketFilterAdd);
+			(void)IsOk(aContext->ModifyTft(KAddFilters, tft), aContext);
+			return ETrue;
+			}
+		// Filter does not need modification, start some other operation...
+		}
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddPacketFilter -- no filters added"), iName, (TInt)this, iState));
+	return EFalse;
+	}
+	
+TBool CRequestBase::ActionCommit(CPdpContext* aContext, const TContextParameters* /*aParams*/)
+	/**
+	* Activate changes made to a context.
+	*
+	* This action can be run after a sequence of context modifying
+	* actions (filter, QoS, etc.). Depending on the state of the
+	* context, this calls either ModifyActive or Activate.
+	*/
+	{
+	if (aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+
+		if (!aContext->ContextActive())
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionCommit -- start Activate %S"), iName, (TInt)this, iState, &info));
+			SetExpected(EPendingActivate);
+			(void)IsOk(aContext->Activate(), aContext);
+			}
+		else if (iContextModified)
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionCommit -- start ModifyActive %S"), iName, (TInt)this, iState, &info));
+			SetExpected(EPendingModifyActive);
+			(void)IsOk(aContext->ModifyActive(), aContext);
+			}
+		else
+			{
+			// For example all flows go into same tunnel and filter is same for everyone.
+			// A flow leaving context does not affect the filter.
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionCommit -- skip ModifyActive, not modified %S"), iName, (TInt)this, iState, &info));
+			return EFalse;
+			}
+		return ETrue;
+		}
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionCommit -- nothing to do, no context"), iName, (TInt)this, iState));
+	return EFalse;
+	}
+
+
+TBool CRequestBase::ActionRequestComplete(CPdpContext* /*aContext*/, const TContextParameters* /*aParams*/)
+	{
+	/**
+	* Default termination of the request.
+	*
+	* This action can be used as a default terminator of the request,
+	*/
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionRequestComplete"), iName, (TInt)this, iState));
+	CompleteAndDestruct(KErrNone, NULL);
+	return ETrue;
+	}
+
+TBool CRequestBase::DoAddFlowToContext(CPdpContext* aContext, const TContextParameters*)
+	/**
+	* Set add current flow to current context.
+	*
+	* Add current flow to current context internally (e.g. add CFlowData object to
+	* CPdpContext object).
+	*/
+	{
+	LOG(TLogContextInfo info(aContext));
+	if (iFlow && aContext)
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.DoAddFlowToContext to %S"), iName, (TInt)this, iState, &info));
+		iFlow->SetContext(aContext);
+		}
+	else
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.DoAddFlowToContext to %S [not done]"), iName, (TInt)this, iState, &info));
+		}
+	// This allows the use ActionRemovePacketFilter to be used after this
+	// to clean out unnecessary filters. This is required in Join, because
+	// when the last flow leaves, the filters are not updated (cannot be
+	// removed because PDP Context cannot exist without filters, and just
+	// deleting the context would be too drastic). Thus, when the same flow
+	// or new flow joins back to existing context, we need to check and
+	// clean out stale filters.
+	iFlow = NULL;
+	return EFalse;
+	}
+
+void CRequestBase::Cancel(CFlowData* aFlowData)
+	/**
+	* Default cancel based on flow.
+	*
+	* If the only CFlowData pointer in request is stored in iFlow,
+	* then this default Cancel should be enough for most cases.
+	*/
+	{
+	if (iFlow == aFlowData)
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] Cancel due flow[%u] -- only detach the flow"), iName, (TInt)this, (TInt)iFlow));
+		// A running request is hard to cancel, because there is no way
+		// to tell NIF about it. Thus, when flow is cancelled, just detach
+		// it from the request and let the state machine run to completion
+		// without the flow (the machine should adapt!)
+		iFlow = NULL;
+		}
+	}
+
+void CRequestBase::Failure(CPdpContext* aContext, TInt aErrorCode)
+	/**
+	* The default Failure handler.
+	*
+	* Load the error code into iExtension and destruct.
+	*/
+	{
+	LOG(TLogContextInfo info(aContext));
+	(void)aContext; // silence warning in MARM release compile.
+	TInt ret = iExtension.SetErrorCode(aErrorCode);
+	LOG(Log::Printf(_L("\trequest %S[%u] Failure %S errorcode=%d ret=%d"), iName, (TInt)this, &info, aErrorCode, ret));
+	CompleteAndDestruct(ret == KErrNone ? aErrorCode : ret, NULL);
+	}
+
+// CNegotiationBase
+CNegotiationBase::CNegotiationBase(CNif& aNif) : CRequestBase(aNif)
+	{
+#ifdef _LOG
+	// This is only fallback, and should be ovvrriden by the
+	//  derived classes!
+	_LIT(KLogName, "Negotiation");
+	iName = &KLogName();
+#endif
+	}
+
+void CNegotiationBase::SetParameters(const TQoSParameters& aParams, CExtensionPolicy& aPolicy)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] SetParamaters"), iName, (TInt)this));
+	iGeneric = aParams;
+	iUmts.ParsePolicyData(&aPolicy);
+	}
+
+void CNegotiationBase::SetParametersFlowExtn(CExtensionPolicy &aPolicy)
+	{
+	// ParsePolicyData will return true if SBLP presents
+	if (iFlowExtnParams.ParsePolicyDataForSblp(&aPolicy))
+		{
+		// SBLP presents
+		// so, set the Sblp flag for the channel
+	 	iSblp = ETrue;	
+		LOG(Log::Printf(_L("\trequest %S[%u] SetParametersFlowExtn -- SBLP"), iName, (TInt)this));
+		}
+	}
+	
+// CNegotiationBase
+TBool CNegotiationBase::ActionAddSblpParameter(CPdpContext *aContext, const TContextParameters* /*aParams*/)
+	{
+	/*
+	 *  if SBLP is supported, sblp parameter is added after setting the 
+	 *  Qos parameters
+	 *  
+	 *  once sblp parameter is added, the operations continue in the same
+	 *  way as it was 
+	 */
+	if(aContext && iSblp) // the negotiations requests sblp context
+		{
+		// call modifytft to add sblp
+		LOG(TLogContextInfo info(aContext));
+		TTFTInfo tft;
+		if (IsOk(tft.AddSblpToken(iFlowExtnParams.iAuthorizationToken, iFlowExtnParams.iFlowIds), aContext))
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddSblpParameter -- Adding SBLP for %S"), iName, (TInt)this, iState, &info));
+			SetExpected(EPendingSblpParameterAdd);
+			(void)IsOk(aContext->ModifyTft(KAddSblpParameter, tft), aContext);
+			}
+		else
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddSblpParameter -- Failed constructing TFT for SBLP for %S"),
+				iName, (TInt)this, iState, &info));
+			}
+		return ETrue;
+		}
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionAddSblpParameter -- no SBLP"), iName, (TInt)this, iState));
+	return EFalse;
+	}
+	
+TBool CNegotiationBase::ActionSetQoS(CPdpContext *aContext, const TContextParameters* /*aParams*/)
+	{
+	if (aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionSetQoS -- request %S"), iName, (TInt)this, iState, &info));
+		SetExpected(EPendingSetQoS);
+		(void)IsOk(aContext->SetQoS(iGeneric, iUmts), aContext);
+		return ETrue;		
+		}
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionSetQoS -- skipping"), iName, (TInt)this, iState));
+	return EFalse;
+	}
+
+
+TBool CNegotiationBase::ActionNegotiationComplete(CPdpContext *aContext, const TContextParameters* aParams)
+	{
+	LOG(TLogContextInfo info(aContext));
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionNegotiationComplete %S"), iName, (TInt)this, iState, &info));
+	if (aParams)
+		{
+		// Return results of the negotiation to upper layers.
+		TInt ret = iExtension.CreateExtension(aParams->iContextConfig, aParams->iReasonCode);
+		if (ret != KErrNone)
+			{
+			LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionNegotiationComplete -- CreateExtension fail=%d"), iName, (TInt)this, iState, ret));
+			// Ugh.. can't construct the return value (probably out of memory)
+			// Try plain error instead (if that does not work, then nothing can
+			// be done about it...)
+			(void)iExtension.SetErrorCode(ret);
+			}
+		}
+
+	if (iFlow && aContext)
+		{
+		// If there is assocated flow, assume it will need to be moved
+		// to the current context (nothing happens, if this is already
+		// true.
+		iFlow->SetContext(aContext);
+		}
+
+	CompleteAndDestruct(KErrNone, &iGeneric, iExtension);
+	return ETrue;
+	}
+	
+void CNegotiationBase::Failure(CPdpContext* /*aPdpContext*/, TInt aErrorCode)
+	{
+	// If allocation space for extn fails, there not much
+	// that can be done, the request must be completed anyway
+	// with empty extn.
+	LOG(Log::Printf(_L("\trequest %S[%u] Failure code=%d"), iName, (TInt)this, aErrorCode));
+	(void)iExtension.SetErrorCode(aErrorCode);
+	CompleteAndDestruct(aErrorCode, &iGeneric, iExtension);
+	}
+
+	
+// CClose
+
+CClose* CClose::New(CPdpContext& aContext)
+	{
+	return new CClose(aContext);
+	}
+
+CClose::CClose(CPdpContext& aContext) : CRequestBase(aContext.Nif()), iClosing(aContext)
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Close");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = NULL;
+	}
+	
+void CClose::Start()
+	{
+	LOG(TLogContextInfo info(&iClosing));
+	LOG(Log::Printf(_L("Start\trequest %S[%u] %S"), iName, (TInt)this, &info));
+	// Give the context to the state machine.
+	SetContext(&iClosing);
+	// Note: iFlow is NULL. This means that the packet
+	// filter is just recomputed based on currenly
+	// joined flows.
+	CRequestBase::Start();
+	}
+
+CClose::~CClose()
+	{
+	}
+
+void CClose::Cancel(CPdpContext* aContext)
+	{
+	if (&iClosing == aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] for %S"), iName, (TInt)this, &info));
+		Failure(aContext, KErrDied);
+		}
+	}
+
+
+CDeleteRequest* CDeleteRequest::NewL(CPdpContext *aContext)
+	{
+	return new (ELeave) CDeleteRequest(aContext);
+	}
+
+CDeleteRequest::CDeleteRequest(CPdpContext* aContext) : CRequestBase(aContext->Nif()), iDelete(aContext)
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Delete");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = NULL;
+	}
+	
+void CDeleteRequest::Start()
+	{
+	LOG(TLogContextInfo info(iDelete));
+	LOG(Log::Printf(_L("Start\trequest %S[%u] %S"), iName, (TInt)this, &info));
+	// Issue a context delete for this context to NIF
+	if (iDelete)
+		{
+		CPdpContext* context = iDelete;
+		iDelete = NULL;		// Prevent Cancel() from triggering...
+		context->Delete();	// Send delete request to NIF
+		context->Nif().DeletePdpContext(context);	// Destroys the object (.. this calls my Cancel!)
+		}
+	CompleteAndDestruct(KErrNone, NULL);
+	}
+
+void CDeleteRequest::Cancel(CPdpContext* aContext)
+	{
+	if (aContext == iDelete)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] for %S"), iName, (TInt)this, &info));
+		Failure(aContext, KErrDied);
+		}
+	}
+
+
+// COpenChannel
+
+COpenChannel* COpenChannel::New(TUint aChannelId, CFlowData &aFlow, MQoSNegotiateEvent* aNotify)
+	{
+	return new COpenChannel(aChannelId, aFlow, aNotify);
+	}
+
+COpenChannel::COpenChannel(TInt aChannelId, CFlowData& aFlow, MQoSNegotiateEvent* aNotify) :
+	CNegotiationBase(aFlow.Nif()),
+	iChannelId(aChannelId)
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Open");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = aNotify;
+	iFlow = &aFlow;
+	}
+
+COpenChannel::~COpenChannel()
+	{
+	}
+
+TBool COpenChannel::ActionNewContext(CPdpContext */*aContext*/, const TContextParameters* /*aParams*/)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.ActionNewContext"), iName, (TInt)this, iState));
+	SetExpected(EPendingCreate);
+	(void)IsOk(iNif.NewPdpContext(), NULL);
+	return ETrue;
+	}
+	
+TBool COpenChannel::DoRememberCreatedContext(CPdpContext* aContext, const TContextParameters*)
+	{
+	iNewContext = aContext;
+	if (aContext)
+		{
+		// ..and bind it to the channel id.
+		aContext->SetChannelId(iChannelId);
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.DoRememberCreatedContext -- %S"), iName, (TInt)this, iState, &info));
+		}
+	else
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] %2d.DoRememberCreatedContext -- No context created for channel=%d"),
+			iName, (TInt)this, iState, iChannelId));
+		}
+	return EFalse;
+	}
+
+void COpenChannel::Start()
+	{
+	LOG(Log::Printf(_L("Start\trequest %S[%u] -- COpenChannel Begin"), iName, (TInt)this));
+	if (!iFlow)
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] Flow has been cancelled"), iName, (TInt)this));
+		CompleteAndDestruct(KErrNone, NULL);
+		return;
+		}
+
+	// First check if currently used Pdp context can be modified!!
+	CPdpContext* context = iFlow->PdpContext();
+	SetContext(context);
+	if (context && context != iNif.DefaultPdpContext())
+		{
+		if (context->RefCount() == 1)
+			{
+			LOG(TLogContextInfo info(context));
+			LOG(Log::Printf(_L("\trequest %S[%u] -- reuse existsing %S"), iName, (TInt)this, &info));
+			// Start state machine at different point.
+			iState = KStateReuseOldContext;
+			}
+		}
+	// If not reusing old, the machine starts by trying
+	// to remove the TFT from old context, if any...
+	CRequestBase::Start();
+	}
+
+
+void COpenChannel::Failure(CPdpContext* aPdpContext, TInt aErrorCode)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] Failure code=%d"), iName, (TInt)this, aErrorCode));
+
+	if (aPdpContext && aPdpContext == iNewContext)
+		{
+		iNewContext = NULL;
+		aPdpContext->Delete();
+		CNif& nif = aPdpContext->Nif();
+		nif.DeletePdpContext(aPdpContext);
+		}
+	CNegotiationBase::Failure(aPdpContext, aErrorCode);	
+	}
+
+void COpenChannel::Cancel(CPdpContext* aContext)
+	{
+	if (aContext == iNewContext)
+		{
+		// Prevent Failure from deleting the context (the caller of Cancel is
+		// just doing that).
+		iNewContext = NULL;
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] Cancelled for "), iName, (TInt)this, &info));
+		Failure(aContext, KErrDied);
+		}
+	}
+
+
+// CNegotiateChannel
+
+CNegotiateChannel* CNegotiateChannel::New(CPdpContext* aContext, MQoSNegotiateEvent* aNotify)
+	{
+	return new CNegotiateChannel(aContext, aNotify);
+	}
+
+CNegotiateChannel::CNegotiateChannel(CPdpContext *aContext, MQoSNegotiateEvent* aNotify) :
+	CNegotiationBase(aContext->Nif())
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Negotiate");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = aNotify;
+	iChannel = aContext;
+	}
+
+CNegotiateChannel::~CNegotiateChannel()
+	{
+	}
+
+
+void CNegotiateChannel::Start()
+	{
+	LOG(Log::Printf(_L("Start\trequest %S[%u] -- CNegotiateChannel Begin"), iName, (TInt)this));
+	SetContext(iChannel);
+	CRequestBase::Start();
+	}
+
+
+void CNegotiateChannel::Cancel(CPdpContext* aContext)
+	{
+	if (iChannel == aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] Cancelled for %S"), iName, (TInt)this, &info));
+		iChannel = NULL;
+		
+		//??Where does this go?
+		Failure(aContext, KErrDied);
+		}
+	}
+
+
+
+// CJoinRequest
+CJoinRequest* CJoinRequest::New(CPdpContext* aContext, CFlowData* aFlowData, MQoSNegotiateEvent* aNotify)
+	{
+	return new CJoinRequest(aContext, aFlowData, aNotify);
+	}
+
+CJoinRequest::CJoinRequest(CPdpContext* aContext,  CFlowData* aFlowData, MQoSNegotiateEvent* aNotify) :
+	CRequestBase(aFlowData->Nif())
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Join");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = aNotify;
+	iChannel = aContext;
+	iFlow = aFlowData;
+	}
+
+CJoinRequest::~CJoinRequest()
+	{
+	}
+
+void CJoinRequest::Start()
+	{
+	LOG(Log::Printf(_L("Start\trequest %S[%u] -- CJoinRequest Begin"), iName, (TInt)this));
+	if (!iFlow)
+		{
+		LOG(Log::Printf(_L("\trequest %S[%u] Flow has been cancelled"), iName, (TInt)this));
+		CompleteAndDestruct(KErrNone, NULL);
+		return;
+		}
+	CPdpContext* context = iFlow->PdpContext();
+	LOG(TLogContextInfo info(context));
+	if (context == iChannel)
+		{
+		// Already joined to the target context
+		LOG(Log::Printf(_L("\trequest %S[%u] already joined to %S"), iName, (TInt)this, &info));
+		CompleteAndDestruct(KErrNone, NULL, iExtension);
+		return;
+		}
+	// Start with removal of the TFT from old context.
+	SetContext(context);
+	CRequestBase::Start();
+	}
+
+
+TBool CJoinRequest::DoStartWithTargetContext(CPdpContext */*aContext*/, const TContextParameters* /*aParams*/)
+	{
+	LOG(TLogContextInfo info(iChannel));
+	LOG(Log::Printf(_L("\trequest %S[%u] %2d.DoStartWithTargetContext -- target %S"), iName, (TInt)this, iState, &info));
+	SetContext(iChannel);
+	return EFalse;
+	}
+
+
+void CJoinRequest::Failure(CPdpContext* /*aPdpContext*/, TInt aErrorCode)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] Failure code=%d"), iName, (TInt)this, aErrorCode));
+	iExtension.SetErrorCode(aErrorCode);
+	CompleteAndDestruct(EQoSJoinFailure, NULL, iExtension);
+	}
+
+void CJoinRequest::Cancel(CPdpContext* aContext)
+	{
+	if (iChannel == aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] Cancelled for %S"), iName, (TInt)this, &info));
+		Failure(aContext, KErrDied);
+		}
+	}
+
+// CLeaveRequest
+CLeaveRequest* CLeaveRequest::New(CPdpContext* aContext, CFlowData* aFlowData, MQoSNegotiateEvent* aNotify)
+	{
+	return new CLeaveRequest(aContext, aFlowData, aNotify);
+	}
+
+CLeaveRequest::CLeaveRequest(CPdpContext* aContext, CFlowData* aFlowData, MQoSNegotiateEvent* aNotify) :
+	CRequestBase(aContext->Nif())
+	{
+#ifdef _LOG
+	_LIT(KLogName, "Leave");
+	iName = &KLogName();
+#endif
+	LOG(Log::Printf(_L("new\trequest %S[%u] size=%d"), iName, (TInt)this, sizeof(*this)));
+	iNotify = aNotify;
+	iChannel = aContext;
+	iFlow = aFlowData;
+	//?? Why channel? it should be same as flow currently joined?
+	//?? Or just use channel and recompute, leave == close?
+	}
+
+void CLeaveRequest::Start()
+	{
+	LOG(Log::Printf(_L("Start\trequest %S[%u] -- CLeaveRequest Begin"), iName, (TInt)this));
+	// Start with removal of the TFT from old context.
+	// The flow has nothing to do with this anymore?
+	SetContext(iChannel);
+	CRequestBase::Start();
+	}
+
+CLeaveRequest::~CLeaveRequest()
+	{
+	LOG(Log::Printf(_L("CLeaveRequest::~CLeaveRequest()")));
+	}
+
+
+void CLeaveRequest::Failure(CPdpContext* /*aPdpContext*/, TInt aErrorCode)
+	{
+	LOG(Log::Printf(_L("\trequest %S[%u] Failure code=%d"), iName, (TInt)this, aErrorCode));
+	iExtension.SetErrorCode(aErrorCode);
+	CompleteAndDestruct(EQoSLeaveFailure, NULL, iExtension);
+	}
+
+void CLeaveRequest::Cancel(CPdpContext* aContext)
+	{
+	if (iChannel == aContext)
+		{
+		LOG(TLogContextInfo info(aContext));
+		LOG(Log::Printf(_L("Cancel\trequest %S[%u] Cancelled for %S"), iName, (TInt)this, &info));
+		Failure(aContext, KErrDied);
+		}
+	}