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