diff -r 000000000000 -r 3553901f7fa8 telephonyprotocols/gprsumtsqosprt/src/context.cpp --- /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 + +#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 + { +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 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 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 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 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 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 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 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); + } +