// 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);
}
}