|
1 // Copyright (c) 2004-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 <bluetooth/logger.h> |
|
17 #include <es_prot.h> |
|
18 #include <bluetooth/hci/aclpacketconsts.h> |
|
19 |
|
20 #include "L2CapPDU.h" |
|
21 #include "l2capCommand.h" |
|
22 #include "l2signalmgr.h" |
|
23 #include "L2CapDataController.h" |
|
24 #include "L2CapSDU.h" |
|
25 #include "L2CapDebugControlInterface.h" |
|
26 |
|
27 #ifdef __FLOG_ACTIVE |
|
28 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP_PDU); |
|
29 #endif |
|
30 |
|
31 TDataPlaneElementHandle::TDataPlaneElementHandle(MDataPlaneElement* aDataElement, TUint16 aElementID) |
|
32 { |
|
33 LOG_FUNC |
|
34 SetUserLen(sizeof(SDataPlaneElementHandle)); |
|
35 SDataPlaneElementHandle* handlePtr = reinterpret_cast<SDataPlaneElementHandle*>(UserPtr()); |
|
36 handlePtr->iDataElement = aDataElement; |
|
37 handlePtr->iElementID = aElementID; |
|
38 } |
|
39 |
|
40 MDataPlaneElement& TDataPlaneElementHandle::DataPlaneElement() const |
|
41 { |
|
42 LOG_FUNC |
|
43 SDataPlaneElementHandle* handlePtr = reinterpret_cast<SDataPlaneElementHandle*>(UserPtr()); |
|
44 return *(handlePtr->iDataElement); |
|
45 } |
|
46 |
|
47 TUint16 TDataPlaneElementHandle::ElementID() const |
|
48 { |
|
49 LOG_FUNC |
|
50 SDataPlaneElementHandle* handlePtr = reinterpret_cast<SDataPlaneElementHandle*>(UserPtr()); |
|
51 return (handlePtr->iElementID); |
|
52 } |
|
53 |
|
54 |
|
55 // |
|
56 // Base class for all PDU types. |
|
57 // |
|
58 // Disable warning WINS 4355: 'this' : used in base member initializer list |
|
59 // This will not cause any problems in this usage and is preferable to the use of a |
|
60 // non-owned pointer. |
|
61 #pragma warning (disable: 4355) |
|
62 HL2CapPDU::HL2CapPDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize) |
|
63 : iIsFlushed(EFalse), |
|
64 iSendingError(EFalse), |
|
65 iQueuedForSend(EFalse), |
|
66 iAwaitingHciCompletion(EFalse), // first transmission never waits for a previous one to finish |
|
67 iElementHandle(this), |
|
68 iPduOwner(NULL), |
|
69 iOptimalFragmentSize(aOptimalFragmentSize), |
|
70 iTotalNumberOfFragments(KNumberOfFragmentsUnknown), |
|
71 iFragmentAcksReceived(0) |
|
72 { |
|
73 LOG_FUNC |
|
74 iPDUData.Assign(aPDUData); |
|
75 iPDUData.Align(Min(iPDUData.Length(), KMaxPDUHeaderLength)); |
|
76 |
|
77 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EBasePDU, |
|
78 L2capDebugInfo::EAllocated)); |
|
79 } |
|
80 |
|
81 HL2CapPDU::HL2CapPDU(TInt aOptimalFragmentSize) |
|
82 : iIsFlushed(EFalse), |
|
83 iSendingError(EFalse), |
|
84 iQueuedForSend(EFalse), |
|
85 iAwaitingHciCompletion(EFalse), // first transmission never waits for a previous one to finish |
|
86 iElementHandle(this), |
|
87 iPduOwner(NULL), |
|
88 iOptimalFragmentSize(aOptimalFragmentSize), |
|
89 iTotalNumberOfFragments(KNumberOfFragmentsUnknown), |
|
90 iFragmentAcksReceived(0) |
|
91 { |
|
92 LOG_FUNC |
|
93 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EBasePDU, |
|
94 L2capDebugInfo::EAllocated)); |
|
95 } |
|
96 #pragma warning (default: 4355) |
|
97 |
|
98 |
|
99 HL2CapPDU::~HL2CapPDU() |
|
100 { |
|
101 LOG_FUNC |
|
102 iPDUData.Free(); |
|
103 |
|
104 iLink.Deque(); |
|
105 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EBasePDU, |
|
106 L2capDebugInfo::EDeleted)); |
|
107 } |
|
108 |
|
109 |
|
110 // Static Message Accessors. |
|
111 /*static*/ TBool HL2CapPDU::AddFragment(RMBufChain& aPDU, RMBufChain& aPDUFragment) |
|
112 { |
|
113 LOG_STATIC_FUNC |
|
114 if(aPDUFragment.First()!= NULL) |
|
115 { |
|
116 aPDU.Append(aPDUFragment); |
|
117 return ((aPDU.Length() - KPDUHeaderLength) >= PDUPayloadLength(aPDU)); |
|
118 } |
|
119 else |
|
120 { |
|
121 return(EFalse); |
|
122 } |
|
123 } |
|
124 |
|
125 /*static*/ TUint16 HL2CapPDU::PDUPayloadLength(const RMBufChain& aPDU) |
|
126 { |
|
127 LOG_STATIC_FUNC |
|
128 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KPDUHeaderLength, |
|
129 Panic(EL2CapPDUInvalidLength)); |
|
130 return LittleEndian::Get16((aPDU.First())->Ptr()+KLengthByteOffset); |
|
131 } |
|
132 |
|
133 /*static*/ TUint16 HL2CapPDU::PDUCID(const RMBufChain& aPDU) |
|
134 { |
|
135 LOG_STATIC_FUNC |
|
136 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KPDUHeaderLength, |
|
137 Panic(EL2CapPDUInvalidLength)); |
|
138 return LittleEndian::Get16((aPDU.First())->Ptr()+KCIDByteOffset); |
|
139 } |
|
140 |
|
141 void HL2CapPDU::SetPDUPayloadLength(TUint16 aLength) |
|
142 { |
|
143 LOG_FUNC |
|
144 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KPDUHeaderLength, |
|
145 Panic(EL2CapPDUInvalidLength)); |
|
146 LittleEndian::Put16((iPDUData.First())->Ptr()+KLengthByteOffset, aLength); |
|
147 } |
|
148 |
|
149 void HL2CapPDU::SetPDUCID(TUint16 aCID) |
|
150 { |
|
151 LOG_FUNC |
|
152 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KPDUHeaderLength, |
|
153 Panic(EL2CapPDUInvalidLength)); |
|
154 LittleEndian::Put16((iPDUData.First())->Ptr()+KCIDByteOffset, aCID); |
|
155 } |
|
156 |
|
157 void HL2CapPDU::WritePDUPayloadLength() |
|
158 { |
|
159 LOG_FUNC |
|
160 SetPDUPayloadLength(static_cast<TUint16>(iPDUData.Length() - KPDUHeaderLength)); |
|
161 } |
|
162 |
|
163 /* |
|
164 * Function to return the PDU L2CAP overhead. |
|
165 */ |
|
166 /*static*/ TInt HL2CapPDU::GetPDUOrFragmentOverhead(TBool aBasicMode) |
|
167 { |
|
168 LOG_STATIC_FUNC |
|
169 if (aBasicMode) |
|
170 { |
|
171 // Basic mode does not segment into PDUs and therefore has no PDU overhead |
|
172 return 0; |
|
173 } |
|
174 |
|
175 // Non-basic mode overhead |
|
176 return KPDUHeaderLength + KControlFieldLength + KFCSFieldLength; |
|
177 } |
|
178 |
|
179 /* |
|
180 * Return the payload size of the optimal pdu based on the baseband packet |
|
181 * sizes, the negotiated MTU (aMTU) and the size of the buffers on the |
|
182 * controller (aBufSize). |
|
183 * SDU length field is taken into account when it get segmented by CL2CapSDU::SegmentSDUIntoPDUs |
|
184 */ |
|
185 /*static*/ TInt HL2CapPDU::GetPDUOrFragmentSize(TInt aMTU, TInt aMaxMps, TInt aBufSize, TBool aBasicMode) |
|
186 { |
|
187 LOG_STATIC_FUNC |
|
188 // aBufSize == 0 means that getting the buffer size failed so assume the best |
|
189 // case scenario for performance |
|
190 TInt bufSize = aBufSize != 0 ? aBufSize : KBBPacketSize[KBaseBandPacketCount - 1]; |
|
191 |
|
192 // get the overhead size for every l2cap pdu |
|
193 TInt packetOverhead = GetPDUOrFragmentOverhead(aBasicMode); |
|
194 |
|
195 // it's possible that the buffer size is so small that when including the packet overhead there is no |
|
196 // room for a payload, this is of course no good. |
|
197 __ASSERT_ALWAYS((bufSize - packetOverhead) > 0, Panic(EL2CAPACLBufferTooSmall)); |
|
198 |
|
199 // store the current baseband packet size as we go through the below for loop |
|
200 TInt currentPacketSize; |
|
201 |
|
202 // iterate backwards through the baseband packet sizes array |
|
203 for (TInt index = KBaseBandPacketCount - 1; index >= 0; index--) |
|
204 { |
|
205 currentPacketSize = KBBPacketSize[index]; |
|
206 |
|
207 if (aMTU >= (index > 0 ? ((currentPacketSize + KBBPacketSize[index - 1]) / 2) : currentPacketSize)) |
|
208 { |
|
209 if (bufSize >= currentPacketSize) |
|
210 { |
|
211 // if the current baseband packet size is less than the MTU size and the baseband |
|
212 // packet will fit into the controllers buffer then use the baseband packet |
|
213 return (aBasicMode ? (currentPacketSize - packetOverhead) : Min(aMaxMps, (currentPacketSize - packetOverhead))); |
|
214 } |
|
215 else if ((index > 0) && (bufSize >= ((currentPacketSize + KBBPacketSize[index - 1]) / 2))) |
|
216 { |
|
217 // if the current baseband packet is less than the MTU but the baseband packet |
|
218 // won't fit into the controllers buffer see if the buffer size is closer to the |
|
219 // current baseband packet than the next size down and if so use the buffer size |
|
220 // of the controller |
|
221 return (aBasicMode ? (bufSize - packetOverhead) : Min(aMaxMps, (bufSize - packetOverhead))); |
|
222 } |
|
223 } |
|
224 } |
|
225 |
|
226 // to get here means that the buffer size of the controller or the MTU is less than the minimum |
|
227 // baseband packet size. A small ACL buffer reduces performance as there is a big overhead to data |
|
228 // ratio, but we handle that situation anyway. |
|
229 return (aBasicMode ? (bufSize - packetOverhead) : Min(aMaxMps, (bufSize - packetOverhead))); |
|
230 } |
|
231 |
|
232 /*static*/ TInt HL2CapPDU::CheckDecode(const RMBufChain& aPDU) |
|
233 { |
|
234 LOG_STATIC_FUNC |
|
235 TInt rerr = KErrNone; |
|
236 if(aPDU.Length() != (PDUPayloadLength(aPDU) + KPDUHeaderLength)) |
|
237 { |
|
238 rerr = KErrCorrupt; |
|
239 } |
|
240 return rerr; |
|
241 } |
|
242 |
|
243 void HL2CapPDU::AppendPayloadToBuffer(RMBufChain& /*aSDUData*/) |
|
244 { |
|
245 LOG_FUNC |
|
246 Panic(EL2CAPInvalidCallToAppendPayloadToBuffer); |
|
247 } |
|
248 |
|
249 void HL2CapPDU::DeliverOutgoingPDU(MOutgoingPDUHandler& aPDUHandler) |
|
250 { |
|
251 iAwaitingHciCompletion = ETrue; |
|
252 DeliverOutgoingPDUDoubleDispatch(aPDUHandler); |
|
253 } |
|
254 |
|
255 |
|
256 void HL2CapPDU::PDUSendPending(TUint16 aTotalNumberOfFragments) |
|
257 { |
|
258 LOG_FUNC |
|
259 // The fragment sender has completed sending the PDU to the |
|
260 // ACL. |
|
261 __ASSERT_DEBUG(iTotalNumberOfFragments == KNumberOfFragmentsUnknown, Panic(EL2CAPPDUSendPendingCalledTwice)); |
|
262 |
|
263 iTotalNumberOfFragments = aTotalNumberOfFragments; |
|
264 |
|
265 // In some error conditions the expected number of outstanding fragments might |
|
266 // have been reached before this method is called. |
|
267 if(iFragmentAcksReceived == iTotalNumberOfFragments) |
|
268 { |
|
269 PDUSendComplete(); |
|
270 } |
|
271 } |
|
272 |
|
273 void HL2CapPDU::PDUSendComplete() |
|
274 { |
|
275 LOG_FUNC |
|
276 iAwaitingHciCompletion = EFalse; |
|
277 |
|
278 if(!iIsFlushed && iPduOwner) |
|
279 { |
|
280 iFragmentAcksReceived = 0; |
|
281 iTotalNumberOfFragments = KNumberOfFragmentsUnknown; |
|
282 |
|
283 if(!iSendingError) |
|
284 { |
|
285 // Do frame-type specific stuff. |
|
286 SendComplete(); |
|
287 |
|
288 iPduOwner->HandlePduSendComplete(*this); |
|
289 } |
|
290 else |
|
291 { |
|
292 iSendingError = EFalse; // in case the owner decides to resend us |
|
293 iPduOwner->HandlePduSendError(*this); |
|
294 } |
|
295 } |
|
296 else |
|
297 { |
|
298 // No references are held to this PDU. Delete it. |
|
299 delete this; |
|
300 } |
|
301 } |
|
302 |
|
303 |
|
304 // MDataPlaneElement Interface |
|
305 void HL2CapPDU::DataElementSent(TUint16 /*aElementID*/) |
|
306 { |
|
307 LOG_FUNC |
|
308 // Check if the PDU has been fully sent to the peer. |
|
309 if(++iFragmentAcksReceived == iTotalNumberOfFragments) |
|
310 { |
|
311 PDUSendComplete(); |
|
312 } |
|
313 } |
|
314 |
|
315 void HL2CapPDU::DataElementFlushed(TUint16 aElementID) |
|
316 { |
|
317 LOG_FUNC |
|
318 // Check if this PDU has been flushed. |
|
319 if(!iIsFlushed) |
|
320 { |
|
321 iSendingError = ETrue; |
|
322 } |
|
323 DataElementSent(aElementID); |
|
324 } |
|
325 |
|
326 TUint16 HL2CapPDU::CalcCRC(const RMBufChain& aPDU) |
|
327 { |
|
328 LOG_STATIC_FUNC |
|
329 TUint16 crcValue = 0; |
|
330 TUint8 dataByte; |
|
331 TInt i, bufLength; |
|
332 TUint16 carryBit, bitCount; |
|
333 |
|
334 const RMBuf* bufPtr = aPDU.First(); |
|
335 TInt fcsLength = aPDU.Length() - KFCSFieldLength; |
|
336 TInt byteCount = 0; |
|
337 while(bufPtr) |
|
338 { |
|
339 // Check if this is the last buffer. If so don't |
|
340 // process the FCS bytes. |
|
341 bufLength = bufPtr->Length(); |
|
342 for(i=0;i<bufLength;i++) |
|
343 { |
|
344 if(byteCount < fcsLength) |
|
345 { |
|
346 dataByte = bufPtr->Get(i); |
|
347 byteCount++; |
|
348 for(bitCount=0;bitCount<8;bitCount++) |
|
349 { |
|
350 carryBit = static_cast<TUint16>(crcValue & 0x8000 ? 1 : 0); |
|
351 crcValue <<= 1; |
|
352 if ((dataByte & 1) ^ carryBit) |
|
353 { |
|
354 crcValue ^= 0x8005; |
|
355 } |
|
356 dataByte >>= 1; |
|
357 } |
|
358 } |
|
359 } |
|
360 |
|
361 bufPtr = bufPtr->Next(); |
|
362 } |
|
363 |
|
364 carryBit = 0; |
|
365 for(bitCount=0;bitCount<16;bitCount++) |
|
366 { |
|
367 carryBit = static_cast<TUint16>((carryBit >> 1) | (crcValue & 0x8000)); |
|
368 crcValue <<= 1; |
|
369 } |
|
370 |
|
371 return carryBit; |
|
372 } |
|
373 |
|
374 void HL2CapPDU::SendComplete() |
|
375 { |
|
376 LOG_FUNC |
|
377 // Nothing to do for most PDUs. |
|
378 } |
|
379 |
|
380 |
|
381 // |
|
382 // Class used to fragment and send any type of PDU. |
|
383 // An instance of this class is currently owned by the Mux |
|
384 // |
|
385 HFragmentedPDUSender::HFragmentedPDUSender(CL2CAPMux& aMuxer) |
|
386 : iPDU(NULL), |
|
387 iPDUBuffer(NULL), |
|
388 iMuxer(aMuxer), |
|
389 iCurrentWriteIndex(0), |
|
390 iCurrentFragmentID(0), |
|
391 iPDULength(0) |
|
392 { |
|
393 LOG_FUNC |
|
394 } |
|
395 |
|
396 HFragmentedPDUSender::~HFragmentedPDUSender() |
|
397 { |
|
398 LOG_FUNC |
|
399 delete iPDUBuffer; |
|
400 __ASSERT_DEBUG(iPDU == NULL, Panic(EL2CAPFragmentSenderDeletedWhileSending)); |
|
401 } |
|
402 |
|
403 TInt HFragmentedPDUSender::FragmentPDU(HL2CapPDU& aPDU) |
|
404 { |
|
405 LOG_FUNC |
|
406 TInt rerr = KErrNone; |
|
407 __ASSERT_DEBUG(!iCurrentWriteIndex && !iCurrentFragmentID, Panic(EL2CAPRequestToFragmentWhileBufferContainsData)); |
|
408 |
|
409 RMBufChain& pduData = aPDU.PDUBuffer(); |
|
410 if(!iPDUBuffer || iPDUBuffer->Size() < pduData.Length()) |
|
411 { |
|
412 // Increase the size of the buffer. |
|
413 delete iPDUBuffer; |
|
414 iPDUBuffer = HBufC8::New(pduData.Length()); |
|
415 } |
|
416 |
|
417 if(iPDUBuffer) |
|
418 { |
|
419 iPDU = &aPDU; |
|
420 iPDULength = pduData.Length(); |
|
421 |
|
422 // Copy the Buffer into the descriptor |
|
423 TPtr8 ptr = iPDUBuffer->Des(); |
|
424 ptr.SetLength(iPDULength); |
|
425 pduData.CopyOut(ptr); |
|
426 |
|
427 // store the optimal fragment size |
|
428 iPDUFragmentSize = aPDU.OptimalFragmentSize(); |
|
429 } |
|
430 else |
|
431 { |
|
432 rerr = KErrNoMemory; |
|
433 } |
|
434 return rerr; |
|
435 } |
|
436 |
|
437 HFragmentedPDUSender::TFragmentSenderStatus HFragmentedPDUSender::WriteNextFragment(CServProviderBase& aSender, TInt aACLMTU) |
|
438 { |
|
439 LOG_FUNC |
|
440 // If optimal fragment size not set then this PDU should only have been segmented, not fragmented |
|
441 __ASSERT_DEBUG((iPDULength <= aACLMTU) || (iPDUFragmentSize != 0), Panic(EL2CAPUnexpectedFragmentation)); |
|
442 if (iPDUFragmentSize == 0) |
|
443 { |
|
444 // For udeb builds we know that this PDU can fit into the ACL buffer so just set the fragment size |
|
445 // to be the ACL buffer size to allow logic below to work. For urel builds this can also recover the |
|
446 // situation if the debug assert fails above, just not using optimal performance. |
|
447 iPDUFragmentSize = aACLMTU; |
|
448 } |
|
449 |
|
450 // Ensure that the optimal fragment size will fit into the ACL buffer. |
|
451 __ASSERT_DEBUG(aACLMTU >= iPDUFragmentSize, Panic(EL2CAPOptimalFragmentSizeTooBigForACLBuffer)); |
|
452 |
|
453 TFragmentSenderStatus rStatus = EFragmentOK; |
|
454 |
|
455 TUint8 flags = iCurrentWriteIndex ? KContinuingHLFragment : KFirstHLFragment; |
|
456 |
|
457 TInt fragLength = Min(iPDULength - iCurrentWriteIndex, Min(iPDUFragmentSize, aACLMTU)); |
|
458 |
|
459 // The 'Write' returns the number of fragments (NOT bytes) |
|
460 // that will be sent. This is typically either 0 or 1. |
|
461 TUint fragmentsSent = aSender.Write(iPDUBuffer->Mid(iCurrentWriteIndex, fragLength), flags, &iPDU->ElementHandle()); |
|
462 if(!fragmentsSent) |
|
463 { |
|
464 rStatus = EFlowControlledOff; |
|
465 } |
|
466 else |
|
467 { |
|
468 iCurrentWriteIndex += fragLength; |
|
469 iCurrentFragmentID++; |
|
470 } |
|
471 |
|
472 // Check if the PDU has been fully sent. |
|
473 if(iCurrentWriteIndex >= iPDULength) |
|
474 { |
|
475 rStatus = EFragmentationComplete; |
|
476 |
|
477 // Inform the PDU that it has been sent. |
|
478 iPDU->PDUSendPending(iCurrentFragmentID); |
|
479 |
|
480 // Reset the internal state of this sender. |
|
481 Reset(); |
|
482 } |
|
483 return rStatus; |
|
484 } |
|
485 |
|
486 void HFragmentedPDUSender::Reset() |
|
487 { |
|
488 LOG_FUNC |
|
489 iPDU = NULL; |
|
490 iPDULength = iCurrentWriteIndex = 0; |
|
491 iCurrentFragmentID = 0; |
|
492 iPDUFragmentSize = 0; |
|
493 } |
|
494 |
|
495 void HFragmentedPDUSender::CheckForFlushed() |
|
496 { |
|
497 LOG_FUNC |
|
498 // Check if the PDU currently being sent(if there is one) |
|
499 // needs to be flushed. |
|
500 if(iPDU) |
|
501 { |
|
502 if(iPDU->IsPDUFlushed()) |
|
503 { |
|
504 // Inform the PDU that it has been sent. |
|
505 iPDU->PDUSendPending(iCurrentFragmentID); |
|
506 |
|
507 // Reset the internal state of this sender. |
|
508 Reset(); |
|
509 } |
|
510 } |
|
511 } |
|
512 |
|
513 void HFragmentedPDUSender::PDUSenderFailed() |
|
514 { |
|
515 LOG_FUNC |
|
516 if(iPDU) |
|
517 { |
|
518 // Inform the PDU that it has been sent. |
|
519 iPDU->PDUSendPending(iCurrentFragmentID); |
|
520 |
|
521 // Reset the internal state of this sender. |
|
522 Reset(); |
|
523 } |
|
524 } |
|
525 |
|
526 |
|
527 |
|
528 // |
|
529 // Basic frame PDU class. |
|
530 // |
|
531 HBFramePDU::HBFramePDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize) |
|
532 : HL2CapPDU(aPDUData, aOptimalFragmentSize) |
|
533 { |
|
534 LOG_FUNC |
|
535 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EBFrame, |
|
536 L2capDebugInfo::EAllocated)); |
|
537 } |
|
538 |
|
539 HBFramePDU::~HBFramePDU() |
|
540 { |
|
541 LOG_FUNC |
|
542 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EBFrame, |
|
543 L2capDebugInfo::EDeleted)); |
|
544 } |
|
545 |
|
546 HBFramePDU* HBFramePDU::New(RMBufChain& aPayloadData, TInt aOptimalFragmentSize) |
|
547 { |
|
548 LOG_STATIC_FUNC |
|
549 HBFramePDU* self = NULL; |
|
550 TRAPD(rerr, aPayloadData.PrependL(KPDUHeaderLength)); |
|
551 if(rerr == KErrNone) |
|
552 { |
|
553 self = new HBFramePDU(aPayloadData, aOptimalFragmentSize); |
|
554 } |
|
555 |
|
556 if(self) |
|
557 { |
|
558 self->WritePDUPayloadLength(); |
|
559 } |
|
560 return self; |
|
561 } |
|
562 |
|
563 void HBFramePDU::DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) |
|
564 { |
|
565 LOG_FUNC |
|
566 aPDUHandler.HandleOutgoingBFrame(this); |
|
567 } |
|
568 |
|
569 void HBFramePDU::AppendPayloadToBuffer(RMBufChain& aSDUData) |
|
570 { |
|
571 LOG_FUNC |
|
572 // Remove header and trailing bytes. |
|
573 iPDUData.TrimStart(KPDUHeaderLength); |
|
574 aSDUData.Append(iPDUData); |
|
575 } |
|
576 |
|
577 /*static*/ void HBFramePDU::RemoveHeaderBytes(RMBufChain& aPDU) |
|
578 { |
|
579 LOG_STATIC_FUNC |
|
580 // Remove header bytes. |
|
581 aPDU.TrimStart(KPDUHeaderLength); |
|
582 } |
|
583 |
|
584 void HBFramePDU::SendComplete() |
|
585 { |
|
586 LOG_FUNC |
|
587 L2CAP_DEBUG_PDU(PDUTimer(L2capDebugInfo::EPDUSent, this, PDUCID())); |
|
588 } |
|
589 |
|
590 |
|
591 // |
|
592 // Information frame PDU class. |
|
593 // |
|
594 HIFramePDU::HIFramePDU(RMBufChain& aPDUData) |
|
595 : HL2CapPDU(aPDUData, 0), |
|
596 iTransmissionCount(0), |
|
597 iAcked(EFalse) |
|
598 { |
|
599 LOG_FUNC |
|
600 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EIFrame, |
|
601 L2capDebugInfo::EAllocated)); |
|
602 } |
|
603 |
|
604 HIFramePDU::~HIFramePDU() |
|
605 { |
|
606 LOG_FUNC |
|
607 LOG1(_L("Deleting TxSeq = %d"), TxSeqNumber()); |
|
608 |
|
609 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EIFrame, |
|
610 L2capDebugInfo::EDeleted)); |
|
611 } |
|
612 |
|
613 |
|
614 HIFramePDU* HIFramePDU::New(RMBufChain& aPayloadData, TL2CapSAR aPduSAR) |
|
615 { |
|
616 LOG_STATIC_FUNC |
|
617 TInt rerr = KErrNone; |
|
618 HIFramePDU* self = NULL; |
|
619 |
|
620 switch(aPduSAR) |
|
621 { |
|
622 case EStartOfL2CapSDU: |
|
623 TRAP(rerr, aPayloadData.PrependL(KPDUHeaderLength + KControlFieldLength + KSDULengthFieldLength)); |
|
624 break; |
|
625 case EUnsegmentedL2CapSDU: |
|
626 case EEndOfL2CapSDU: |
|
627 case EContinuationOfL2CapSDU: |
|
628 TRAP(rerr, aPayloadData.PrependL(KPDUHeaderLength + KControlFieldLength)); |
|
629 break; |
|
630 |
|
631 default: |
|
632 Panic(EL2CAPInvalidPDUSAR); |
|
633 break; |
|
634 }; |
|
635 |
|
636 if(rerr == KErrNone) |
|
637 { |
|
638 TRAP(rerr, aPayloadData.AppendL(KFCSFieldLength)); |
|
639 } |
|
640 |
|
641 if(rerr == KErrNone) |
|
642 { |
|
643 self = new HIFramePDU(aPayloadData); |
|
644 if(self) |
|
645 { |
|
646 self->WritePDUPayloadLength(); |
|
647 self->SetIFrameControlDefault(); |
|
648 self->SetSAR(aPduSAR); |
|
649 } |
|
650 } |
|
651 |
|
652 return self; |
|
653 } |
|
654 |
|
655 void HIFramePDU::DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) |
|
656 { |
|
657 LOG_FUNC |
|
658 aPDUHandler.HandleOutgoingIFrame(this); |
|
659 } |
|
660 |
|
661 // Message Accessors. |
|
662 /*static*/ TBool HIFramePDU::IFrameIdentifier(const RMBufChain& aPDU) |
|
663 { |
|
664 LOG_STATIC_FUNC |
|
665 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
666 Panic(EL2CapPDUInvalidLength)); |
|
667 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
668 return (!(ctrl & KCtrlFrameTypeMask)); |
|
669 } |
|
670 |
|
671 /*static*/ TUint8 HIFramePDU::TxSeqNumber(const RMBufChain& aPDU) |
|
672 { |
|
673 LOG_STATIC_FUNC |
|
674 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
675 Panic(EL2CapPDUInvalidLength)); |
|
676 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
677 return static_cast<TUint8>((ctrl & KCtrlTxSeqMask) >> KCtrlTxSeqShift); |
|
678 } |
|
679 |
|
680 /*static*/ TBool HIFramePDU::FinalBit(const RMBufChain& aPDU) |
|
681 { |
|
682 LOG_STATIC_FUNC |
|
683 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
684 Panic(EL2CapPDUInvalidLength)); |
|
685 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
686 return (ctrl & KCtrlFinalBitMask); |
|
687 } |
|
688 |
|
689 void HIFramePDU::SetFinalBit(TBool aFinalBit) |
|
690 { |
|
691 LOG_FUNC |
|
692 SetRetransmitDisable(aFinalBit); |
|
693 } |
|
694 |
|
695 void HIFramePDU::SetTxSeqNumber(TUint8 aTxSeqNum) |
|
696 { |
|
697 LOG_FUNC |
|
698 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
699 Panic(EL2CapPDUInvalidLength)); |
|
700 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
701 ctrl &= ~KCtrlTxSeqMask; |
|
702 ctrl |= (aTxSeqNum << KCtrlTxSeqShift); |
|
703 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
704 } |
|
705 |
|
706 /*static*/ TBool HIFramePDU::RetransmitDisable(const RMBufChain& aPDU) |
|
707 { |
|
708 LOG_STATIC_FUNC |
|
709 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
710 Panic(EL2CapPDUInvalidLength)); |
|
711 return (LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset) & KCtrlReTxDisableMask); |
|
712 } |
|
713 |
|
714 void HIFramePDU::SetRetransmitDisable(TBool aReTxDisable) |
|
715 { |
|
716 LOG_FUNC |
|
717 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
718 Panic(EL2CapPDUInvalidLength)); |
|
719 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
720 ctrl &= ~KCtrlReTxDisableMask; |
|
721 ctrl |= (aReTxDisable << KCtrlReTxDisableShift); |
|
722 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
723 } |
|
724 |
|
725 /*static*/ TUint8 HIFramePDU::ReqSeqNumber(const RMBufChain& aPDU) |
|
726 { |
|
727 LOG_STATIC_FUNC |
|
728 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
729 Panic(EL2CapPDUInvalidLength)); |
|
730 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
731 return static_cast<TUint8>((ctrl & KCtrlReqSeqMask) >> KCtrlReqSeqShift); |
|
732 } |
|
733 |
|
734 void HIFramePDU::SetReqSeqNumber(TUint8 aReqSeqNum) |
|
735 { |
|
736 LOG_STATIC_FUNC |
|
737 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
738 Panic(EL2CapPDUInvalidLength)); |
|
739 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
740 ctrl &= ~KCtrlReqSeqMask; |
|
741 ctrl |= (aReqSeqNum << KCtrlReqSeqShift); |
|
742 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
743 } |
|
744 |
|
745 /*static*/ TBool HIFramePDU::IsStartOfSDU(const RMBufChain& aPDU) |
|
746 { |
|
747 LOG_STATIC_FUNC |
|
748 return (SAR(aPDU) == EUnsegmentedL2CapSDU || SAR(aPDU) == EStartOfL2CapSDU); |
|
749 } |
|
750 |
|
751 |
|
752 /*static*/ TL2CapSAR HIFramePDU::SAR(const RMBufChain& aPDU) |
|
753 { |
|
754 LOG_STATIC_FUNC |
|
755 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
756 Panic(EL2CapPDUInvalidLength)); |
|
757 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
758 return TL2CapSAR((ctrl & KCtrlSARMask) >> KCtrlSARShift); |
|
759 } |
|
760 |
|
761 void HIFramePDU::SetSAR(TL2CapSAR aSARValue) |
|
762 { |
|
763 LOG_FUNC |
|
764 __ASSERT_DEBUG(iPDUData.First() && (iPDUData.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
765 Panic(EL2CapPDUInvalidLength)); |
|
766 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
767 ctrl &= ~KCtrlSARMask; |
|
768 TUint8 sar = static_cast<TUint8>(aSARValue); |
|
769 ctrl |= (sar << KCtrlSARShift); |
|
770 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
771 } |
|
772 |
|
773 /*static*/ TUint16 HIFramePDU::SDUSize(const RMBufChain& aPDU) |
|
774 { |
|
775 LOG_STATIC_FUNC |
|
776 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KSDULengthFieldLength + KSDULengthFieldByteOffset, |
|
777 Panic(EL2CapPDUInvalidLength)); |
|
778 |
|
779 return LittleEndian::Get16((aPDU.First())->Ptr()+KSDULengthFieldByteOffset); |
|
780 } |
|
781 |
|
782 void HIFramePDU::SetSDUSize(TUint16 aSDUSize) |
|
783 { |
|
784 LOG_FUNC |
|
785 LittleEndian::Put16((iPDUData.First())->Ptr()+KSDULengthFieldByteOffset, aSDUSize); |
|
786 } |
|
787 |
|
788 void HIFramePDU::CalculateAndSetFCS() |
|
789 { |
|
790 LOG_FUNC |
|
791 |
|
792 TUint16 fcs = HL2CapPDU::CalcCRC(); |
|
793 |
|
794 RMBuf* buf = iPDUData.Last(); |
|
795 if(buf->Length() < KFCSFieldLength) |
|
796 { |
|
797 // This can only mean that the last buffer contains one byte. |
|
798 // Get a pointer to the penultimate buffer. |
|
799 buf = iPDUData.First(); |
|
800 for(TInt i=1;i<(iPDUData.NumBufs() - 1);i++) |
|
801 { |
|
802 buf = buf->Next(); |
|
803 } |
|
804 buf->Put(static_cast<TUint8>(fcs & 0x00ff), buf->Length() - 1); |
|
805 fcs = static_cast<TUint16>(fcs >> 8); |
|
806 buf = buf->Next(); |
|
807 buf->Put(static_cast<TUint8>(fcs & 0x00ff), 0); |
|
808 } |
|
809 else |
|
810 { |
|
811 LittleEndian::Put16(buf->Ptr()+buf->Length()-KFCSFieldLength, fcs); |
|
812 } |
|
813 } |
|
814 |
|
815 /*static*/ TBool HIFramePDU::CheckFCS(const RMBufChain& aPDU) |
|
816 { |
|
817 LOG_STATIC_FUNC |
|
818 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KPDUHeaderLength + KFCSFieldLength, |
|
819 Panic(EL2CapPDUInvalidLength)); |
|
820 |
|
821 TUint16 msgFCS; |
|
822 RMBuf* buf = aPDU.Last(); |
|
823 if(buf->Length() < KFCSFieldLength) |
|
824 { |
|
825 // This can only mean that the last buffer contains one byte. |
|
826 msgFCS = static_cast<TUint16>((buf->Get(0)) << 8); |
|
827 |
|
828 // Get a pointer to the penultimate buffer. |
|
829 const RMBuf* cBuf = aPDU.First(); |
|
830 for(TInt i=1;i<(aPDU.NumBufs() - 1);i++) |
|
831 { |
|
832 cBuf = cBuf->Next(); |
|
833 } |
|
834 msgFCS |= cBuf->Get(cBuf->Length() - 1); |
|
835 } |
|
836 else |
|
837 { |
|
838 msgFCS = LittleEndian::Get16(buf->Ptr()+buf->Length()-KFCSFieldLength); |
|
839 } |
|
840 |
|
841 return (msgFCS == HL2CapPDU::CalcCRC(aPDU)); |
|
842 } |
|
843 |
|
844 TBool HIFramePDU::CheckFCS() |
|
845 { |
|
846 LOG_FUNC |
|
847 return CheckFCS(iPDUData); |
|
848 } |
|
849 |
|
850 void HIFramePDU::SetIFrameControlDefault() |
|
851 { |
|
852 LOG_FUNC |
|
853 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, KIFrameControlDefault); |
|
854 } |
|
855 |
|
856 |
|
857 void HIFramePDU::AppendPayloadToBuffer(RMBufChain& aSDUData) |
|
858 { |
|
859 LOG_FUNC |
|
860 // Remove header and trailing bytes. |
|
861 if(SAR() == EStartOfL2CapSDU) |
|
862 { |
|
863 iPDUData.TrimStart(KPDUHeaderLength + KControlFieldLength + KSDULengthFieldLength); |
|
864 } |
|
865 else |
|
866 { |
|
867 iPDUData.TrimStart(KPDUHeaderLength + KControlFieldLength); |
|
868 } |
|
869 iPDUData.TrimEnd(iPDUData.Length()-KFCSFieldLength); |
|
870 aSDUData.Append(iPDUData); |
|
871 } |
|
872 |
|
873 /*static*/ void HIFramePDU::RemoveHeaderAndFCSBytes(RMBufChain& aPDU) |
|
874 { |
|
875 // Remove header and trailing bytes. |
|
876 if(SAR(aPDU) == EStartOfL2CapSDU) |
|
877 { |
|
878 aPDU.TrimStart(KPDUHeaderLength + KControlFieldLength + KSDULengthFieldLength); |
|
879 } |
|
880 else |
|
881 { |
|
882 aPDU.TrimStart(KPDUHeaderLength + KControlFieldLength); |
|
883 } |
|
884 aPDU.TrimEnd(aPDU.Length()-KFCSFieldLength); |
|
885 } |
|
886 |
|
887 /*static*/ TInt HIFramePDU::CheckPayloadDecode(const RMBufChain& aPDU) |
|
888 { |
|
889 LOG_STATIC_FUNC |
|
890 TInt rerr = KErrNone; |
|
891 |
|
892 if(PDUCID(aPDU) < KL2CapDynamicCIDStart) |
|
893 { |
|
894 rerr = KErrCorrupt; |
|
895 } |
|
896 else if(!CheckFCS(aPDU)) |
|
897 { |
|
898 rerr = KErrCorrupt; |
|
899 } |
|
900 return rerr; |
|
901 } |
|
902 |
|
903 /*static*/ TInt HIFramePDU::CheckLengthWithinLimits(const RMBufChain& aPDU, TUint16 aMps) |
|
904 { |
|
905 LOG_STATIC_FUNC |
|
906 // Check that the PDU size is >= than minimal and that the information payload size is <= MPS. |
|
907 |
|
908 TInt err = KErrNone; |
|
909 TBool hasSduLength = (SAR(aPDU) == EStartOfL2CapSDU); |
|
910 |
|
911 TInt infoPayloadSize = PDUPayloadLength(aPDU) - KControlFieldLength - KFCSFieldLength; |
|
912 if (hasSduLength) |
|
913 { |
|
914 infoPayloadSize -= KSDULengthFieldLength; |
|
915 } |
|
916 |
|
917 if (infoPayloadSize > aMps) |
|
918 { |
|
919 err = KErrL2CAPIncomingIFrameTooBig; |
|
920 } |
|
921 else |
|
922 { |
|
923 if (aPDU.Length() < (KPDUHeaderLength + KControlFieldLength + KFCSFieldLength)) |
|
924 { |
|
925 err = KErrL2CAPIncomingIFrameTooSmall; |
|
926 } |
|
927 } |
|
928 |
|
929 return err; |
|
930 } |
|
931 |
|
932 /*static*/ TInt HIFramePDU::CheckStartSduLength(const RMBufChain& aPDU, TUint16 aMtu) |
|
933 { |
|
934 LOG_STATIC_FUNC |
|
935 TInt err = KErrNone; |
|
936 |
|
937 if (aPDU.Length() < (KPDUHeaderLength + KControlFieldLength + KSDULengthFieldLength + KFCSFieldLength)) |
|
938 { |
|
939 err = KErrL2CAPIncomingIFrameTooSmall; |
|
940 } |
|
941 else if (SDUSize(aPDU) > aMtu) |
|
942 { |
|
943 err = KErrL2CAPIncomingSduTooBig; |
|
944 } |
|
945 return err; |
|
946 } |
|
947 |
|
948 void HIFramePDU::SendComplete() |
|
949 { |
|
950 LOG_FUNC |
|
951 iTransmissionCount++; |
|
952 |
|
953 #ifdef _DEBUG |
|
954 if(SAR() == EEndOfL2CapSDU || SAR() == EUnsegmentedL2CapSDU) |
|
955 { |
|
956 L2CAP_DEBUG_PDU(PDUTimer(L2capDebugInfo::EPDUSent, this, PDUCID())); |
|
957 } |
|
958 #endif |
|
959 } |
|
960 |
|
961 |
|
962 // |
|
963 // Supervisory frame PDU class. |
|
964 // |
|
965 HSFramePDU* HSFramePDU::New(TSupervisoryFunction aFunction) |
|
966 { |
|
967 LOG_STATIC_FUNC |
|
968 TInt rerr = KErrNone; |
|
969 HSFramePDU* self = NULL; |
|
970 |
|
971 RMBufChain frameBuffer; |
|
972 TRAP(rerr, frameBuffer.AllocL(KSFrameLength)); |
|
973 |
|
974 if(rerr == KErrNone) |
|
975 { |
|
976 self = new HSFramePDU(frameBuffer); |
|
977 if(self) |
|
978 { |
|
979 self->WritePDUPayloadLength(); |
|
980 self->SetSFrameControlDefault(); |
|
981 self->SetSupervisoryFunction(aFunction); |
|
982 } |
|
983 else |
|
984 { |
|
985 frameBuffer.Free(); |
|
986 } |
|
987 } |
|
988 return self; |
|
989 } |
|
990 |
|
991 HSFramePDU* HSFramePDU::NewL(TSupervisoryFunction aFunction) |
|
992 { |
|
993 LOG_STATIC_FUNC |
|
994 HSFramePDU* self = New(aFunction); |
|
995 if (self == NULL) |
|
996 { |
|
997 LEAVEL(KErrNoMemory); |
|
998 } |
|
999 return self; |
|
1000 } |
|
1001 |
|
1002 HSFramePDU::HSFramePDU(RMBufChain& aPDUData) |
|
1003 : HL2CapPDU(aPDUData, 0) |
|
1004 { |
|
1005 LOG_FUNC |
|
1006 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ESFrame, |
|
1007 L2capDebugInfo::EAllocated)); |
|
1008 } |
|
1009 |
|
1010 HSFramePDU::~HSFramePDU() |
|
1011 { |
|
1012 LOG_FUNC |
|
1013 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ESFrame, |
|
1014 L2capDebugInfo::EDeleted)); |
|
1015 } |
|
1016 |
|
1017 void HSFramePDU::DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) |
|
1018 { |
|
1019 LOG_FUNC |
|
1020 aPDUHandler.HandleOutgoingSFrame(this); |
|
1021 } |
|
1022 |
|
1023 /*static*/ TInt HSFramePDU::CheckLengthField(const RMBufChain& aPDU) |
|
1024 { |
|
1025 LOG_STATIC_FUNC |
|
1026 TInt err = KErrNone; |
|
1027 |
|
1028 // The length field doesn't include the L2CAP Basic header. |
|
1029 if (PDUPayloadLength(aPDU) != KControlFieldLength + KFCSFieldLength) |
|
1030 { |
|
1031 err = KErrL2CAPInvalidIncomingSFrameSize; |
|
1032 } |
|
1033 |
|
1034 return err; |
|
1035 } |
|
1036 |
|
1037 /*static*/ TInt HSFramePDU::CheckPayloadDecode(RMBufChain& aPDU) |
|
1038 { |
|
1039 LOG_STATIC_FUNC |
|
1040 TInt rerr = KErrNone; |
|
1041 |
|
1042 if(!CheckFCS(aPDU)) |
|
1043 { |
|
1044 rerr = KErrCorrupt; |
|
1045 } |
|
1046 |
|
1047 return rerr; |
|
1048 } |
|
1049 |
|
1050 /*static*/ TSupervisoryFunction HSFramePDU::SupervisoryFunction(const RMBufChain& aPDU) |
|
1051 { |
|
1052 LOG_STATIC_FUNC |
|
1053 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
1054 Panic(EL2CapPDUInvalidLength)); |
|
1055 |
|
1056 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
1057 return TSupervisoryFunction((ctrl & KCtrlSupervisoryMask) >> 2); |
|
1058 } |
|
1059 |
|
1060 /*static*/ TUint8 HSFramePDU::ReqSeqNumber(const RMBufChain& aPDU) |
|
1061 { |
|
1062 LOG_STATIC_FUNC |
|
1063 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
1064 Panic(EL2CapPDUInvalidLength)); |
|
1065 |
|
1066 TUint16 ctrl = LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset); |
|
1067 return static_cast<TUint8>((ctrl & KCtrlReqSeqMask) >> 8); |
|
1068 } |
|
1069 |
|
1070 void HSFramePDU::SetSupervisoryFunction(TSupervisoryFunction aSupervisoryFunction) |
|
1071 { |
|
1072 LOG_FUNC |
|
1073 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
1074 ctrl &= ~KCtrlSupervisoryMask; |
|
1075 ctrl |= (aSupervisoryFunction << 2); |
|
1076 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
1077 } |
|
1078 |
|
1079 /*static*/ TBool HSFramePDU::RetransmitDisable(const RMBufChain& aPDU) |
|
1080 { |
|
1081 LOG_STATIC_FUNC |
|
1082 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
1083 Panic(EL2CapPDUInvalidLength)); |
|
1084 |
|
1085 return (LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset) & KCtrlReTxDisableMask); |
|
1086 } |
|
1087 |
|
1088 /*static*/ TBool HSFramePDU::FinalBit(const RMBufChain& aPDU) |
|
1089 { |
|
1090 LOG_STATIC_FUNC |
|
1091 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
1092 Panic(EL2CapPDUInvalidLength)); |
|
1093 |
|
1094 return (LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset) & KCtrlFinalBitMask); |
|
1095 } |
|
1096 |
|
1097 /*static*/ TBool HSFramePDU::PollBit(const RMBufChain& aPDU) |
|
1098 { |
|
1099 LOG_STATIC_FUNC |
|
1100 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KControlFieldLength + KControlFieldByteOffset, |
|
1101 Panic(EL2CapPDUInvalidLength)); |
|
1102 |
|
1103 return (LittleEndian::Get16((aPDU.First())->Ptr()+KControlFieldByteOffset) & KCtrlPollBitMask); |
|
1104 } |
|
1105 |
|
1106 void HSFramePDU::SetFinalBit(TBool aFinalBit) |
|
1107 { |
|
1108 LOG_FUNC |
|
1109 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
1110 ctrl &= ~KCtrlFinalBitMask; |
|
1111 ctrl |= (aFinalBit << 7); |
|
1112 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
1113 } |
|
1114 |
|
1115 void HSFramePDU::SetPollBit(TBool aPollBit) |
|
1116 { |
|
1117 LOG_FUNC |
|
1118 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
1119 ctrl &= ~KCtrlPollBitMask; |
|
1120 ctrl |= (aPollBit << 4); |
|
1121 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
1122 } |
|
1123 |
|
1124 void HSFramePDU::SetRetransmitDisable(TBool aReTxDisable) |
|
1125 { |
|
1126 LOG_FUNC |
|
1127 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
1128 ctrl &= ~KCtrlReTxDisableMask; |
|
1129 ctrl |= (aReTxDisable << 7); |
|
1130 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
1131 } |
|
1132 |
|
1133 void HSFramePDU::SetReqSeqNumber(TUint8 aReqSeqNum) |
|
1134 { |
|
1135 LOG_FUNC |
|
1136 TUint16 ctrl = LittleEndian::Get16((iPDUData.First())->Ptr()+KControlFieldByteOffset); |
|
1137 ctrl &= ~KCtrlReqSeqMask; |
|
1138 ctrl |= (aReqSeqNum << 8); |
|
1139 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, ctrl); |
|
1140 } |
|
1141 |
|
1142 void HSFramePDU::CalculateAndSetFCS() |
|
1143 { |
|
1144 LOG_FUNC |
|
1145 |
|
1146 TUint16 fcs = HL2CapPDU::CalcCRC(); |
|
1147 |
|
1148 RMBuf* lastBuf = iPDUData.Last(); |
|
1149 if(lastBuf->Length() < KFCSFieldLength) |
|
1150 { |
|
1151 // This can only be 8 bytes long. Align the buffer. |
|
1152 iPDUData.Align(iPDUData.Length()); |
|
1153 lastBuf = iPDUData.Last(); |
|
1154 } |
|
1155 LittleEndian::Put16(lastBuf->Ptr()+lastBuf->Length()-KFCSFieldLength, fcs); |
|
1156 } |
|
1157 |
|
1158 /*static*/ TBool HSFramePDU::CheckFCS(RMBufChain& aPDU) |
|
1159 { |
|
1160 LOG_STATIC_FUNC |
|
1161 __ASSERT_DEBUG(aPDU.First() && (aPDU.First())->Length() >= KPDUHeaderLength + KFCSFieldLength, |
|
1162 Panic(EL2CapPDUInvalidLength)); |
|
1163 |
|
1164 TUint16 msgFCS; |
|
1165 RMBuf* buf = aPDU.Last(); |
|
1166 if(buf->Length() < KFCSFieldLength) |
|
1167 { |
|
1168 // This can only be 8 bytes long. Align the buffer. |
|
1169 aPDU.Align(aPDU.Length()); |
|
1170 buf = aPDU.Last(); |
|
1171 } |
|
1172 |
|
1173 msgFCS = LittleEndian::Get16(buf->Ptr()+buf->Length()-KFCSFieldLength); |
|
1174 |
|
1175 return (msgFCS == HL2CapPDU::CalcCRC(aPDU)); |
|
1176 } |
|
1177 |
|
1178 TBool HSFramePDU::CheckFCS() |
|
1179 { |
|
1180 LOG_FUNC |
|
1181 return CheckFCS(iPDUData); |
|
1182 } |
|
1183 |
|
1184 void HSFramePDU::SetSFrameControlDefault() |
|
1185 { |
|
1186 LOG_FUNC |
|
1187 LittleEndian::Put16((iPDUData.First())->Ptr()+KControlFieldByteOffset, KSFrameControlDefault); |
|
1188 } |
|
1189 |
|
1190 |
|
1191 // |
|
1192 // Group frame PDU class. |
|
1193 // |
|
1194 HGFramePDU::HGFramePDU(RMBufChain& aPDUData) |
|
1195 : HL2CapPDU(aPDUData, 0) |
|
1196 { |
|
1197 LOG_FUNC |
|
1198 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EGFrame, |
|
1199 L2capDebugInfo::EAllocated)); |
|
1200 } |
|
1201 |
|
1202 HGFramePDU::~HGFramePDU() |
|
1203 { |
|
1204 LOG_FUNC |
|
1205 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EGFrame, |
|
1206 L2capDebugInfo::EDeleted)); |
|
1207 } |
|
1208 |
|
1209 void HGFramePDU::DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) |
|
1210 { |
|
1211 LOG_FUNC |
|
1212 aPDUHandler.HandleOutgoingGFrame(this); |
|
1213 } |
|
1214 |
|
1215 void HGFramePDU::AppendPayloadToBuffer(RMBufChain& aSDUData) |
|
1216 { |
|
1217 LOG_FUNC |
|
1218 // Remove header and trailing bytes. |
|
1219 iPDUData.TrimStart(KPDUHeaderLength + KGFramePSMLength); |
|
1220 aSDUData.Append(iPDUData); |
|
1221 } |
|
1222 |
|
1223 |
|
1224 // |
|
1225 // Control frame PDU class. |
|
1226 // |
|
1227 /*static*/ HCFramePDU* HCFramePDU::New(TInt aOptimalFragmentSize) |
|
1228 { |
|
1229 LOG_STATIC_FUNC |
|
1230 RMBufChain buf; |
|
1231 HCFramePDU* cFrame = NULL; |
|
1232 |
|
1233 TRAPD(err, buf.AllocL(KCFrameHeaderLength)); |
|
1234 if(err == KErrNone) |
|
1235 { |
|
1236 cFrame = new HCFramePDU(buf, aOptimalFragmentSize); |
|
1237 if(cFrame) |
|
1238 { |
|
1239 cFrame->SetPDUCID(KL2CapSignallingCID); |
|
1240 cFrame->WritePDUPayloadLength(); |
|
1241 } |
|
1242 else |
|
1243 { |
|
1244 buf.Free(); |
|
1245 } |
|
1246 } |
|
1247 return cFrame; |
|
1248 } |
|
1249 |
|
1250 HCFramePDU::HCFramePDU(RMBufChain& aPDUData, TInt aOptimalFragmentSize) |
|
1251 : HL2CapPDU(aPDUData, aOptimalFragmentSize), |
|
1252 iCommands(_FOFF(HL2CapCommand, iLink)), |
|
1253 iCommandIter(iCommands) |
|
1254 { |
|
1255 LOG_STATIC_FUNC |
|
1256 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ECFrame, |
|
1257 L2capDebugInfo::EAllocated)); |
|
1258 } |
|
1259 |
|
1260 HCFramePDU::~HCFramePDU() |
|
1261 { |
|
1262 LOG_FUNC |
|
1263 __ASSERT_DEBUG(iCommands.IsEmpty(), Panic(EL2CAPDeleteCFrameWhileContainingCommands)); |
|
1264 |
|
1265 while(!iCommands.IsEmpty()) |
|
1266 { |
|
1267 HL2CapCommand *cmd = iCommands.First(); |
|
1268 cmd->iLink.Deque(); |
|
1269 delete cmd; |
|
1270 } |
|
1271 |
|
1272 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::ECFrame, |
|
1273 L2capDebugInfo::EDeleted)); |
|
1274 } |
|
1275 |
|
1276 void HCFramePDU::DeliverOutgoingPDUDoubleDispatch(MOutgoingPDUHandler& aPDUHandler) |
|
1277 { |
|
1278 LOG_FUNC |
|
1279 aPDUHandler.HandleOutgoingCFrame(this); |
|
1280 } |
|
1281 |
|
1282 TInt HCFramePDU::CheckDecode() |
|
1283 { |
|
1284 LOG_FUNC |
|
1285 TInt rerr = KErrNone; |
|
1286 if(iPDUData.Length() != (PDUPayloadLength() + KPDUHeaderLength)) |
|
1287 { |
|
1288 rerr = KErrCorrupt; |
|
1289 } |
|
1290 else |
|
1291 { |
|
1292 rerr = CheckPayloadDecode(); |
|
1293 } |
|
1294 return rerr; |
|
1295 } |
|
1296 |
|
1297 TInt HCFramePDU::CheckPayloadDecode() |
|
1298 { |
|
1299 LOG_FUNC |
|
1300 return CreateCommands(); |
|
1301 } |
|
1302 |
|
1303 |
|
1304 // Takes this original PDU and extracts out a list of the contained Command Frames |
|
1305 // Upon completion the original PDU will be freed, but this class will hold a list |
|
1306 // CFrames. |
|
1307 TInt HCFramePDU::CreateCommands() |
|
1308 { |
|
1309 LOG_FUNC |
|
1310 // Trim off the standard header. |
|
1311 iPDUData.TrimStart(KCFrameHeaderLength); |
|
1312 |
|
1313 HL2CapCommand* cmd = NULL; |
|
1314 |
|
1315 // If a command is decoded it will be removed from the |
|
1316 // start of the buffer. |
|
1317 TInt err = KErrNone; |
|
1318 while(err == KErrNone) |
|
1319 { |
|
1320 err = HL2CapCommand::DecodeCommand(iPDUData, cmd); |
|
1321 LOG1(_L("HCFramePDU::CreateCommands, DecodeCommand returned %d"), err); |
|
1322 |
|
1323 if(err == KErrNone && cmd) |
|
1324 { |
|
1325 iCommands.AddLast(*cmd); |
|
1326 } |
|
1327 } |
|
1328 |
|
1329 // A C-Frame must contain at least one command. |
|
1330 if(iCommands.IsEmpty()) |
|
1331 { |
|
1332 err = KErrCorrupt; |
|
1333 } |
|
1334 return (err == KErrCompletion ? KErrNone : err); |
|
1335 } |
|
1336 |
|
1337 |
|
1338 HL2CapCommand* HCFramePDU::FirstCommand() |
|
1339 { |
|
1340 LOG_FUNC |
|
1341 iCommandIter.SetToFirst(); |
|
1342 return iCommandIter++; |
|
1343 } |
|
1344 |
|
1345 HL2CapCommand* HCFramePDU::NextCommand() |
|
1346 { |
|
1347 LOG_FUNC |
|
1348 return iCommandIter++; |
|
1349 } |
|
1350 |
|
1351 |
|
1352 TInt HCFramePDU::AddCommand(HL2CapCommand& aCommand, CL2CAPMux& aMuxer) |
|
1353 { |
|
1354 LOG_FUNC |
|
1355 TInt rerr = KErrNone; |
|
1356 // Check if there is room in the PDU. |
|
1357 if((aCommand.CommandLength() + PDUPayloadLength()) <= aMuxer.SigMTU()) |
|
1358 { |
|
1359 // Add this command onto end of PDU buff |
|
1360 RMBufChain buf; |
|
1361 rerr = aCommand.GetCommand(aMuxer, buf); |
|
1362 if(rerr == KErrNone) |
|
1363 { |
|
1364 iPDUData.Append(buf); |
|
1365 |
|
1366 WritePDUPayloadLength(); |
|
1367 } |
|
1368 } |
|
1369 else |
|
1370 { |
|
1371 rerr = KErrCompletion; |
|
1372 } |
|
1373 return rerr; |
|
1374 } |