|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <in_iface.h> |
|
17 |
|
18 #include "guqos.h" |
|
19 #include "iface.h" |
|
20 #include "tc.h" |
|
21 #include "parameters.h" |
|
22 #include "guqos_err.h" |
|
23 #include "async_request.h" |
|
24 #include "context.h" |
|
25 #include "guqos_log.h" |
|
26 |
|
27 #ifdef _LOG |
|
28 // ***************** |
|
29 // Logging utilities |
|
30 // ***************** |
|
31 |
|
32 // Return count of contiguous most significant 1-bits in TUint32 |
|
33 static TInt MaskLength(TUint32 aAddr) |
|
34 { |
|
35 TInt count = 0; |
|
36 // obviously, this is "brute force" counting |
|
37 while (aAddr & 0x80000000) |
|
38 { |
|
39 count++; |
|
40 aAddr <<= 1; |
|
41 } |
|
42 return count; |
|
43 } |
|
44 |
|
45 //Return count of contiguous most significant 1-bits in IPv6 address. |
|
46 static TInt MaskLength(const TIp6Addr &aAddr) |
|
47 { |
|
48 TInt count = 0; |
|
49 for (TUint i = 0; i < sizeof(aAddr.u.iAddr8) / sizeof(aAddr.u.iAddr8[0]); ++i) |
|
50 if (aAddr.u.iAddr8[i] == 0xFF) |
|
51 count += 8; |
|
52 else |
|
53 { |
|
54 count += MaskLength(aAddr.u.iAddr8[i] << 24); |
|
55 break; |
|
56 } |
|
57 return count; |
|
58 } |
|
59 |
|
60 // A buffer to contain textual format of internet address |
|
61 class TAddressBuf : public TBuf<70> |
|
62 { |
|
63 public: |
|
64 TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort = 0); |
|
65 }; |
|
66 |
|
67 TAddressBuf::TAddressBuf(const TIp6Addr& aAddr, TInt aMask, TUint16 aPort) |
|
68 { |
|
69 TInetAddr addr(aAddr, 0); |
|
70 addr.Output(*this); |
|
71 if (aMask != 128) |
|
72 { |
|
73 if (aAddr.IsV4Mapped()) |
|
74 aMask -= 96; |
|
75 _LIT(KFormat1, "/%u"); |
|
76 AppendFormat(KFormat1, aMask); |
|
77 } |
|
78 if (aPort) |
|
79 { |
|
80 _LIT(KFormat2, "#%u"); |
|
81 AppendFormat(KFormat2, (TInt)aPort); |
|
82 } |
|
83 } |
|
84 |
|
85 // Log packet filter address selector |
|
86 // Make this not "static", so that it can be used by other modules too... |
|
87 void LogPacketFilter(const TPacketFilter& aFilter) |
|
88 { |
|
89 TIp6Addr srcAddr; |
|
90 Mem::Copy(&srcAddr,aFilter.iSrcAddr, sizeof(srcAddr)); |
|
91 TIp6Addr mask; |
|
92 Mem::Copy(&mask,aFilter.iSrcAddrSubnetMask,sizeof(mask)); |
|
93 TAddressBuf addr( |
|
94 srcAddr, |
|
95 MaskLength(mask), |
|
96 aFilter.iSrcPortMin); |
|
97 Log::Printf(_L("\t\t%u(%u) %S-%u dst#%u-%u SPI=%u TOS=%u FL=%u"), |
|
98 aFilter.iId, aFilter.iEvaluationPrecedenceIndex, |
|
99 &addr, (TInt)aFilter.iSrcPortMax, |
|
100 (TInt)aFilter.iDestPortMin, (TInt)aFilter.iDestPortMax, |
|
101 (TInt)aFilter.iIPSecSPI, |
|
102 (TInt)aFilter.iTOSorTrafficClass, |
|
103 (TInt)aFilter.iFlowLabel); |
|
104 } |
|
105 #endif |
|
106 |
|
107 // XPdpContextTimeoutLinkage |
|
108 // ************************ |
|
109 // Glue to bind timeout callback from the timeout manager into Timeout() call |
|
110 // on the CPdpContext |
|
111 // |
|
112 // *NOTE* |
|
113 // This kludgery is all static and compile time, and only used in the constructor |
|
114 // of CPdpContext. |
|
115 // |
|
116 |
|
117 // This ungainly manoevure is forced on us because the offset is not evaluated early enough by GCC3.4 to be |
|
118 // passed as a template parameter |
|
119 #if defined(__X86GCC__) || defined(__GCCE__) |
|
120 #define KPdpContextTimeoutOffset 716 |
|
121 __ASSERT_COMPILE(KPdpContextTimeoutOffset == _FOFF(CPdpContext, iTimeout)); |
|
122 #else |
|
123 #define KPdpContextTimeoutOffset _FOFF(CPdpContext, iTimeout) |
|
124 #endif |
|
125 |
|
126 class XPdpContextTimeoutLinkage : public TimeoutLinkage<CPdpContext, KPdpContextTimeoutOffset> |
|
127 { |
|
128 public: |
|
129 static void Timeout(RTimeout &aLink, const TTime & /*aNow*/, TAny * /*aPtr*/) |
|
130 { |
|
131 Object(aLink)->Timeout(); |
|
132 } |
|
133 }; |
|
134 |
|
135 |
|
136 CPdpContext* CPdpContext::NewL(CNif& aNifItem, const TContextType& aType, TUint8 aContextId) |
|
137 { |
|
138 CPdpContext* context = new (ELeave) CPdpContext(aNifItem, aType, aContextId); |
|
139 CleanupStack::PushL(context); |
|
140 context->ConstructL(); |
|
141 CleanupStack::Pop(); |
|
142 return context; |
|
143 } |
|
144 |
|
145 CPdpContext::CPdpContext(CNif& aNifItem, TContextType aType, TUint8 aContextId) : |
|
146 iContextId(aContextId), |
|
147 iNifItem(aNifItem), |
|
148 iTimeout(XPdpContextTimeoutLinkage::Timeout) |
|
149 { |
|
150 iContextType = aType; |
|
151 iContextStatus = RPacketContext::EStatusUnknown; |
|
152 iFlows.SetOffset(_FOFF(CFlowData, iLink)); |
|
153 //iTrafficClass = -1; |
|
154 } |
|
155 |
|
156 |
|
157 void CPdpContext::ConstructL() |
|
158 { |
|
159 } |
|
160 |
|
161 CPdpContext::~CPdpContext() |
|
162 { |
|
163 LOG(Log::Printf(_L("CPdpContext::~CPdpContext [ContextId=%d]"),iContextId)); |
|
164 while (!iFlows.IsEmpty()) |
|
165 { |
|
166 // Any flows still attached to the PDP Context instance when |
|
167 // we are in destructor, are deleted. If automatic move of |
|
168 // flows to another context is the desired, it must be taken |
|
169 // care before deleting the context (this destructor is also |
|
170 // called from CNif destructor, and we cannot reference |
|
171 // any other contexts on the CNif) |
|
172 CFlowData* flow = iFlows.First(); |
|
173 // Deleting flow removes it from the list, |
|
174 // and eventually the iFlows will become EMPTY! |
|
175 delete flow; |
|
176 } |
|
177 iNifItem.CancelPendingRequest(this); |
|
178 iTimeout.Cancel(); // ..if any active |
|
179 } |
|
180 |
|
181 |
|
182 void CPdpContext::Timeout() |
|
183 { |
|
184 LOG(Log::Printf(_L(""))); |
|
185 if (Flows().IsEmpty()) |
|
186 { |
|
187 LOG(Log::Printf(_L("CPdpContext::Timeout -- no flows, delete context"))); |
|
188 Delete(); |
|
189 Nif().DeletePdpContext(this); |
|
190 } |
|
191 else |
|
192 { |
|
193 LOG(Log::Printf(_L("CPdpContext::Timeout -- flows have re-appeared, keep context"))); |
|
194 // Some flows have come back, context is not |
|
195 // deleted after all. But, because TFT's are |
|
196 // not updated when the last flow leaves the |
|
197 // context and this callback is scheduled, we |
|
198 // now may have garbage TFT's left on the |
|
199 // context. To cleanup the situation, schedule |
|
200 // a CClose request. |
|
201 CClose* request = CClose::New(*this); |
|
202 if (request) |
|
203 Nif().AddRequest(*request); |
|
204 // If allocating request object fails, just |
|
205 // ignore the issue of extra TFT's. It will |
|
206 // eventually fix itself next time some flow |
|
207 // leaves the context or context is deleted. |
|
208 } |
|
209 } |
|
210 |
|
211 void CPdpContext::NotifyBlockingState(TUint aOldBlocking) |
|
212 { |
|
213 const TUint blocked = IsFlowBlocked(); |
|
214 if (blocked == aOldBlocking) |
|
215 { |
|
216 LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking unchanged (%d)"), ContextId(), ChannelId(), blocked)); |
|
217 return; // No Change, no need to notify anyone. |
|
218 } |
|
219 LOG(Log::Printf(_L("\t\tContextId = %d (channel=%d) Blocking changed to (%d)"), ContextId(), ChannelId(), blocked)); |
|
220 |
|
221 MEventInterface *notifier = Nif().Module().QoSEvent(); |
|
222 if (!notifier) |
|
223 { |
|
224 LOG(Log::Printf(_L("\tOops -- QoS has not setup the MEventInterface"))); |
|
225 return; |
|
226 } |
|
227 |
|
228 // Set all flows associated with this context into blocked or unblocked state |
|
229 TDblFlowIter iter(iFlows); |
|
230 CFlowData *flow; |
|
231 //?? Potentially dangerout iterator, becuase BlockFlow upcall |
|
232 //?? may call back and modify the list! |
|
233 while ((flow = iter++) != NULL) |
|
234 { |
|
235 // Throw away "const". The MEventInterface is misdeclared to |
|
236 // use non-const reference parameter, when const reference |
|
237 // would be the correct way... |
|
238 if (blocked) |
|
239 notifier->BlockFlow((CFlowContext &)flow->FlowContext()); |
|
240 else |
|
241 notifier->UnBlockFlow((CFlowContext &)flow->FlowContext()); |
|
242 } |
|
243 } |
|
244 |
|
245 // Block flows on this context, no packets are sent to these flows after this. |
|
246 void CPdpContext::Block() |
|
247 { |
|
248 const TUint blocked = IsFlowBlocked(); // get old state |
|
249 iBlocked = ETrue; |
|
250 NotifyBlockingState(blocked); |
|
251 } |
|
252 |
|
253 |
|
254 // Unblock flows on this context. Re-enable packet sending for these flows. |
|
255 void CPdpContext::UnBlock() |
|
256 { |
|
257 LOG(Log::Printf(_L("\tCPdpContext::UnBlock()"))); |
|
258 const TUint blocked = IsFlowBlocked(); // get old state |
|
259 iBlocked = EFalse; |
|
260 NotifyBlockingState(blocked); |
|
261 } |
|
262 |
|
263 |
|
264 // Check if CFlowContext matches with packet filter attributes |
|
265 TBool CPdpContext::MatchPacketFilter(const TPacketFilter& aFlow, const TPacketFilter& aFilter) const |
|
266 { |
|
267 if (Mem::Compare(aFlow.iSrcAddr, 16, aFilter.iSrcAddr, 16) != 0) |
|
268 return EFalse; |
|
269 |
|
270 if (Mem::Compare(aFlow.iSrcAddrSubnetMask, 16, aFilter.iSrcAddrSubnetMask, 16) != 0) |
|
271 return EFalse; |
|
272 |
|
273 if (aFlow.iProtocolNumberOrNextHeader != (TUint)aFilter.iProtocolNumberOrNextHeader) |
|
274 return EFalse; |
|
275 |
|
276 if (aFlow.iDestPortMin < aFilter.iDestPortMin || aFlow.iDestPortMax > aFilter.iDestPortMax) |
|
277 return EFalse; |
|
278 |
|
279 if (aFlow.iSrcPortMin < aFilter.iSrcPortMin || aFlow.iSrcPortMax > aFilter.iSrcPortMax) |
|
280 return EFalse; |
|
281 |
|
282 if (aFlow.iFlowLabel != aFilter.iFlowLabel) |
|
283 return EFalse; |
|
284 |
|
285 if (aFlow.iTOSorTrafficClass != aFilter.iTOSorTrafficClass) |
|
286 return EFalse; |
|
287 |
|
288 return ETrue; |
|
289 } |
|
290 |
|
291 |
|
292 // Return QoS ranking according to TS 23.107 |
|
293 // |
|
294 // (only used for turning some secondary context into new default/primary context) |
|
295 TInt CPdpContext::GetQoSRanking() |
|
296 { |
|
297 TInt ranking = 6; |
|
298 switch (TrafficClass()) |
|
299 { |
|
300 case RPacketQoS::ETrafficClassConversational: |
|
301 ranking = 2; |
|
302 break; |
|
303 |
|
304 case RPacketQoS::ETrafficClassStreaming: |
|
305 ranking = 3; |
|
306 break; |
|
307 |
|
308 case RPacketQoS::ETrafficClassInteractive: |
|
309 { |
|
310 const TInt priority = iNegotiated.iTrafficHandlingPriority; |
|
311 if (priority == 1) |
|
312 ranking = 1; |
|
313 else if (priority == 2) |
|
314 ranking = 4; |
|
315 else |
|
316 ranking = 5; |
|
317 } |
|
318 break; |
|
319 |
|
320 default: |
|
321 case RPacketQoS::ETrafficClassBackground: |
|
322 ranking = 6; |
|
323 break; |
|
324 } |
|
325 return ranking; |
|
326 } |
|
327 |
|
328 |
|
329 TInt CPdpContext::FindPacketFilterId() |
|
330 { |
|
331 // Valid filter id's are from 1 - 8, find one which |
|
332 // is not yet in use: First find out used id's into mask |
|
333 |
|
334 // Note: 3GPP specification uses 0-7 as the filter id. |
|
335 // The etelpckt.h range [1-8] is adjusted to [0-7] at |
|
336 // lower layers. |
|
337 TUint mask = 0; |
|
338 for (TInt i = iNumFilters; --i >= 0;) |
|
339 { |
|
340 const TPacketFilter& f = iFilters[i]; |
|
341 // Note silly naked constants, but there are no symbols for these? |
|
342 if (f.iId > 0 && f.iId < 9) |
|
343 { |
|
344 mask |= (1 << f.iId); |
|
345 } |
|
346 } |
|
347 // Find an empty id slot. |
|
348 for (TInt j = 0; ++j < 9; ) |
|
349 { |
|
350 if ((mask & (1 << j)) == 0) |
|
351 return j; |
|
352 } |
|
353 //??What error is supposed to be returned? |
|
354 //return KErrNotFound; |
|
355 return KErrOverflow; |
|
356 } |
|
357 |
|
358 |
|
359 // Add packet filter to TFT, return error or number of filters added |
|
360 TInt CPdpContext::AddPacketFilter(CFlowData& aFlow, TTFTInfo& aTft) |
|
361 { |
|
362 TInt ret = KErrNone; |
|
363 |
|
364 LOG(Log::Printf(_L("\t\tCPdpContext::AddPacketFilter"))); |
|
365 |
|
366 |
|
367 TPacketFilter& flow_filter = aFlow.PacketFilter(); |
|
368 |
|
369 for (TInt i = iNumFilters; --i >= 0; ) |
|
370 if (MatchPacketFilter(flow_filter, iFilters[i])) |
|
371 { |
|
372 // The flow is already covered by an existing filter, |
|
373 // no need to add anything, return 0. |
|
374 return 0; |
|
375 } |
|
376 |
|
377 // Update flow filter with dynamic fields. |
|
378 // This only marks the Id and evaluation precedende as reserved. It |
|
379 // does not add the filter to the context object (iNumFilters is not |
|
380 // incremented). |
|
381 // It is assumed that once NIF completes the request, it will return |
|
382 // the complete state of the context, including all currently active |
|
383 // filters. At that point GUQOS state is recomputed to match the |
|
384 // actual reality. |
|
385 |
|
386 // Not touching the iNumFilters works for now, because there is at |
|
387 // most one negotiation open on any interface, and because negoatiation |
|
388 // currently adds at most one new filter. |
|
389 // If above changes, and some negotiation would need to add multiple |
|
390 // filters, then additional logic needs to remember the to-be-added |
|
391 // filters and assigned ids. |
|
392 ret = FindPacketFilterId(); |
|
393 if (ret < 0) |
|
394 { |
|
395 // All filter slots already used! |
|
396 LOG(Log::Printf(_L("\t\tNo PacketFilterId -- all used"))); |
|
397 return ret; |
|
398 } |
|
399 flow_filter.iId = ret; |
|
400 LOG(Log::Printf(_L("\t\tPacketFilterId: %d"), flow_filter.iId)); |
|
401 |
|
402 flow_filter.iEvaluationPrecedenceIndex = Nif().FindEvaluationPrecedence(); |
|
403 LOG(Log::Printf(_L("\t\tEvaluationPrecedenceIndex: %d"), flow_filter.iEvaluationPrecedenceIndex)); |
|
404 LOG(LogPacketFilter(flow_filter)); |
|
405 ret = aTft.AddPacketFilter(flow_filter); |
|
406 return ret < 0 ? ret : 1; // if OK, 1 filter added |
|
407 } |
|
408 |
|
409 |
|
410 // Remove packet filter(s) from the TFT, return error or number of filters to remove |
|
411 TInt CPdpContext::RemovePacketFilter(TTFTInfo& aTft, const CFlowData* aFlow) |
|
412 /** |
|
413 * Find the set of unused filters. |
|
414 * |
|
415 * Scan all currently attached flows and match them against current set of |
|
416 * filters. Return the list of filters that didn't match any flows. |
|
417 * |
|
418 * One optional flow can be treated as non-attached (even if it appears |
|
419 * in the attached list) and excluded matching test. This allows caller |
|
420 * to leave a flow in the attached list for later removal. |
|
421 * |
|
422 * @retval aTft The list of unused filters |
|
423 * @par aFlow Optional flow to exclude from the matching. |
|
424 * |
|
425 * @return Negative error code (< 0), or number of unsed filters (>= 0), |
|
426 * which were added into. |
|
427 */ |
|
428 { |
|
429 // Because filters can match multiple flows (if someone actually starts |
|
430 // using the netmask and port ranges), this must test whether any of the |
|
431 // current filters become unnecessary when the indicated flow has been |
|
432 // removed. |
|
433 |
|
434 LOG(Log::Printf(_L("\t\tCPdpContext::RemovePacketFilter"))); |
|
435 TUint mask = 0; |
|
436 |
|
437 // If the context is current designated "primary", then all filters |
|
438 // must be removed (there can be filters only if this primary is |
|
439 // a secondary context that has been assigned as new default). |
|
440 if (!IsPrimary()) |
|
441 { |
|
442 TDblFlowIter iter(iFlows); |
|
443 CFlowData *flow; |
|
444 while ((flow = iter++) != NULL) |
|
445 { |
|
446 if (flow == aFlow) |
|
447 continue; // skip the flow being removed. |
|
448 const TPacketFilter& flow_filter = flow->PacketFilter(); |
|
449 for (TInt i = iNumFilters; --i >= 0; ) |
|
450 if (MatchPacketFilter(flow_filter, iFilters[i])) |
|
451 { |
|
452 mask |= (1 << i); // Mark this filter as used. |
|
453 break; // No need to test other filters for this flow. |
|
454 } |
|
455 } |
|
456 } |
|
457 // Schedule removal of all filters that were not used. |
|
458 TInt count = 0; |
|
459 for (TInt j = 0; j < iNumFilters; ++j, mask >>= 1) |
|
460 { |
|
461 if ((mask & 1) == 0) |
|
462 { |
|
463 // This filter is not needed anymore |
|
464 LOG(LogPacketFilter(iFilters[j])); |
|
465 TInt ret = aTft.AddPacketFilter(iFilters[j]); |
|
466 if (ret != KErrNone) |
|
467 return ret; |
|
468 ++count; |
|
469 } |
|
470 } |
|
471 return count; |
|
472 } |
|
473 |
|
474 // |
|
475 // Set QoS parameters for a Pdp context. |
|
476 // Note: Change is not signaled to network until Activate/ModifyActive is called. |
|
477 // |
|
478 TInt CPdpContext::SetQoS(const TQoSParameters& aGeneric, const TQoSRequested& aUmts) |
|
479 { |
|
480 LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d]"),iContextId)); |
|
481 |
|
482 TContextParameters& parameters(Nif().ContextParameters()); |
|
483 |
|
484 TQoSRequested requested; |
|
485 ParameterMapper::MapGenericToRel99(aGeneric, requested); |
|
486 |
|
487 // If adapt flag set, minimum params are set to unspecified |
|
488 if (aGeneric.AdaptMode()) |
|
489 requested.ClearMinimumParameters(); |
|
490 |
|
491 ParameterMapper::CombineOverride(aUmts, requested); |
|
492 |
|
493 parameters.iContextConfig.SetUMTSQoSReq(requested); |
|
494 parameters.iContextConfig.SetPdpCompression(requested.iHeaderCompression); |
|
495 parameters.iContextInfo.iContextId = iContextId; |
|
496 parameters.iContextType = iContextType; |
|
497 TPckg<TContextParameters> options(parameters); |
|
498 const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options); |
|
499 return ret == KErrNone ? parameters.iReasonCode : ret; |
|
500 } |
|
501 |
|
502 |
|
503 // Set QoS parameters for a Pdp context from defaults |
|
504 // Note: Change is not signaled to network until Activate/ModifyActive is called. |
|
505 TInt CPdpContext::SetQoS() |
|
506 { |
|
507 LOG(Log::Printf(_L("\t\tCPdpContext::SetQoSL on PDP Context [ContextId=%d ChannelId=%d]"), iContextId, iChannelId)); |
|
508 |
|
509 TContextParameters& parameters(Nif().ContextParameters()); |
|
510 TQoSRequested policy; |
|
511 Nif().Module().GetDefaultParameters(policy, Nif().IapId()); |
|
512 parameters.iContextConfig.SetUMTSQoSReq(policy); |
|
513 parameters.iContextConfig.SetPdpCompression(policy.iHeaderCompression); |
|
514 parameters.iContextInfo.iContextId = iContextId; |
|
515 parameters.iContextType = iContextType; |
|
516 TPckg<TContextParameters> options(parameters); |
|
517 const TInt ret = Nif().Interface().Control(KSOLInterface, KContextQoSSet, options); |
|
518 return ret == KErrNone ? parameters.iReasonCode : ret; |
|
519 } |
|
520 |
|
521 |
|
522 // SetQoS response |
|
523 void CPdpContext::SetQoSReply(CRequestBase* aRequest, const TContextParameters& aParams) |
|
524 { |
|
525 LOG(Log::Printf(_L("CPdpContext::SetQoSReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode)); |
|
526 |
|
527 // Note: Because Run may complete the request, and resulting upcall |
|
528 // to QoS may delete anything within the GUQOS, don't assume "this" |
|
529 // exists after Run! Any actions on this must be done before the |
|
530 // Run call. |
|
531 if (aRequest) |
|
532 aRequest->Run(EPendingSetQoS, this, aParams); |
|
533 } |
|
534 |
|
535 TInt CPdpContext::ModifyTft(const TTFTOperationCode& aTFTOperationCode, const TTFTInfo& aTft) |
|
536 { |
|
537 LOG(Log::Printf(_L("\t\tModifyTFT on PDP Context [ContextId=%d]"),iContextId)); |
|
538 |
|
539 TPckg<TContextParameters> options(Nif().ContextParameters()); |
|
540 options().iContextConfig.SetTFTInfo(aTft); |
|
541 options().iContextInfo.iContextId = iContextId; |
|
542 options().iContextType = iContextType; |
|
543 options().iTFTOperationCode = aTFTOperationCode; |
|
544 |
|
545 const TInt ret = Nif().Interface().Control(KSOLInterface, KContextTFTModify, options); |
|
546 return ret == KErrNone ? options().iReasonCode : ret; |
|
547 } |
|
548 |
|
549 void CPdpContext::ModifyTftReply(CRequestBase* aRequest, const TContextParameters& aParams) |
|
550 { |
|
551 LOG(Log::Printf(_L("CPdpContext::ModifyTftReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode)); |
|
552 if (!aRequest) |
|
553 return; |
|
554 |
|
555 // Translate operation code into "request code"... |
|
556 TRequest code = EPendingAny;; |
|
557 switch(aParams.iTFTOperationCode) |
|
558 { |
|
559 case KAddFilters: |
|
560 code = EPendingPacketFilterAdd; |
|
561 break; |
|
562 |
|
563 case KRemoveFilters: |
|
564 code = EPendingPacketFilterRemove; |
|
565 break; |
|
566 |
|
567 case KDeleteTFT: |
|
568 code = EPendingTFTRemove; |
|
569 break; |
|
570 |
|
571 case KAddSblpParameter: |
|
572 code = EPendingSblpParameterAdd; |
|
573 break; |
|
574 |
|
575 case KRemoveSblpParameter: |
|
576 code = EPendingSblpParameterRemove; |
|
577 break; |
|
578 |
|
579 default: |
|
580 // Should not happen, but if it does, let the request state |
|
581 // machine handle the problem (code is now EPendingAny!) |
|
582 break; |
|
583 } |
|
584 // Note: Because Run may complete the request, and resulting upcall |
|
585 // to QoS may delete anything within the GUQOS, don't assume "this" |
|
586 // exists after Run! Any actions on this must be done before the |
|
587 // Run call. |
|
588 aRequest->Run(code, this, aParams); |
|
589 } |
|
590 |
|
591 |
|
592 // Activate context |
|
593 TInt CPdpContext::Activate() |
|
594 { |
|
595 LOG(Log::Printf(_L("\t\tCPdpContext::Activate PDP Context [ContextId=%d]"),iContextId)); |
|
596 |
|
597 TContextParameters& parameters(Nif().ContextParameters()); |
|
598 |
|
599 // Activate only needs the context id. |
|
600 parameters.iContextInfo.iContextId = iContextId; |
|
601 //?? Does it need the "context type"? |
|
602 parameters.iContextType = iContextType; |
|
603 TPckg<TContextParameters> options(parameters); |
|
604 const TInt ret = Nif().Interface().Control(KSOLInterface, KContextActivate, options); |
|
605 return ret == KErrNone ? parameters.iReasonCode : ret; |
|
606 } |
|
607 |
|
608 // Activate context response |
|
609 void CPdpContext::ActivateReply(CRequestBase* aRequest, const TContextParameters& aParams) |
|
610 { |
|
611 LOG(Log::Printf(_L("CPdpContext::ActivateReply() [ContextId=%d]"),iContextId)); |
|
612 |
|
613 Update(aParams); |
|
614 // Must be done before Run (see below)! |
|
615 if (ContextActive()) |
|
616 UnBlock(); |
|
617 // Note: Because Run may complete the request, and resulting upcall |
|
618 // to QoS may delete anything within the GUQOS, don't assume "this" |
|
619 // exists after Run! Any actions on this must be done before the |
|
620 // Run call. |
|
621 if (aRequest) |
|
622 { |
|
623 aRequest->Run(EPendingActivate, this, aParams); |
|
624 } |
|
625 } |
|
626 |
|
627 // Modify active Pdp context |
|
628 TInt CPdpContext::ModifyActive() |
|
629 { |
|
630 LOG(Log::Printf(_L("\t\tCPdpContext::ModifyActive [ContextId=%d]"),iContextId)); |
|
631 |
|
632 TContextParameters& parameters(Nif().ContextParameters()); |
|
633 parameters.iContextInfo.iContextId = iContextId; |
|
634 TPckg<TContextParameters> options(parameters); |
|
635 |
|
636 const TInt ret(Nif().Interface().Control(KSOLInterface, KContextModifyActive, options)); |
|
637 return ret == KErrNone ? parameters.iReasonCode : ret; |
|
638 } |
|
639 |
|
640 void CPdpContext::ModifyActiveReply(CRequestBase* aRequest, const TContextParameters& aParams) |
|
641 { |
|
642 LOG(Log::Printf(_L("CPdpContext::ModifyActiveReply [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode)); |
|
643 Update(aParams); |
|
644 |
|
645 // Must be done before Run (see below)! |
|
646 if (ContextActive()) |
|
647 UnBlock(); |
|
648 // Note: Because Run may complete the request, and resulting upcall |
|
649 // to QoS may delete anything within the GUQOS, don't assume "this" |
|
650 // exists after Run! Any actions on this must be done before the |
|
651 // Run call. |
|
652 if (aRequest) |
|
653 aRequest->Run(EPendingModifyActive, this, aParams); |
|
654 } |
|
655 |
|
656 // QoS parameters have changed |
|
657 void CPdpContext::ParametersChangedEvent(const TContextParameters& aParams) |
|
658 { |
|
659 LOG(Log::Printf(_L("CPdpContext::ParametersChangedEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode)); |
|
660 Update(aParams); |
|
661 // Notify applications about QoS change |
|
662 GenerateEvent(KPfqosEventAdapt, aParams); |
|
663 } |
|
664 |
|
665 void CPdpContext::DeleteEvent(const TContextParameters& aParams) |
|
666 { |
|
667 LOG(Log::Printf(_L("CPdpContext::DeleteEvent [ContextId=%d] [ReasonCode=%d]"),iContextId,aParams.iReasonCode)); |
|
668 GenerateEvent(KPfqosEventFailure, aParams); |
|
669 } |
|
670 |
|
671 // delete Pdp context |
|
672 TInt CPdpContext::Delete() |
|
673 { |
|
674 if (!IsPrimary()) |
|
675 { |
|
676 LOG(Log::Printf(_L("\t\tCPdpContext::Delete [ContextId=%d]"),iContextId)); |
|
677 |
|
678 TContextParameters& parameters(Nif().ContextParameters()); |
|
679 parameters.iContextInfo.iContextId = iContextId; |
|
680 TPckg<TContextParameters> options(parameters); |
|
681 Nif().Interface().Control(KSOLInterface, KContextDelete, options); |
|
682 } |
|
683 return KErrNone; |
|
684 } |
|
685 |
|
686 |
|
687 void CPdpContext::FlowAttached() |
|
688 { |
|
689 ++iRefs; |
|
690 } |
|
691 |
|
692 void CPdpContext::FlowDetached() |
|
693 { |
|
694 --iRefs; |
|
695 if (!IsPrimary() && iFlows.IsEmpty()) |
|
696 { |
|
697 ASSERT(iRefs == 0); |
|
698 iTimeout.Set(Nif().Module().TimeoutManager(), Nif().Module().Options().iTimeout); |
|
699 } |
|
700 } |
|
701 |
|
702 void CPdpContext::GenerateEvent(TUint aEventType, const TContextParameters& aParams) |
|
703 { |
|
704 // Generate event for channels |
|
705 MEventInterface *notifier = Nif().Module().QoSEvent(); |
|
706 if (!notifier) |
|
707 return; // Nobody to notify! |
|
708 |
|
709 RExtensionData extension; |
|
710 TInt ret = extension.CreateExtension(aParams.iContextConfig, aParams.iReasonCode); |
|
711 // if cannot generate full return information, try with plain reason code |
|
712 if (ret != KErrNone) |
|
713 (void)extension.SetErrorCode(aParams.iReasonCode); |
|
714 |
|
715 if (ChannelId()) |
|
716 { |
|
717 // The PDP context represents a channel, one event for all joined flows |
|
718 notifier->NotifyEvent(ChannelId(), aEventType, NULL, extension); |
|
719 } |
|
720 else |
|
721 { |
|
722 // Generate event for each flow |
|
723 TDblFlowIter iter(iFlows); |
|
724 CFlowData *flow; |
|
725 while ((flow = iter++) != NULL) |
|
726 { |
|
727 // Throw away "const". The MEventInterface is misdeclared to |
|
728 // use non-const reference parameter, when const reference |
|
729 // would be the correct way... |
|
730 notifier->NotifyEvent((CFlowContext &)flow->FlowContext(), aEventType, NULL, extension); |
|
731 } |
|
732 } |
|
733 extension.Close(); |
|
734 } |
|
735 |
|
736 |
|
737 void CPdpContext::SetContextStatus(const RPacketContext::TContextStatus& aStatus) |
|
738 { |
|
739 #ifdef _LOG |
|
740 TBuf<40> statusBefore; |
|
741 |
|
742 switch(iContextStatus) |
|
743 { |
|
744 case RPacketContext::EStatusUnknown: statusBefore.Append(_L("EStatusUnknown")); break; |
|
745 case RPacketContext::EStatusInactive: statusBefore.Append(_L("EStatusInactive")); break; |
|
746 case RPacketContext::EStatusActivating: statusBefore.Append(_L("EStatusActivating")); break; |
|
747 case RPacketContext::EStatusActive: statusBefore.Append(_L("EStatusActive")); break; |
|
748 case RPacketContext::EStatusDeactivating: statusBefore.Append(_L("EStatusDeactivating")); break; |
|
749 case RPacketContext::EStatusSuspended: statusBefore.Append(_L("EStatusSuspended")); break; |
|
750 case RPacketContext::EStatusDeleted: statusBefore.Append(_L("EStatusDeleted")); break; |
|
751 default: statusBefore.Append(_L("error")); break; |
|
752 } |
|
753 |
|
754 TBuf<40> statusAfter; |
|
755 |
|
756 switch(aStatus) |
|
757 { |
|
758 case RPacketContext::EStatusUnknown: statusAfter.Append(_L("EStatusUnknown")); break; |
|
759 case RPacketContext::EStatusInactive: statusAfter.Append(_L("EStatusInactive")); break; |
|
760 case RPacketContext::EStatusActivating: statusAfter.Append(_L("EStatusActivating")); break; |
|
761 case RPacketContext::EStatusActive: statusAfter.Append(_L("EStatusActive")); break; |
|
762 case RPacketContext::EStatusDeactivating: statusAfter.Append(_L("EStatusDeactivating")); break; |
|
763 case RPacketContext::EStatusSuspended: statusAfter.Append(_L("EStatusSuspended")); break; |
|
764 case RPacketContext::EStatusDeleted: statusAfter.Append(_L("EStatusDeleted")); break; |
|
765 default: statusAfter.Append(_L("error")); break; |
|
766 } |
|
767 |
|
768 LOG(Log::Printf(_L("\tCPdpContext::SetContextStatus, iContextStatus before: {%S}, after: {%S}"), &statusBefore, &statusAfter)); |
|
769 #endif |
|
770 |
|
771 const TUint blocked = IsFlowBlocked(); |
|
772 iContextStatus = aStatus; |
|
773 NotifyBlockingState(blocked); |
|
774 } |
|
775 |
|
776 void CPdpContext::Update(const TContextParameters& aParams) |
|
777 { |
|
778 LOG(Log::Printf(_L("\tUpdate Context id = %d (channel=%d)"), ContextId(), ChannelId())); |
|
779 // Save some basic negotiated values to the context instance. |
|
780 aParams.iContextConfig.GetUMTSQoSNeg(iNegotiated); |
|
781 |
|
782 // *NOTE* *ASSUMED* |
|
783 // This function is called on completion of MofifyActive/Activate and |
|
784 // in some other cases. Assume that the TContextParameters contains the |
|
785 // current state of the context as seen by lower layers. The iReasonCode |
|
786 // only indicates that the indicated operation failed or succeeded. |
|
787 // The current state is provided even if iReasonCode != KErrNone. |
|
788 |
|
789 LOG(Log::Printf(_L("\tCurrent TFT from NIF to PDP ContextId=%d"), ContextId())); |
|
790 //?? The specification of TTFTInfo class is plain idiotic. There is no way to |
|
791 //?? scan through filters with constant object. There is no way to get a |
|
792 //?? const ref to filter inside TFTInfo, instead all scanning always requires |
|
793 //?? inconvenient copying of the element (in addition to the fact that, |
|
794 //?? you often have to copy the whole TTFTInfo structure to local store |
|
795 //?? for a "modifiable copy" (which really should not be needed!) |
|
796 |
|
797 // Avoid some of the problems by *not* keeping TTFTInfo in CPdpContext, and |
|
798 // maintain own simple array of TPacketFilters instead, which can at least |
|
799 // be looked without needing to copy the elements each time... |
|
800 TTFTInfo& tft = ((RContextConfig&)aParams.iContextConfig).TFTInfo(); |
|
801 tft.SetToFirst(); |
|
802 iNumFilters = 0; |
|
803 while (iNumFilters < KMaxPacketFilters && tft.NextPacketFilter(iFilters[iNumFilters]) == KErrNone) |
|
804 { |
|
805 LOG(LogPacketFilter(iFilters[iNumFilters])); |
|
806 ++iNumFilters; |
|
807 } |
|
808 Nif().RecomputeEvaluationPrecedences(); |
|
809 |
|
810 #ifdef _LOG |
|
811 RPacketContext::CTFTMediaAuthorizationV3 *sblpParams; |
|
812 TRAPD(err, sblpParams = RPacketContext::CTFTMediaAuthorizationV3::NewL()); |
|
813 if (err != KErrNone) |
|
814 return; // Blah!! |
|
815 if (tft.GetSblpToken(*sblpParams) == KErrNone) |
|
816 { |
|
817 TBuf<KMaxFQDNLength> mat; |
|
818 mat.Copy(sblpParams->iAuthorizationToken); |
|
819 //coverity[leave_without_push] |
|
820 Log::Printf(_L("\t\tMedia authorization: '%S'"),&mat); |
|
821 for( TInt i = 0; i < sblpParams->iFlowIds.Count(); i++ ) |
|
822 { |
|
823 //coverity[leave_without_push] |
|
824 Log::Printf(_L("\t\tFlowId %d. Media <%d> Flow <%d>"), |
|
825 i, |
|
826 sblpParams->iFlowIds[i].iMediaComponentNumber, |
|
827 sblpParams->iFlowIds[i].iIPFlowNumber); |
|
828 } |
|
829 } |
|
830 else |
|
831 //coverity[leave_without_push] |
|
832 Log::Printf(_L("\t\tNo SBLP")); |
|
833 delete sblpParams; |
|
834 #endif |
|
835 // Do the status change last, because it may generate events |
|
836 // and callbacks. Now all the context state is updated... |
|
837 SetContextStatus(aParams.iContextInfo.iStatus); |
|
838 } |
|
839 |
|
840 // Rename: IsDefaultContext() |
|
841 TBool CPdpContext::IsPrimary() const |
|
842 { |
|
843 return (iNifItem.DefaultPdpContext() == this); |
|
844 } |
|
845 |