--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/gprsumtsqosprt/src/context.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +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);
+ }
+