|
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 |
|
18 #include <e32base.h> |
|
19 |
|
20 #include "L2CapDataController.h" |
|
21 #include "L2CapEnhancedDataController.h" |
|
22 |
|
23 #include "L2CapSDUQueue.h" |
|
24 #include "l2signalmgr.h" |
|
25 |
|
26 #include "btsockettimer.h" |
|
27 |
|
28 #include "l2util.h" |
|
29 #include "L2CapDebugControlInterface.h" |
|
30 |
|
31 #include "l2constants.h" |
|
32 |
|
33 #ifdef __FLOG_ACTIVE |
|
34 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP_DATA_CONTROLLER); |
|
35 #endif |
|
36 |
|
37 using namespace L2CapDataUtils; |
|
38 |
|
39 // ***** CL2CapBasicDataController Implementation |
|
40 /*static*/ CL2CapBasicDataController* CL2CapBasicDataController::NewL(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig) |
|
41 { |
|
42 LOG_STATIC_FUNC |
|
43 // Create the required data controller. |
|
44 CL2CapBasicDataController* controller = NULL; |
|
45 |
|
46 switch(aConfig->LinkMode()) |
|
47 { |
|
48 case EL2CAPBasicMode: |
|
49 LOG(_L("FEC L2CapBasicDataController Basic Mode")) |
|
50 controller = new(ELeave) CL2CapBasicDataController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig, ETrue); |
|
51 break; |
|
52 |
|
53 case EL2CAPRetransmissionMode: |
|
54 LOG(_L("FEC L2CapBasicDataController Retransmission Mode")) |
|
55 controller = new(ELeave) CL2CapDataReTxController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig); |
|
56 break; |
|
57 |
|
58 case EL2CAPFlowControlMode: |
|
59 LOG(_L("FEC L2CapBasicDataController Flow Control Mode")) |
|
60 controller = new(ELeave) CL2CapDataFlowController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig); |
|
61 break; |
|
62 |
|
63 case EL2CAPStreamingMode: |
|
64 LOG(_L("FEC L2CapBasicDataController Streaming Mode")) |
|
65 controller = new(ELeave) CL2CapStreamingController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig); |
|
66 break; |
|
67 |
|
68 case EL2CAPEnhancedRetransmissionMode: |
|
69 LOG(_L("FEC L2CapBasicDataController Enhnaced Retransmission Mode")) |
|
70 controller = CL2CapEnhancedReTxController::NewL(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig); |
|
71 break; |
|
72 |
|
73 default: |
|
74 Panic(EL2CAPInvalidLinkMode); |
|
75 break; |
|
76 }; |
|
77 |
|
78 return controller; |
|
79 } |
|
80 |
|
81 CL2CapBasicDataController::CL2CapBasicDataController(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig, TBool aIsBasicDataVersion) |
|
82 : iSDUQueue(aSDUQueue), |
|
83 iMuxer(aMuxer), |
|
84 iLocalCID(aLocalCID), |
|
85 iRemoteCID(aRemoteCID), |
|
86 iConfig(aConfig), |
|
87 iIsBasicDataVersion(aIsBasicDataVersion) |
|
88 { |
|
89 LOG_FUNC |
|
90 // Register with the Mux. |
|
91 iMuxer.RegisterDataPDUHandler(*this); |
|
92 |
|
93 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EDataPlanes, |
|
94 L2capDebugInfo::EAllocated)); |
|
95 } |
|
96 |
|
97 CL2CapBasicDataController::~CL2CapBasicDataController() |
|
98 { |
|
99 LOG_FUNC |
|
100 delete iConfig; |
|
101 |
|
102 L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EDataPlanes, |
|
103 L2capDebugInfo::EDeleted)); |
|
104 } |
|
105 |
|
106 HL2CapPDU* CL2CapBasicDataController::GetPdu() |
|
107 { |
|
108 LOG_FUNC |
|
109 HL2CapPDU* pdu = NULL; |
|
110 TRAPD(err, pdu = GetPduL()); |
|
111 if (err != KErrNone) |
|
112 { |
|
113 // The protocol here is that all leaves propagated up to here cause |
|
114 // us to ErrorD() ourselves, which will destruct data plane objects |
|
115 // (the data controller, SDU queue and the whole shebang) and error |
|
116 // the socket with the leave error code. |
|
117 ErrorD(err); |
|
118 } |
|
119 return pdu; |
|
120 } |
|
121 |
|
122 HL2CapPDU* CL2CapBasicDataController::GetPduL() |
|
123 { |
|
124 LOG_FUNC |
|
125 HL2CapPDU* pduToSend = NULL; |
|
126 if((pduToSend = iSDUQueue.GetPDU()) != NULL) |
|
127 { |
|
128 pduToSend->SetPDUCID(iRemoteCID); |
|
129 } |
|
130 return pduToSend; |
|
131 } |
|
132 |
|
133 void CL2CapBasicDataController::ProcessFlushTimerExpiry() |
|
134 { |
|
135 LOG_FUNC |
|
136 iMuxer.ProcessFlushTimerExpiry(); |
|
137 } |
|
138 |
|
139 void CL2CapBasicDataController::OutgoingPduAvailableOnSduQ() |
|
140 { |
|
141 LOG_FUNC |
|
142 iMuxer.PDUAvailable(); |
|
143 } |
|
144 |
|
145 void CL2CapBasicDataController::UpdateConfig(TL2CapDataControllerConfig* aConfig) |
|
146 { |
|
147 LOG_FUNC |
|
148 TBool channelPriorityUpdated = (iConfig->ChannelPriority() != aConfig->ChannelPriority()); |
|
149 // Delete the existing config, and replace it with the new one. |
|
150 delete iConfig; |
|
151 iConfig = aConfig; |
|
152 |
|
153 if(channelPriorityUpdated) |
|
154 { |
|
155 iMuxer.ChannelPriorityUpdated(*this); |
|
156 } |
|
157 } |
|
158 |
|
159 void CL2CapBasicDataController::UpdateChannelPriority(TUint8 aNewPriority) |
|
160 { |
|
161 LOG_FUNC |
|
162 if(iConfig->ChannelPriority() != aNewPriority) |
|
163 { |
|
164 iConfig->SetChannelPriority(aNewPriority); |
|
165 iMuxer.ChannelPriorityUpdated(*this); |
|
166 } |
|
167 } |
|
168 |
|
169 |
|
170 void CL2CapBasicDataController::ErrorD(TInt aError) |
|
171 { |
|
172 LOG_FUNC |
|
173 LOG1(_L("FEC CL2CapBasicDataController::Error %d"), aError) |
|
174 iDataPlaneErrored = ETrue; |
|
175 iSDUQueue.ErrorD(aError); |
|
176 } |
|
177 |
|
178 void CL2CapBasicDataController::SetIncomingSduQFull(TBool /*aIncomingSduQFull*/) |
|
179 { |
|
180 LOG_FUNC |
|
181 // No action can be taken in basic mode. |
|
182 } |
|
183 |
|
184 TBool CL2CapBasicDataController::DeliverOutgoingDataAndSignalToSduQWhenDone() |
|
185 { |
|
186 LOG_FUNC |
|
187 // We can be deleted right away. |
|
188 return ETrue; |
|
189 } |
|
190 |
|
191 void CL2CapBasicDataController::DeregisterFromMuxer() |
|
192 { |
|
193 LOG_FUNC |
|
194 iMuxer.DataChannelRemoved(this); |
|
195 } |
|
196 |
|
197 #ifdef _DEBUG |
|
198 TInt CL2CapBasicDataController::GetDataPlaneConfig(TL2DataPlaneConfig& conf) const |
|
199 { |
|
200 LOG_FUNC |
|
201 TInt rerr = KErrNone; |
|
202 // Populate the debug structure. |
|
203 if(iConfig) |
|
204 { |
|
205 conf.iPriority = iConfig->ChannelPriority(); |
|
206 conf.iLinkMode = iConfig->LinkMode(); |
|
207 conf.iTxWindowSize = iConfig->TXWindowSize(); |
|
208 conf.iMaxTransmit = iConfig->MaxTransmit(); |
|
209 conf.iRetransmissionTimeout = iConfig->RetransmissionTimeout(); |
|
210 conf.iMonitorTimeout = iConfig->MonitorTimeout(); |
|
211 } |
|
212 else |
|
213 { |
|
214 rerr = KErrNotReady; |
|
215 } |
|
216 return rerr; |
|
217 } |
|
218 #endif |
|
219 |
|
220 TBool CL2CapBasicDataController::HandleIncomingDataFrame(RMBufChain& aDataFrame) |
|
221 { |
|
222 LOG_FUNC |
|
223 TBool packetDelivered = EFalse; |
|
224 TRAPD(err, packetDelivered = HandleIncomingDataFrameL(aDataFrame)); |
|
225 if (err != KErrNone) |
|
226 { |
|
227 // The protocol here is that all leaves propagated up to here cause |
|
228 // us to ErrorD() ourselves, which will destruct data plane objects |
|
229 // (the data controller, SDU queue and the whole shebang) and error |
|
230 // the socket with the leave error code. |
|
231 ErrorD(err); |
|
232 |
|
233 if (aDataFrame.IsEmpty()) |
|
234 { |
|
235 packetDelivered = ETrue; |
|
236 } |
|
237 // else frame will be offered to other data controllers |
|
238 } |
|
239 return packetDelivered; |
|
240 } |
|
241 |
|
242 void CL2CapBasicDataController::HandleIncomingIFrameL(RMBufChain& /*aDataFrame*/) |
|
243 { |
|
244 LOG_FUNC |
|
245 Panic(EL2CAPIFrameOrSFrameHandledByBasicController); |
|
246 } |
|
247 |
|
248 void CL2CapBasicDataController::HandleIncomingBFrameL(RMBufChain& aDataFrame) |
|
249 { |
|
250 LOG_FUNC |
|
251 iSDUQueue.PutBFramePDU(aDataFrame); |
|
252 } |
|
253 |
|
254 void CL2CapBasicDataController::HandleIncomingSFrameL(RMBufChain& /*aDataFrame*/) |
|
255 { |
|
256 LOG_FUNC |
|
257 Panic(EL2CAPIFrameOrSFrameHandledByBasicController); |
|
258 } |
|
259 |
|
260 TBool CL2CapBasicDataController::HandleIncomingDataFrameL(RMBufChain& aDataFrame) |
|
261 { |
|
262 LOG_FUNC |
|
263 TBool PDUProcessed = EFalse; |
|
264 TInt err = KErrNone; |
|
265 |
|
266 if(HL2CapPDU::PDUCID(aDataFrame) == iLocalCID) |
|
267 { |
|
268 if(iIsBasicDataVersion) |
|
269 { |
|
270 // This can only be a B-Frame. |
|
271 if(HBFramePDU::CheckDecode(aDataFrame) == KErrNone) |
|
272 { |
|
273 HandleIncomingBFrameL(aDataFrame); |
|
274 } |
|
275 else |
|
276 { |
|
277 // Invalid frame. Drop it. |
|
278 aDataFrame.Free(); |
|
279 LOG(_L("FEC L2CapBasicDataController B-Frame Dropped")) |
|
280 } |
|
281 } |
|
282 else |
|
283 { |
|
284 if(HIFramePDU::IFrameIdentifier(aDataFrame)) |
|
285 { |
|
286 // This is an I-Frame |
|
287 |
|
288 // Check stuff that causes us to drop frames first: |
|
289 // - FCS (2.1 Core Spec Addendum 1: 3.3.7 Invalid Frame Detection Algorithm pt. 2) |
|
290 // - length field matching the actual payload length (funnily 3.3.7 doesn't say |
|
291 // what to do with it, pt. 7.2.2 Recombination Of L2CAP PDUs mentions it in |
|
292 // passing). |
|
293 // Note: the frame is dropped when length is incorrect (instead of disconnecting) |
|
294 // because we don't know where FCS is (it's at the end of the packet and we don't |
|
295 // know where that is), so have to assume that the length field problem is due to |
|
296 // transmission corruption and not the remote misbehaving. |
|
297 if (HIFramePDU::CheckPayloadDecode(aDataFrame) != KErrNone || |
|
298 HL2CapPDU::CheckDecode(aDataFrame) != KErrNone) |
|
299 { |
|
300 aDataFrame.Free(); |
|
301 LOG(_L("FEC L2CapBasicDataController I-Frame Dropped")) |
|
302 } |
|
303 else |
|
304 { |
|
305 // Now check stuff that causes us to disconnect (per CSA1 3.3.7). |
|
306 err = HIFramePDU::CheckLengthWithinLimits(aDataFrame, iConfig->IncomingMps()); |
|
307 if (err != KErrNone) |
|
308 { |
|
309 LOG(_L("FEC L2CapBasicDataController I-Frame invalid")) |
|
310 |
|
311 aDataFrame.Free(); |
|
312 // This will cause the channel to be closed. |
|
313 LEAVEL(err); |
|
314 } |
|
315 else |
|
316 { |
|
317 HandleIncomingIFrameL(aDataFrame); |
|
318 } |
|
319 } |
|
320 } |
|
321 else |
|
322 { |
|
323 // S-Frame |
|
324 |
|
325 // Check stuff that causes the frame to be dropped first. |
|
326 if (HSFramePDU::CheckPayloadDecode(aDataFrame) != KErrNone || |
|
327 HL2CapPDU::CheckDecode(aDataFrame) != KErrNone) |
|
328 { |
|
329 LOG(_L("FEC L2CapBasicDataController S-Frame Dropped")) |
|
330 } |
|
331 else |
|
332 { |
|
333 // Now check stuff that causes us to disconnect (per CSA1 3.3.7). |
|
334 err = HSFramePDU::CheckLengthField(aDataFrame); |
|
335 if (err != KErrNone) |
|
336 { |
|
337 LOG(_L("FEC L2CapBasicDataController S-Frame Invalid")) |
|
338 |
|
339 aDataFrame.Free(); |
|
340 // This will cause the channel to be closed. |
|
341 LEAVEL(err); |
|
342 } |
|
343 else |
|
344 { |
|
345 HandleIncomingSFrameL(aDataFrame); |
|
346 } |
|
347 } |
|
348 // Finished with the S-Frame. |
|
349 aDataFrame.Free(); |
|
350 } |
|
351 } |
|
352 PDUProcessed = ETrue; |
|
353 } |
|
354 return PDUProcessed; |
|
355 } |
|
356 |
|
357 // Outgoing PDU handler. |
|
358 TInt CL2CapBasicDataController::HandleOutgoingIFrame(HIFramePDU* /*aIFrame*/) |
|
359 { |
|
360 LOG_FUNC |
|
361 return KErrNone; |
|
362 } |
|
363 |
|
364 TInt CL2CapBasicDataController::HandleOutgoingBFrame(HBFramePDU* /*aBFrame*/) |
|
365 { |
|
366 LOG_FUNC |
|
367 return KErrNone; |
|
368 } |
|
369 |
|
370 TInt CL2CapBasicDataController::HandleOutgoingGFrame(HGFramePDU* /*aGFrame*/) |
|
371 { |
|
372 LOG_FUNC |
|
373 return KErrNone; |
|
374 } |
|
375 |
|
376 TInt CL2CapBasicDataController::HandleOutgoingCFrame(HCFramePDU* /*aCFrame*/) |
|
377 { |
|
378 LOG_FUNC |
|
379 return KErrNone; |
|
380 } |
|
381 |
|
382 TInt CL2CapBasicDataController::HandleOutgoingSFrame(HSFramePDU* /*aSFrame*/) |
|
383 { |
|
384 LOG_FUNC |
|
385 return KErrNone; |
|
386 } |
|
387 |
|
388 // ***** CL2CapDataFlowController Implementation |
|
389 CL2CapDataFlowController::CL2CapDataFlowController(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig) |
|
390 : CL2CapBasicDataController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig, EFalse), |
|
391 iPendingSentPDUs(_FOFF(HIFramePDU, iLink)), |
|
392 iSentPDUs(_FOFF(HIFramePDU, iLink)), |
|
393 iTimerMan(*this), |
|
394 iIncomingSduQFull(EFalse) |
|
395 { |
|
396 LOG_FUNC |
|
397 } |
|
398 |
|
399 CL2CapDataFlowController::~CL2CapDataFlowController() |
|
400 { |
|
401 LOG_FUNC |
|
402 // Some PDUs may hold a reference to this data controller. |
|
403 TDblQueIter<HIFramePDU> pendingIter(iPendingSentPDUs); |
|
404 TDblQueIter<HIFramePDU> sentIter(iSentPDUs); |
|
405 HIFramePDU* pduPtr; |
|
406 |
|
407 while((pduPtr = pendingIter++) != NULL) |
|
408 { |
|
409 LOG1(_L("Deregistering TxSeq = %d"), pduPtr->TxSeqNumber()); |
|
410 pduPtr->DeregisterPduOwner(); |
|
411 } |
|
412 |
|
413 // Delete any PDUs that have already been sent. |
|
414 while((pduPtr = sentIter++) != NULL) |
|
415 { |
|
416 delete pduPtr; |
|
417 } |
|
418 |
|
419 // Cancel any outstanding timers. |
|
420 iTimerMan.Close(); |
|
421 } |
|
422 |
|
423 |
|
424 void CL2CapDataFlowController::ProcessFlushTimerExpiry() |
|
425 { |
|
426 LOG_FUNC |
|
427 iMuxer.ProcessFlushTimerExpiry(); |
|
428 PDUAvailable(); |
|
429 |
|
430 if(!iSentPDUs.IsEmpty()) |
|
431 { |
|
432 iNextTxSeq = Mod64(iSentPDUs.Last()->TxSeqNumber() + 1); |
|
433 } |
|
434 else |
|
435 { |
|
436 iNextTxSeq = iExpectedAckSeq; |
|
437 } |
|
438 } |
|
439 |
|
440 void CL2CapDataFlowController::HandleIncomingIFrameL(RMBufChain& aDataFrame) |
|
441 { |
|
442 LOG_FUNC |
|
443 // Check if flow control is active for incoming data. |
|
444 if(iIncomingSduQFull) |
|
445 { |
|
446 // Check that the PDU sequence number is within the expected range. |
|
447 if(!iSenderTxWindowClosed && Mod64(HIFramePDU::TxSeqNumber(aDataFrame) - iLastAckSentRxSeqNum) >= iConfig->PeerTXWindowSize()) |
|
448 { |
|
449 // The number is not in range. No more I-Frames will be processed |
|
450 // until flow control is deactivated. |
|
451 iSenderTxWindowClosed = ETrue; |
|
452 } |
|
453 } |
|
454 |
|
455 LOG(_L("FEC CL2CapDataFlowController: HandleIncomingIFrame")) |
|
456 LOG1(_L("\tTxSeqNumber = %d"), HIFramePDU::TxSeqNumber(aDataFrame)) |
|
457 LOG1(_L("\tLastAckSentRxSeqNum = %d"), iLastAckSentRxSeqNum) |
|
458 |
|
459 if(!iSenderTxWindowClosed) |
|
460 { |
|
461 ProcessIFrameL(aDataFrame); |
|
462 } |
|
463 else |
|
464 { |
|
465 // Drop the frame. |
|
466 aDataFrame.Free(); |
|
467 LOG(_L("FEC CL2CapDataFlowController: Incoming PDU seq number of I-Frame is not in range!")) |
|
468 } |
|
469 } |
|
470 |
|
471 void CL2CapDataFlowController::ProcessIFrameL(RMBufChain& aDataFrame) |
|
472 { |
|
473 LOG_FUNC |
|
474 iExpectedTxSeq = Mod64(iExpectedTxSeq + 1); |
|
475 iExpectedAckSeq = HIFramePDU::ReqSeqNumber(aDataFrame); |
|
476 |
|
477 LEAVEIFERRORL(iSDUQueue.PutIFramePDU(aDataFrame)); |
|
478 |
|
479 // Check if the acknowledged frame(s) has created |
|
480 // space in the window. |
|
481 RemoveAckedPDUsFromSentQueue(); |
|
482 |
|
483 // Only send an ack if incoming data is not currently flow controlled off. |
|
484 if(!iIncomingSduQFull) |
|
485 { |
|
486 // Check if the peer frames need to be acknowledged now. |
|
487 // Check the peer TxWindow. This check is |
|
488 // (Number of I-Frames recv since last Ack was sent > (TxWindow - Constant) |
|
489 if(Mod64(iExpectedTxSeq - iLastAckSentRxSeqNum) > (iConfig->PeerTXWindowSize() - KTxWinAckThresholdOffset)) |
|
490 { |
|
491 // Send an ack. |
|
492 iSendAckToPeer = ETrue; |
|
493 } |
|
494 else |
|
495 { |
|
496 // If the timer is not running, start it. |
|
497 if(!iTimerMan.IsSendPeerAckTimerRunning()) |
|
498 { |
|
499 if(!iTimerMan.StartSendPeerAckTimer()) |
|
500 { |
|
501 // A timer could not be started. Send an ack immediately. |
|
502 iSendAckToPeer = ETrue; |
|
503 } |
|
504 } |
|
505 } |
|
506 } |
|
507 // Check if any outbound data can be sent. |
|
508 PDUAvailable(); |
|
509 } |
|
510 |
|
511 void CL2CapDataFlowController::HandleIncomingSFrameL(RMBufChain& aDataFrame) |
|
512 { |
|
513 LOG_FUNC |
|
514 // Check that the function is RR. If not this S-Frame is not valid for |
|
515 // flow control mode. |
|
516 if(HSFramePDU::SupervisoryFunction(aDataFrame) == EReceiverReady) |
|
517 { |
|
518 iExpectedAckSeq = HSFramePDU::ReqSeqNumber(aDataFrame); |
|
519 // Check if the acknowledged frame(s) has created |
|
520 // space in the window. |
|
521 RemoveAckedPDUsFromSentQueue(); |
|
522 PDUAvailable(); |
|
523 LOG(_L("FEC CL2CapDataFlowController: Incoming S-Frame: RR")) |
|
524 LOG1(_L("\tiLastAckedFrameNum = %d"), iExpectedAckSeq) |
|
525 } |
|
526 } |
|
527 |
|
528 TInt CL2CapDataFlowController::HandleOutgoingIFrame(HIFramePDU* aIFrame) |
|
529 { |
|
530 LOG_FUNC |
|
531 aIFrame->SetPDUCID(iRemoteCID); |
|
532 aIFrame->SetTxSeqNumber(iNextTxSeq); |
|
533 LOG(_L("FEC CL2CapDataFlowController: HandleOutgoingIFrame")) |
|
534 LOG1(_L("\tTxSeqNumber = %d"), iNextTxSeq) |
|
535 iNextTxSeq = Mod64(iNextTxSeq + 1); |
|
536 |
|
537 // If flow controlled off - don't acknowledge any new I-Frames |
|
538 aIFrame->SetReqSeqNumber(iIncomingSduQFull ? iLastAckSentRxSeqNum : iExpectedTxSeq); |
|
539 |
|
540 // Set the retransmission disable bit if flow control is on. |
|
541 aIFrame->SetRetransmitDisable(iIncomingSduQFull); |
|
542 aIFrame->CalculateAndSetFCS(); |
|
543 |
|
544 aIFrame->iLink.Deque(); // just in case, it shouldn't be on any list at this point |
|
545 aIFrame->SetPduOwner(this); |
|
546 iPendingSentPDUs.AddLast(*aIFrame); |
|
547 |
|
548 // Cancel the peer ack timer. |
|
549 iTimerMan.StopSendPeerAckTimer(); |
|
550 iSendAckToPeer = EFalse; |
|
551 |
|
552 // Store the last acknowledged frame index. |
|
553 if(!iIncomingSduQFull) |
|
554 { |
|
555 iLastAckSentRxSeqNum = iExpectedTxSeq; |
|
556 } |
|
557 LOG1(_L("\tLastAckSentRxSeqNum = %d"), iLastAckSentRxSeqNum) |
|
558 |
|
559 return KErrNone; |
|
560 } |
|
561 |
|
562 TInt CL2CapDataFlowController::HandleOutgoingSFrame(HSFramePDU* aSFrame) |
|
563 { |
|
564 LOG_FUNC |
|
565 aSFrame->SetPDUCID(iRemoteCID); |
|
566 // If flow controlled off - don't acknowledge any new I-Frames |
|
567 aSFrame->SetReqSeqNumber(iIncomingSduQFull ? iLastAckSentRxSeqNum : iExpectedTxSeq); |
|
568 LOG(_L("FEC CL2CapDataFlowController: HandleOutgoingSFrame")) |
|
569 LOG1(_L("\tReqSeqNUmber = %d"), iIncomingSduQFull ? iLastAckSentRxSeqNum : iExpectedTxSeq) |
|
570 // Set the retransmission disable bit if flow control is on. |
|
571 aSFrame->SetRetransmitDisable(iIncomingSduQFull); |
|
572 aSFrame->CalculateAndSetFCS(); |
|
573 |
|
574 // If the monitor timer is currently running. Re-start it. |
|
575 if(!iTimerMan.IsAckTimerRunning()) |
|
576 { |
|
577 iTimerMan.StartMonitorTimer(); |
|
578 } |
|
579 |
|
580 // Store the last acknowledged frame index. |
|
581 if(!iIncomingSduQFull) |
|
582 { |
|
583 iLastAckSentRxSeqNum = iExpectedTxSeq; |
|
584 } |
|
585 |
|
586 // Cancel the peer ack timer. |
|
587 iTimerMan.StopSendPeerAckTimer(); |
|
588 iSendAckToPeer = EFalse; |
|
589 LOG1(_L("\tLastAckSentRxSeqNum = %d"), iLastAckSentRxSeqNum) |
|
590 return KErrNone; |
|
591 } |
|
592 |
|
593 TBool CL2CapDataFlowController::CanSendPDU() |
|
594 { |
|
595 LOG_FUNC |
|
596 TBool canSend = ETrue; |
|
597 |
|
598 // This condition is (V(S) - V(A))mod64 >= TxWindow |
|
599 if(Mod64(iNextTxSeq - iExpectedAckSeq) >= iConfig->TXWindowSize()) |
|
600 { |
|
601 canSend = EFalse; |
|
602 } |
|
603 return canSend; |
|
604 } |
|
605 |
|
606 |
|
607 HL2CapPDU* CL2CapDataFlowController::GetPduL() |
|
608 { |
|
609 LOG_FUNC |
|
610 // This is called from the signal manager. |
|
611 HL2CapPDU* pduToSend = NULL; |
|
612 |
|
613 if(CanSendPDU()) |
|
614 { |
|
615 pduToSend = iSDUQueue.GetPDU(); |
|
616 } |
|
617 |
|
618 if(pduToSend) |
|
619 { |
|
620 pduToSend->DeliverOutgoingPDU(*this); |
|
621 } |
|
622 |
|
623 // Note: If pduToSend has a valid pointer then the call to |
|
624 // pduToSend->DeliverOutgoingPDU(*this) (above) will clear the |
|
625 // iSendAckToPeer flag. |
|
626 if(iSendAckToPeer) |
|
627 { |
|
628 pduToSend = HSFramePDU::New(EReceiverReady); |
|
629 if(pduToSend) |
|
630 { |
|
631 pduToSend->DeliverOutgoingPDU(*this); |
|
632 } |
|
633 else |
|
634 { |
|
635 ErrorD(KErrNoMemory); |
|
636 // We've been deleted! |
|
637 } |
|
638 } |
|
639 return pduToSend; |
|
640 } |
|
641 |
|
642 |
|
643 void CL2CapDataFlowController::PDUAvailable() |
|
644 { |
|
645 LOG_FUNC |
|
646 |
|
647 // Note that CanSend only checks whether there's available outgoing window space, |
|
648 // not whether there really is some outstanding data on SDU Q. GetPduL will check |
|
649 // that and do nothing if there isn't. |
|
650 if(CanSendPDU() || iSendAckToPeer) |
|
651 { |
|
652 iMuxer.PDUAvailable(); |
|
653 } |
|
654 } |
|
655 |
|
656 void CL2CapDataFlowController::RemoveAckedPDUsFromSentQueue() |
|
657 { |
|
658 LOG_FUNC |
|
659 TDblQueIter<HIFramePDU> iter(iSentPDUs); |
|
660 HIFramePDU* pduPtr; |
|
661 TInt ackedPDUs = 0; |
|
662 TInt count = 0; |
|
663 |
|
664 TUint8 frameSeqNumber = Mod64(iExpectedAckSeq - 1); |
|
665 |
|
666 // Find out how many PDU's have been ack'd |
|
667 while((pduPtr = iter++) != NULL) |
|
668 { |
|
669 if(pduPtr->TxSeqNumber() == frameSeqNumber) |
|
670 { |
|
671 // Increment the count by one and exit the loop. |
|
672 ackedPDUs = count + 1; |
|
673 break; |
|
674 } |
|
675 count++; |
|
676 } |
|
677 |
|
678 // Remove all ack'd PDUs |
|
679 iter.SetToFirst(); |
|
680 for(TInt i=0;i<ackedPDUs;i++) |
|
681 { |
|
682 pduPtr = iter++; |
|
683 delete pduPtr; |
|
684 } |
|
685 |
|
686 // Some PDUs have been ack'd. |
|
687 if(ackedPDUs) |
|
688 { |
|
689 if(iSentPDUs.IsEmpty()) |
|
690 { |
|
691 iTimerMan.StartMonitorTimer(); |
|
692 } |
|
693 else |
|
694 { |
|
695 iTimerMan.StopMonitorTimer(); |
|
696 iTimerMan.StartAckTimer(); |
|
697 } |
|
698 } |
|
699 } |
|
700 |
|
701 void CL2CapDataFlowController::MonitorTimerExpired() |
|
702 { |
|
703 LOG_FUNC |
|
704 // The monitor timer has expired. Send a S-Frame to the peer by setting |
|
705 // the ack outstanding flag and calling PDUAvailable. This method will |
|
706 // call this back at which point the S-Frame will be created. |
|
707 LOG(_L("FEC CL2CapDataFlowController::MonitorTimerExpired")) |
|
708 iSendAckToPeer = ETrue; |
|
709 PDUAvailable(); |
|
710 } |
|
711 |
|
712 |
|
713 void CL2CapDataFlowController::AckTimerExpired() |
|
714 { |
|
715 LOG_FUNC |
|
716 // Remove the PDU that the timer is supervising. This can |
|
717 // only be the first Sent PDU. |
|
718 LOG(_L("FEC CL2CapDataFlowController::AckTimerExpired")) |
|
719 __ASSERT_DEBUG(!iSentPDUs.IsEmpty(), Panic(EL2CAPAckTimerExpiryWithoutPDUToSupervise)); |
|
720 |
|
721 HL2CapPDU* pdu = iSentPDUs.First(); |
|
722 delete pdu; |
|
723 |
|
724 iExpectedAckSeq = Mod64(iExpectedAckSeq + 1); |
|
725 |
|
726 if(iSentPDUs.IsEmpty()) |
|
727 { |
|
728 iTimerMan.StartMonitorTimer(); |
|
729 } |
|
730 else |
|
731 { |
|
732 iTimerMan.StopMonitorTimer(); |
|
733 iTimerMan.StartAckTimer(); |
|
734 } |
|
735 PDUAvailable(); |
|
736 } |
|
737 |
|
738 void CL2CapDataFlowController::SendPeerAckTimerExpired() |
|
739 { |
|
740 LOG_FUNC |
|
741 |
|
742 // Indicate that an ack should be sent to the peer to |
|
743 // acknowledge receipt of I-Frames. |
|
744 iSendAckToPeer = ETrue; |
|
745 PDUAvailable(); |
|
746 } |
|
747 |
|
748 TUint16 CL2CapDataFlowController::MonitorTimeout() |
|
749 { |
|
750 return iConfig->MonitorTimeout(); |
|
751 } |
|
752 |
|
753 TUint16 CL2CapDataFlowController::RetransmissionTimeout() |
|
754 { |
|
755 return iConfig->RetransmissionTimeout(); |
|
756 } |
|
757 |
|
758 TUint16 CL2CapDataFlowController::PeerRetransmissionTimeout() |
|
759 { |
|
760 return iConfig->PeerRetransmissionTimeout(); |
|
761 } |
|
762 |
|
763 |
|
764 void CL2CapDataFlowController::HandlePduSendComplete(HL2CapPDU& aPdu) |
|
765 { |
|
766 LOG_FUNC |
|
767 |
|
768 // We only claim ownership of I-Frames. |
|
769 HIFramePDU& IFrame = static_cast<HIFramePDU&>(aPdu); |
|
770 |
|
771 // Remove the PDU from the pending send queue. |
|
772 IFrame.iLink.Deque(); |
|
773 |
|
774 // If there are outstanding (i.e., un-ack'ed) PDU's, the |
|
775 // Ack timer will already be running. Otherwise it should |
|
776 // be started. |
|
777 if(iSentPDUs.IsEmpty()) |
|
778 { |
|
779 iTimerMan.StartAckTimer(); |
|
780 } |
|
781 |
|
782 // It's waiting for acknowledgement now. |
|
783 iSentPDUs.AddLast(IFrame); |
|
784 PDUAvailable(); |
|
785 } |
|
786 |
|
787 void CL2CapDataFlowController::HandlePduSendError(HL2CapPDU& /*aPdu*/) |
|
788 { |
|
789 LOG_FUNC |
|
790 // In FC mode the frame will get deleted when we get an acknowledgement. |
|
791 // In RTM, protocol-level retransmissions will be run when peer rejects or |
|
792 // our ack timer expires. |
|
793 } |
|
794 |
|
795 |
|
796 void CL2CapDataFlowController::SetIncomingSduQFull(TBool aIncomingSduQFull) |
|
797 { |
|
798 LOG_FUNC |
|
799 // Check that the FC status has changed |
|
800 if(iIncomingSduQFull != aIncomingSduQFull) |
|
801 { |
|
802 iIncomingSduQFull = aIncomingSduQFull; |
|
803 iSenderTxWindowClosed = EFalse; |
|
804 |
|
805 // Send an acknowledgement to the peer indicate the new |
|
806 // flow control status. |
|
807 iSendAckToPeer = ETrue; |
|
808 PDUAvailable(); |
|
809 } |
|
810 } |
|
811 |
|
812 |
|
813 // ***** CL2CapDataReTxController Implementation |
|
814 CL2CapDataReTxController::CL2CapDataReTxController(TL2CAPPort aLocalCID, TL2CAPPort aRemoteCID, CL2CAPMux& aMuxer, CL2CapSDUQueue& aSDUQueue, TL2CapDataControllerConfig* aConfig) |
|
815 : CL2CapDataFlowController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig), |
|
816 iRejectPDU(0), |
|
817 iRetransmitSentPDUs(EFalse), |
|
818 iRejectSent(EFalse), |
|
819 iRetransmissionDisabled(EFalse), |
|
820 iRestartAckTimer(EFalse), |
|
821 iRetransTxVal(iNextTxSeq) |
|
822 { |
|
823 LOG_FUNC |
|
824 } |
|
825 |
|
826 void CL2CapDataReTxController::HandleIncomingIFrameL(RMBufChain& aDataFrame) |
|
827 { |
|
828 LOG_FUNC |
|
829 TBool newRtxDisable = HIFramePDU::RetransmitDisable(aDataFrame); |
|
830 if(iExpectedTxSeq == HIFramePDU::TxSeqNumber(aDataFrame)) |
|
831 { |
|
832 LOG(_L("FEC CL2CapDataReTxController: HandleIncomingIFrame")) |
|
833 LOG1(_L("\tTxSeqNumber = %d"), HIFramePDU::TxSeqNumber(aDataFrame)) |
|
834 ProcessIFrameL(aDataFrame); |
|
835 iRejectSent = EFalse; |
|
836 } |
|
837 else |
|
838 { |
|
839 // This I-Frame has an invalid sequence number. |
|
840 // Check that a Reject Exception is not already being |
|
841 // handled. |
|
842 if(!iRejectSent) |
|
843 { |
|
844 iRejectPDU = HSFramePDU::NewL(EReject); |
|
845 iRejectPDU->DeliverOutgoingPDU(*this); |
|
846 // Send the Reject PDU. |
|
847 iMuxer.PDUAvailable(); |
|
848 iRejectSent = ETrue; |
|
849 } |
|
850 aDataFrame.Free(); |
|
851 LOG(_L("FEC CL2CapDataReTxController: Incoming PDU seq number of I-Frame is not in range!")) |
|
852 } |
|
853 |
|
854 // Check if the re-transmission disable bit has transitioned. |
|
855 if(iRetransmissionDisabled != newRtxDisable) |
|
856 { |
|
857 if(newRtxDisable) |
|
858 { |
|
859 // Re-transmission has been disabled. |
|
860 iTimerMan.StartMonitorTimer(); |
|
861 } |
|
862 else |
|
863 { |
|
864 // Re-transmission has been enabled. |
|
865 if(!iSentPDUs.IsEmpty()) |
|
866 { |
|
867 iTimerMan.StopMonitorTimer(); |
|
868 iTimerMan.StartAckTimer(); |
|
869 } |
|
870 } |
|
871 iRetransmissionDisabled = newRtxDisable; |
|
872 } |
|
873 } |
|
874 |
|
875 void CL2CapDataReTxController::HandleIncomingSFrameL(RMBufChain& aDataFrame) |
|
876 { |
|
877 LOG_FUNC |
|
878 if(HSFramePDU::SupervisoryFunction(aDataFrame) == EReject) |
|
879 { |
|
880 iRetransmitSentPDUs = ETrue; |
|
881 iRetransTxVal = HSFramePDU::ReqSeqNumber(aDataFrame); |
|
882 LOG(_L("FEC CL2CapDataReTxController: Incoming S-Frame: Reject")) |
|
883 } |
|
884 iExpectedAckSeq = HSFramePDU::ReqSeqNumber(aDataFrame); |
|
885 LOG(_L("FEC CL2CapDataReTxController: Incoming S-Frame")) |
|
886 LOG1(_L("\tLastAckedFrameNum = %d"), iExpectedAckSeq) |
|
887 |
|
888 TBool newRtxDisable = HSFramePDU::RetransmitDisable(aDataFrame); |
|
889 |
|
890 // Check if the acknowledged frame(s) has created |
|
891 // space in the window. |
|
892 RemoveAckedPDUsFromSentQueue(); |
|
893 PDUAvailable(); |
|
894 |
|
895 // Check if the re-transmission disable bit has transitioned. |
|
896 if(iRetransmissionDisabled != newRtxDisable) |
|
897 { |
|
898 if(newRtxDisable) |
|
899 { |
|
900 // Re-transmission has been disabled. |
|
901 iTimerMan.StartMonitorTimer(); |
|
902 } |
|
903 else |
|
904 { |
|
905 // Re-transmission has been enabled. |
|
906 if(!iSentPDUs.IsEmpty()) |
|
907 { |
|
908 iTimerMan.StopMonitorTimer(); |
|
909 iTimerMan.StartAckTimer(); |
|
910 } |
|
911 } |
|
912 iRetransmissionDisabled = newRtxDisable; |
|
913 } |
|
914 } |
|
915 |
|
916 HL2CapPDU* CL2CapDataReTxController::GetPduL() |
|
917 { |
|
918 LOG_FUNC |
|
919 // This is called from the signal manager. |
|
920 HL2CapPDU* pduToSend = NULL; |
|
921 |
|
922 // Check the re-transmission disabled flag. If its set |
|
923 // then only S-Frames can be sent. |
|
924 if(!iRetransmissionDisabled && !iDataPlaneErrored) |
|
925 { |
|
926 if(iRejectPDU) |
|
927 { |
|
928 pduToSend = iRejectPDU; |
|
929 iRejectPDU = NULL; |
|
930 } |
|
931 else |
|
932 { |
|
933 if(iRetransmitSentPDUs) |
|
934 { |
|
935 pduToSend = RetransmitSentPDU(); |
|
936 } |
|
937 |
|
938 if(!pduToSend && CanSendPDU()) |
|
939 { |
|
940 pduToSend = iSDUQueue.GetPDU(); |
|
941 } |
|
942 } |
|
943 } |
|
944 |
|
945 if(pduToSend) |
|
946 { |
|
947 pduToSend->DeliverOutgoingPDU(*this); |
|
948 } |
|
949 |
|
950 // Note: If pduToSend has a valid pointer then the call to |
|
951 // pduToSend->DeliverOutgoingPDU(*this) (above) will clear the |
|
952 // iSendAckToPeer flag. |
|
953 if(iSendAckToPeer) |
|
954 { |
|
955 pduToSend = HSFramePDU::New(EReceiverReady); |
|
956 if(pduToSend) |
|
957 { |
|
958 pduToSend->DeliverOutgoingPDU(*this); |
|
959 } |
|
960 else |
|
961 { |
|
962 ErrorD(KErrNoMemory); |
|
963 // We've been deleted! |
|
964 } |
|
965 } |
|
966 return pduToSend; |
|
967 } |
|
968 |
|
969 void CL2CapDataReTxController::PDUAvailable() |
|
970 { |
|
971 LOG_FUNC |
|
972 |
|
973 // Note that CanSend only checks whether there's available outgoing window space, |
|
974 // not whether there really is some outstanding data on SDU Q. GetPduL will check |
|
975 // that and do nothing if there isn't. |
|
976 if(CanSendPDU() || iSendAckToPeer || iRetransmitSentPDUs) |
|
977 { |
|
978 iMuxer.PDUAvailable(); |
|
979 } |
|
980 } |
|
981 |
|
982 void CL2CapDataReTxController::AckTimerExpired() |
|
983 { |
|
984 LOG_FUNC |
|
985 __ASSERT_DEBUG(!iSentPDUs.IsEmpty(), Panic(EL2CAPAckTimerExpiryWithoutPDUToSupervise)); |
|
986 |
|
987 // Check if the PDU can be re-sent (i.e., the Max. |
|
988 // transmit has not been exceeded.) |
|
989 |
|
990 HIFramePDU* pdu = iSentPDUs.First(); |
|
991 |
|
992 if(pdu->CanTransmit(iConfig->MaxTransmit())) |
|
993 { |
|
994 // Set the next frame to be transmitted to the PDU |
|
995 // whose timer expired. |
|
996 iRetransTxVal = pdu->TxSeqNumber(); |
|
997 iRetransmitSentPDUs = ETrue; |
|
998 iRestartAckTimer = ETrue; |
|
999 |
|
1000 // The frame will be re-transmitted when GetPDU is called. |
|
1001 // This will also re-start the Retransmission timer. |
|
1002 PDUAvailable(); |
|
1003 } |
|
1004 else |
|
1005 { |
|
1006 // The channel can not support the requested quality. |
|
1007 // i.e., the number of retransmissions before the channel is |
|
1008 // disconnected has been exceeded. |
|
1009 // Error the SAP to disconnect the channel. |
|
1010 ErrorD(KErrL2CAPMaxTransmitExceeded); |
|
1011 LOG(_L("FEC CL2CapDataReTxController::AckTimerExpired - KErrL2CAPMaxTransmitExceeded")) |
|
1012 } |
|
1013 } |
|
1014 |
|
1015 HL2CapPDU* CL2CapDataReTxController::RetransmitSentPDU() |
|
1016 { |
|
1017 LOG_FUNC |
|
1018 HIFramePDU* pduToSend = NULL; |
|
1019 TDblQueIter<HIFramePDU> iter(iSentPDUs); |
|
1020 HIFramePDU* pduPtr; |
|
1021 |
|
1022 while((pduPtr = iter++) != NULL) |
|
1023 { |
|
1024 if(pduPtr->TxSeqNumber() == iRetransTxVal) |
|
1025 { |
|
1026 pduToSend = pduPtr; |
|
1027 break; |
|
1028 } |
|
1029 } |
|
1030 |
|
1031 if(!pduToSend) |
|
1032 { |
|
1033 iRetransmitSentPDUs = EFalse; |
|
1034 } |
|
1035 return pduToSend; |
|
1036 } |
|
1037 |
|
1038 void CL2CapDataReTxController::HandlePduSendComplete(HL2CapPDU& aPdu) |
|
1039 { |
|
1040 LOG_FUNC |
|
1041 |
|
1042 // We only claim ownership of I-Frames. |
|
1043 HIFramePDU& IFrame = static_cast<HIFramePDU&>(aPdu); |
|
1044 |
|
1045 // Remove the PDU from the pending send queue. |
|
1046 IFrame.iLink.Deque(); |
|
1047 |
|
1048 // If there are outstanding (i.e., un-ack'ed) PDU's, the |
|
1049 // Ack timer will already be running. Otherwise it should |
|
1050 // be started. |
|
1051 if(iSentPDUs.IsEmpty() || iRestartAckTimer) |
|
1052 { |
|
1053 iTimerMan.StopMonitorTimer(); |
|
1054 iRestartAckTimer = EFalse; |
|
1055 iTimerMan.StartAckTimer(); |
|
1056 } |
|
1057 |
|
1058 iSentPDUs.AddLast(IFrame); |
|
1059 |
|
1060 // When operating in lossy conditions such as when running |
|
1061 // concurrently with a name inquiry it is possible for an |
|
1062 // acknowledgement to arrive before the sent completion code is called |
|
1063 // for the relevant PDU. As a result aIFrame may have already been |
|
1064 // acknowledged. Now that we have ownership of the PDU we can |
|
1065 // remove it and cancel the Ack timer if necessary. |
|
1066 |
|
1067 // N.B. Here we have assumed that the delay in the notification |
|
1068 // that a PDU has been sent (thereby moving it from the pending sent |
|
1069 // queue to the sent queue) is not so large that in the mean time we |
|
1070 // have sent so many new PDUs that the transmission window has wrapped |
|
1071 // so far around that an old I-Frame from the last cycle is |
|
1072 // considered an unacknowledged one because the Tx Seq value is once again |
|
1073 // in the valid transmission window. This would require BT to be much |
|
1074 // faster than it currently is (11/04/2007). |
|
1075 RemoveAckedPDUsFromSentQueue(); |
|
1076 PDUAvailable(); |
|
1077 } |
|
1078 |
|
1079 void CL2CapDataReTxController::RemoveAckedPDUsFromSentQueue() |
|
1080 { |
|
1081 LOG_FUNC |
|
1082 TDblQueIter<HIFramePDU> iter(iSentPDUs); |
|
1083 HIFramePDU* pduPtr; |
|
1084 TBool ackedPDUs = EFalse; |
|
1085 |
|
1086 // Remove PDUs which have been previously acknowledged. |
|
1087 // The queue may be out of order due to retransmissions |
|
1088 // being appended at the end of the sent queue. |
|
1089 while((pduPtr = iter++) != NULL) |
|
1090 { |
|
1091 // If the PDU's Tx Seq number is not in the current valid transmission window it is considered a previously acknowledged I-Frame and is removed. |
|
1092 if (!(((pduPtr->TxSeqNumber()>= iExpectedAckSeq) && (pduPtr->TxSeqNumber()< (iExpectedAckSeq + iConfig->TXWindowSize()))) || (((iExpectedAckSeq + iConfig->TXWindowSize()) > KL2CapTxSeqValues) && (pduPtr->TxSeqNumber()< Mod64((iExpectedAckSeq + iConfig->TXWindowSize())))))) |
|
1093 { |
|
1094 ackedPDUs = ETrue; |
|
1095 delete pduPtr; |
|
1096 } |
|
1097 } |
|
1098 |
|
1099 // Some PDUs have been ack'd. |
|
1100 if(ackedPDUs) |
|
1101 { |
|
1102 if(iSentPDUs.IsEmpty()) |
|
1103 { |
|
1104 if (iDeliverOutgoingDataAndSignalToSduQWhenDone && iPendingSentPDUs.IsEmpty()) |
|
1105 { |
|
1106 iSDUQueue.DataControllerDeliveredOutgoingData(); |
|
1107 } |
|
1108 else |
|
1109 { |
|
1110 iTimerMan.StartMonitorTimer(); |
|
1111 } |
|
1112 } |
|
1113 else |
|
1114 { |
|
1115 iTimerMan.StopMonitorTimer(); |
|
1116 iTimerMan.StartAckTimer(); |
|
1117 } |
|
1118 } |
|
1119 } |
|
1120 |
|
1121 TInt CL2CapDataReTxController::HandleOutgoingIFrame(HIFramePDU* aIFrame) |
|
1122 { |
|
1123 LOG_FUNC |
|
1124 aIFrame->SetPDUCID(iRemoteCID); |
|
1125 |
|
1126 // When sending a retransmission iRetransmitSentPDUs = ETrue. |
|
1127 // When doing a retransmission the I-Frame has already had its Tx Seq |
|
1128 // value set and iRetransTxVal is incremented so that we will continue |
|
1129 // iterating through the sent PDUs for retransmission. |
|
1130 // When sending a new I-Frame iNextTxSeq is used to get the next |
|
1131 // brand new Tx Seq value (given the limitations of wrapping round the number |
|
1132 // space). |
|
1133 if (!iRetransmitSentPDUs) |
|
1134 { |
|
1135 aIFrame->SetTxSeqNumber(iNextTxSeq); |
|
1136 iNextTxSeq = Mod64(iNextTxSeq + 1); |
|
1137 } |
|
1138 else |
|
1139 { |
|
1140 ++iRetransTxVal; |
|
1141 } |
|
1142 |
|
1143 LOG(_L("FEC CL2CapDataReTxController::HandleOutgoingIFrame")) |
|
1144 LOG1(_L("\tTxSeqNumber = %d"), (aIFrame->TxSeqNumber())) |
|
1145 |
|
1146 // If flow controlled off - don't acknowledge any new I-Frames |
|
1147 aIFrame->SetReqSeqNumber(iIncomingSduQFull ? iLastAckSentRxSeqNum : iExpectedTxSeq); |
|
1148 |
|
1149 // Set the retransmission disable bit if flow control is on. |
|
1150 aIFrame->SetRetransmitDisable(iIncomingSduQFull); |
|
1151 aIFrame->CalculateAndSetFCS(); |
|
1152 |
|
1153 aIFrame->iLink.Deque(); // may be on Sent PDU list if it's a retransmission |
|
1154 aIFrame->SetPduOwner(this); |
|
1155 iPendingSentPDUs.AddLast(*aIFrame); |
|
1156 if ((iSentPDUs.IsEmpty()) && iTimerMan.IsAckTimerRunning()) |
|
1157 { |
|
1158 iRestartAckTimer = EFalse; |
|
1159 iTimerMan.StartMonitorTimer(); |
|
1160 } |
|
1161 |
|
1162 // Cancel the peer ack timer. |
|
1163 iTimerMan.StopSendPeerAckTimer(); |
|
1164 iSendAckToPeer = EFalse; |
|
1165 |
|
1166 // Store the last acknowledged frame index. |
|
1167 if(!iIncomingSduQFull) |
|
1168 { |
|
1169 iLastAckSentRxSeqNum = iExpectedTxSeq; |
|
1170 } |
|
1171 LOG1(_L("\tLastAckSentRxSeqNum = %d"), iLastAckSentRxSeqNum) |
|
1172 |
|
1173 return KErrNone; |
|
1174 } |
|
1175 |
|
1176 TBool CL2CapDataReTxController::DeliverOutgoingDataAndSignalToSduQWhenDone() |
|
1177 { |
|
1178 LOG_FUNC |
|
1179 iDeliverOutgoingDataAndSignalToSduQWhenDone = ETrue; |
|
1180 // Returning true means we don't have any outstanding data to deliver and |
|
1181 // hence can be deleted immediately. |
|
1182 return iPendingSentPDUs.IsEmpty() && iSentPDUs.IsEmpty(); |
|
1183 } |
|
1184 |
|
1185 |
|
1186 RL2CapRetransmissionModeTimerManager::RL2CapRetransmissionModeTimerManager(MRetransmissionModeTimerClient& aClient) |
|
1187 : iClient(aClient) |
|
1188 { |
|
1189 LOG_FUNC |
|
1190 } |
|
1191 |
|
1192 void RL2CapRetransmissionModeTimerManager::Close() |
|
1193 { |
|
1194 LOG_FUNC |
|
1195 CancelFECTimer(); |
|
1196 StopSendPeerAckTimer(); |
|
1197 } |
|
1198 |
|
1199 void RL2CapRetransmissionModeTimerManager::StartMonitorTimer() |
|
1200 { |
|
1201 LOG_FUNC |
|
1202 // Monitor timer preempts the Ack timer, so we can stop whichever we have running. |
|
1203 CancelFECTimer(); |
|
1204 |
|
1205 TCallBack cb(FECTimerExpired, this); |
|
1206 iFECTimerEntry.Set(cb); |
|
1207 |
|
1208 // Set the timeout. The value is in Milliseconds. |
|
1209 BTSocketTimer::Queue(iClient.MonitorTimeout()*1000, iFECTimerEntry); |
|
1210 iFECTimerState = EMonitorTimerRunning; |
|
1211 } |
|
1212 |
|
1213 void RL2CapRetransmissionModeTimerManager::StartAckTimer() |
|
1214 { |
|
1215 LOG_FUNC |
|
1216 |
|
1217 if (iFECTimerState != EMonitorTimerRunning) |
|
1218 // Ack timer can't be run when the Monitor timer is running. |
|
1219 { |
|
1220 CancelFECTimer(); |
|
1221 |
|
1222 TCallBack cb(FECTimerExpired, this); |
|
1223 iFECTimerEntry.Set(cb); |
|
1224 |
|
1225 // Set the timeout. The value is in Milliseconds. |
|
1226 BTSocketTimer::Queue(iClient.RetransmissionTimeout()*1000, iFECTimerEntry); |
|
1227 iFECTimerState = EAckTimerRunning; |
|
1228 } |
|
1229 } |
|
1230 |
|
1231 void RL2CapRetransmissionModeTimerManager::StopMonitorTimer() |
|
1232 { |
|
1233 LOG_FUNC |
|
1234 if (iFECTimerState == EMonitorTimerRunning) |
|
1235 { |
|
1236 CancelFECTimer(); |
|
1237 } |
|
1238 } |
|
1239 |
|
1240 void RL2CapRetransmissionModeTimerManager::StopAckTimer() |
|
1241 { |
|
1242 LOG_FUNC |
|
1243 if (iFECTimerState == EAckTimerRunning) |
|
1244 { |
|
1245 CancelFECTimer(); |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 void RL2CapRetransmissionModeTimerManager::CancelFECTimer() |
|
1250 { |
|
1251 LOG_FUNC |
|
1252 // Cancel either the monitor or ack timer. |
|
1253 if(iFECTimerState != EFECTimerIdle) |
|
1254 { |
|
1255 // Cancel the current outgoing timer. |
|
1256 BTSocketTimer::Remove(iFECTimerEntry); |
|
1257 iFECTimerState = EFECTimerIdle; |
|
1258 } |
|
1259 } |
|
1260 |
|
1261 void RL2CapRetransmissionModeTimerManager::HandleFECTimerExpired() |
|
1262 { |
|
1263 LOG_FUNC |
|
1264 // Call the appropriate method to handle this expiry. |
|
1265 switch(iFECTimerState) |
|
1266 { |
|
1267 case EFECTimerIdle: |
|
1268 Panic(EL2CAPInvalidDataControllerTimerState); |
|
1269 break; |
|
1270 |
|
1271 case EMonitorTimerRunning: |
|
1272 iFECTimerState = EFECTimerIdle; |
|
1273 iClient.MonitorTimerExpired(); |
|
1274 break; |
|
1275 |
|
1276 case EAckTimerRunning: |
|
1277 iFECTimerState = EFECTimerIdle; |
|
1278 iClient.AckTimerExpired(); |
|
1279 break; |
|
1280 |
|
1281 default: |
|
1282 Panic(EL2CAPInvalidDataControllerTimerState); |
|
1283 break; |
|
1284 } |
|
1285 } |
|
1286 |
|
1287 void RL2CapRetransmissionModeTimerManager::HandleSendPeerAckTimerExpired() |
|
1288 { |
|
1289 LOG_FUNC |
|
1290 __ASSERT_ALWAYS(iSendPeerAckTimerRunning, Panic(EL2CAPInvalidDataControllerTimerState)); |
|
1291 iSendPeerAckTimerRunning = EFalse; |
|
1292 iClient.SendPeerAckTimerExpired(); |
|
1293 } |
|
1294 |
|
1295 TBool RL2CapRetransmissionModeTimerManager::StartSendPeerAckTimer() |
|
1296 { |
|
1297 LOG_FUNC |
|
1298 // This timer should only be started if the peer is using a long re-transmission timer. |
|
1299 __ASSERT_ALWAYS(!iSendPeerAckTimerRunning, Panic(EL2CAPInvalidDataControllerTimerState)); |
|
1300 |
|
1301 TInt peerAckTimer = iClient.PeerRetransmissionTimeout() - KAveTimeToTransmitAckToPeer; |
|
1302 if(peerAckTimer > KMinimumPeerAckTimeout) |
|
1303 { |
|
1304 TCallBack cb(SendPeerAckTimerExpired, this); |
|
1305 iSendPeerAckTimerEntry.Set(cb); |
|
1306 |
|
1307 // Set the timeout. The value os in Milliseconds. |
|
1308 BTSocketTimer::Queue(peerAckTimer*1000, iSendPeerAckTimerEntry); |
|
1309 iSendPeerAckTimerRunning = ETrue; |
|
1310 } |
|
1311 return iSendPeerAckTimerRunning; |
|
1312 } |
|
1313 |
|
1314 void RL2CapRetransmissionModeTimerManager::StopSendPeerAckTimer() |
|
1315 { |
|
1316 LOG_FUNC |
|
1317 if (iSendPeerAckTimerRunning) |
|
1318 { |
|
1319 BTSocketTimer::Remove(iSendPeerAckTimerEntry); |
|
1320 iSendPeerAckTimerRunning = EFalse; |
|
1321 } |
|
1322 } |
|
1323 |
|
1324 /*static*/ TInt RL2CapRetransmissionModeTimerManager::SendPeerAckTimerExpired(TAny* aTimerMan) |
|
1325 { |
|
1326 LOG_STATIC_FUNC |
|
1327 RL2CapRetransmissionModeTimerManager* timerMan = reinterpret_cast<RL2CapRetransmissionModeTimerManager*>(aTimerMan); |
|
1328 timerMan->HandleSendPeerAckTimerExpired(); |
|
1329 return EFalse; |
|
1330 } |
|
1331 |
|
1332 /*static*/ TInt RL2CapRetransmissionModeTimerManager::FECTimerExpired(TAny* aTimeMan) |
|
1333 { |
|
1334 LOG_STATIC_FUNC |
|
1335 RL2CapRetransmissionModeTimerManager* timeMan = reinterpret_cast<RL2CapRetransmissionModeTimerManager*>(aTimeMan); |
|
1336 timeMan->HandleFECTimerExpired(); |
|
1337 return EFalse; |
|
1338 } |