24
|
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 |
|