|
1 // Copyright (c) 2008-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 "btsockettimer.h" |
|
18 #include "L2CapEnhancedDataController.h" |
|
19 #include "L2CapSDUQueue.h" |
|
20 #include "l2signalmgr.h" |
|
21 #include "l2util.h" |
|
22 #include "L2CapDebugControlInterface.h" |
|
23 |
|
24 #ifdef __FLOG_ACTIVE |
|
25 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP_DATA_CONTROLLER); |
|
26 #endif |
|
27 |
|
28 using namespace L2CapDataUtils; |
|
29 |
|
30 |
|
31 CL2CapStreamingController::CL2CapStreamingController(TL2CAPPort aLocalCID, |
|
32 TL2CAPPort aRemoteCID, |
|
33 CL2CAPMux& aMuxer, |
|
34 CL2CapSDUQueue& aSDUQueue, |
|
35 TL2CapDataControllerConfig* aConfig) |
|
36 : CL2CapBasicDataController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig, EFalse) |
|
37 { |
|
38 LOG_FUNC |
|
39 } |
|
40 |
|
41 CL2CapStreamingController::~CL2CapStreamingController() |
|
42 { |
|
43 LOG_FUNC |
|
44 } |
|
45 |
|
46 void CL2CapStreamingController::ProcessFlushTimerExpiry() |
|
47 { |
|
48 LOG_FUNC |
|
49 __ASSERT_DEBUG(EFalse, Panic(EL2CAPFlushingNotReallySupported)); |
|
50 } |
|
51 |
|
52 HL2CapPDU* CL2CapStreamingController::GetPduL() |
|
53 { |
|
54 LOG_FUNC |
|
55 // This is called from the signal manager. |
|
56 HL2CapPDU* pduToSend = NULL; |
|
57 |
|
58 pduToSend = iSDUQueue.GetPDU(); |
|
59 |
|
60 if(pduToSend) |
|
61 { |
|
62 pduToSend->DeliverOutgoingPDU(*this); |
|
63 } |
|
64 |
|
65 if (iSDUQueue.HavePDUToSend()) |
|
66 { |
|
67 iMuxer.PDUAvailable(); |
|
68 } |
|
69 |
|
70 return pduToSend; |
|
71 } |
|
72 |
|
73 void CL2CapStreamingController::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
74 { |
|
75 LOG_FUNC |
|
76 |
|
77 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
78 |
|
79 if (txSeq != iExpectedTxSeq) |
|
80 { |
|
81 // SDU currently being assembled is no good now. Need to tell the SDU Q to flush |
|
82 // it, otherwise if we lost the right amount of I-Frames, we would end up assembling |
|
83 // an FDU (Frankenstein Data Unit) - half SDU number n, half SDU number n+1. |
|
84 // Note that FDUs are still possible if 63 frames are lost. There'se no notion of |
|
85 // SDU checksumming in the protocol, so that can't be prevented. |
|
86 iSDUQueue.FlushCurrentlyAssembledSdu(); |
|
87 } |
|
88 |
|
89 if (iSDUQueue.IsIncomingQueueFull()) |
|
90 { |
|
91 // Make room for new data. From the spec: |
|
92 // "If there is no buffer space for the received I-frame an existing I-frame |
|
93 // (i.e. the oldest) shall be discarded (flushed) freeing up buffer space for |
|
94 // the new I-frame. The discarded I-frame shall be marked as missing." |
|
95 iSDUQueue.FlushOldestIncomingSdu(); |
|
96 } |
|
97 LEAVEIFERRORL(iSDUQueue.PutIFramePDU(aIFrame)); |
|
98 |
|
99 iExpectedTxSeq = Mod64(txSeq + 1); |
|
100 |
|
101 // SDU Q sucks out the content, so we can free the frame whether it's been consumed or dropped. |
|
102 aIFrame.Free(); |
|
103 } |
|
104 |
|
105 TInt CL2CapStreamingController::HandleOutgoingIFrame(HIFramePDU* aIFrame) |
|
106 { |
|
107 LOG_FUNC |
|
108 aIFrame->SetPDUCID(iRemoteCID); |
|
109 aIFrame->SetTxSeqNumber(iNextTxSeq); |
|
110 iNextTxSeq = Mod64(iNextTxSeq + 1); |
|
111 |
|
112 // The Control field is zero-ed when the frame is created. |
|
113 |
|
114 aIFrame->CalculateAndSetFCS(); |
|
115 |
|
116 return KErrNone; |
|
117 } |
|
118 |
|
119 void CL2CapStreamingController::HandlePduSendComplete(HL2CapPDU& aPdu) |
|
120 { |
|
121 LOG_FUNC |
|
122 delete &aPdu; |
|
123 } |
|
124 |
|
125 void CL2CapStreamingController::HandlePduSendError(HL2CapPDU& aPdu) |
|
126 { |
|
127 LOG_FUNC |
|
128 delete &aPdu; |
|
129 } |
|
130 |
|
131 |
|
132 RL2CapErtmTimerManager::RL2CapErtmTimerManager(CL2CapEnhancedReTxController& aClient) |
|
133 : RL2CapRetransmissionModeTimerManager(aClient), |
|
134 iLocalBusyDelayTimerRunning(EFalse) |
|
135 { |
|
136 LOG_FUNC |
|
137 } |
|
138 |
|
139 void RL2CapErtmTimerManager::Close() |
|
140 { |
|
141 LOG_FUNC |
|
142 StopLocalBusyDelayTimer(); |
|
143 RL2CapRetransmissionModeTimerManager::Close(); |
|
144 } |
|
145 |
|
146 void RL2CapErtmTimerManager::StartLocalBusyDelayTimer() |
|
147 { |
|
148 LOG_FUNC |
|
149 // Shouldn't happen, but no big deal if it does. |
|
150 __ASSERT_DEBUG(!iLocalBusyDelayTimerRunning, Panic(EL2CAPInvalidDataControllerTimerState)); |
|
151 |
|
152 if (!iLocalBusyDelayTimerRunning) |
|
153 { |
|
154 TCallBack cb(LocalBusyDelayTimerExpired, this); |
|
155 iLocalBusyDelayTimerEntry.Set(cb); |
|
156 |
|
157 // Set the timeout. The value is in Milliseconds. |
|
158 BTSocketTimer::Queue((iClient.PeerRetransmissionTimeout() * 1000) / KLocalBusyDelayTimerDenominator, |
|
159 iLocalBusyDelayTimerEntry); |
|
160 iLocalBusyDelayTimerRunning = ETrue; |
|
161 } |
|
162 } |
|
163 |
|
164 void RL2CapErtmTimerManager::StopLocalBusyDelayTimer() |
|
165 { |
|
166 LOG_FUNC |
|
167 if (iLocalBusyDelayTimerRunning) |
|
168 { |
|
169 BTSocketTimer::Remove(iLocalBusyDelayTimerEntry); |
|
170 iLocalBusyDelayTimerRunning = EFalse; |
|
171 } |
|
172 } |
|
173 |
|
174 void RL2CapErtmTimerManager::HandleLocalBusyDelayTimerExpired() |
|
175 { |
|
176 LOG_FUNC |
|
177 iLocalBusyDelayTimerRunning = EFalse; |
|
178 static_cast<CL2CapEnhancedReTxController&>(iClient).LocalBusyDelayTimerExpired(); |
|
179 } |
|
180 |
|
181 /*static*/ TInt RL2CapErtmTimerManager::LocalBusyDelayTimerExpired(TAny* aTimerMan) |
|
182 { |
|
183 LOG_STATIC_FUNC |
|
184 RL2CapErtmTimerManager* timerMan = reinterpret_cast<RL2CapErtmTimerManager*>(aTimerMan); |
|
185 timerMan->HandleLocalBusyDelayTimerExpired(); |
|
186 return EFalse; |
|
187 } |
|
188 |
|
189 |
|
190 |
|
191 RL2CapErtmUnacknowledgedIFrames::RL2CapErtmUnacknowledgedIFrames() |
|
192 : iFrameList(_FOFF(HIFramePDU, iLink)) |
|
193 { |
|
194 LOG_FUNC |
|
195 iFrameIndex.Reset(); |
|
196 } |
|
197 |
|
198 void RL2CapErtmUnacknowledgedIFrames::Close() |
|
199 { |
|
200 LOG_FUNC |
|
201 |
|
202 // Some PDUs may hold a reference to this data controller. |
|
203 TDblQueIter<HIFramePDU> unackedIter(iFrameList); |
|
204 HIFramePDU* pdu; |
|
205 |
|
206 while((pdu = unackedIter++) != NULL) |
|
207 { |
|
208 Remove(*pdu); |
|
209 if (!pdu->IsAwaitingHciCompletion()) |
|
210 { |
|
211 delete pdu; |
|
212 } |
|
213 else |
|
214 { |
|
215 // Will delete itself on HCI completion. |
|
216 pdu->DeregisterPduOwner(); |
|
217 } |
|
218 } |
|
219 } |
|
220 |
|
221 |
|
222 CL2CapErtmDataTransmitter* CL2CapErtmDataTransmitter::NewL(CL2CapEnhancedReTxController& aController) |
|
223 { |
|
224 LOG_STATIC_FUNC |
|
225 return new (ELeave) CL2CapErtmDataTransmitter(aController); |
|
226 } |
|
227 |
|
228 CL2CapErtmDataTransmitter::~CL2CapErtmDataTransmitter() |
|
229 { |
|
230 LOG_FUNC |
|
231 iUnackedIFrames.Close(); |
|
232 } |
|
233 |
|
234 CL2CapErtmDataTransmitter::CL2CapErtmDataTransmitter(CL2CapEnhancedReTxController& aController) |
|
235 : iController(aController), |
|
236 iNextTxSeq(0), |
|
237 iExpectedAckSeq(0), |
|
238 iRemoteBusy(EFalse), |
|
239 iSRejActioned(EFalse), |
|
240 iSRejSaveReqSeq(0), |
|
241 iWaitAckStatePending(EFalse), |
|
242 iInWaitAckState(EFalse) |
|
243 { |
|
244 LOG_FUNC |
|
245 } |
|
246 |
|
247 void CL2CapErtmDataTransmitter::HandleIncomingIFrame(RMBufChain& aIFrame) |
|
248 { |
|
249 LOG_FUNC |
|
250 LOG2(_L("NextTxSeq=%d, ExpectedAckSeq = %d"), iNextTxSeq, iExpectedAckSeq) |
|
251 |
|
252 const TUint8 reqSeq = HIFramePDU::ReqSeqNumber(aIFrame); |
|
253 const TBool final = HIFramePDU::FinalBit(aIFrame); |
|
254 |
|
255 HandleReqSeqAck(reqSeq); |
|
256 if (final) |
|
257 { |
|
258 HandleFinalAck(); |
|
259 } |
|
260 } |
|
261 |
|
262 void CL2CapErtmDataTransmitter::HandleIncomingSFrameL(RMBufChain& aSFrame) |
|
263 { |
|
264 LOG_FUNC |
|
265 LOG2(_L("NextTxSeq=%d, ExpectedAckSeq = %d"), iNextTxSeq, iExpectedAckSeq) |
|
266 |
|
267 const TUint8 reqSeq = HSFramePDU::ReqSeqNumber(aSFrame); |
|
268 const TSupervisoryFunction function = HSFramePDU::SupervisoryFunction(aSFrame); |
|
269 const TBool final = HSFramePDU::FinalBit(aSFrame); |
|
270 const TBool poll = HSFramePDU::PollBit(aSFrame); |
|
271 |
|
272 // An S-Frame [SREJ] with the POLL=0 does NOT acknowledge any I-Frames. |
|
273 if (!(function == ESelectiveReject && !poll)) |
|
274 { |
|
275 HandleReqSeqAck(reqSeq); |
|
276 } |
|
277 else // SREJ [P=0] |
|
278 { |
|
279 // The remote detected packet loss itself, so restart the retransmission timer - |
|
280 // - SREJ -> I-Frame -> RR roundtrip time is too long and would almost always |
|
281 // cause it to expire if we didn't (most probably unnecessarily). |
|
282 if (TimerMan().IsAckTimerRunning()) |
|
283 { |
|
284 TimerMan().StartAckTimer(); |
|
285 } |
|
286 } |
|
287 |
|
288 switch (function) |
|
289 { |
|
290 case EReceiverNotReady: |
|
291 iRemoteBusy = ETrue; |
|
292 TimerMan().StopAckTimer(); |
|
293 if (final && iInWaitAckState) |
|
294 { |
|
295 iInWaitAckState = EFalse; |
|
296 // We'll start retransmitting when we get RR from the peer. |
|
297 } |
|
298 break; |
|
299 |
|
300 case EReceiverReady: |
|
301 if (final) |
|
302 { |
|
303 HandleFinalAck(); |
|
304 } |
|
305 // iRemoteBusy cleared at the bottom of the function. |
|
306 break; |
|
307 |
|
308 case EReject: |
|
309 // A REJ should be ignored if we're in WAIT_ACK and the Final bit in the |
|
310 // frame is 0. We'll receive a Final packet in a while anyway, and that |
|
311 // packet is guaranteed to contain the same ReqSeq, because the remote |
|
312 // can't acknowledge anything new until we retransmit, and we won't |
|
313 // retransmit until we receive the Final ack. |
|
314 if (!(iInWaitAckState && !final)) |
|
315 { |
|
316 RetransmitUnackedIFrames(); |
|
317 |
|
318 TimerMan().StopAckTimer(); |
|
319 // The timer will be started again when the first retransmitted I-Frame |
|
320 // is completed. |
|
321 } |
|
322 |
|
323 if (final) |
|
324 { |
|
325 HandleFinalAck(); |
|
326 } |
|
327 // iRemoteBusy cleared at the bottom of the function. |
|
328 break; |
|
329 |
|
330 case ESelectiveReject: |
|
331 HandleIncomingSRejL(aSFrame); |
|
332 // iRemoteBusy cleared at the bottom of the function. |
|
333 break; |
|
334 } |
|
335 |
|
336 // Anything other than RNR means remote isn't busy anymore. |
|
337 if (iRemoteBusy && function != EReceiverNotReady) |
|
338 { |
|
339 __ASSERT_DEBUG(!TimerMan().IsAckTimerRunning(), Panic(EL2CAPAckTimerRunningWhenRemoteBusy)); |
|
340 iRemoteBusy = EFalse; |
|
341 if (!iUnackedIFrames.IsEmpty()) |
|
342 { |
|
343 TimerMan().StartAckTimer(); |
|
344 } |
|
345 LOG(_L("Exitted RemoteBusy condition")) |
|
346 } |
|
347 } |
|
348 |
|
349 void CL2CapErtmDataTransmitter::HandleIncomingSRejL(RMBufChain& aSRejFrame) |
|
350 { |
|
351 LOG_FUNC |
|
352 |
|
353 const TUint8 reqSeq = HSFramePDU::ReqSeqNumber(aSRejFrame); |
|
354 const TSupervisoryFunction function = HSFramePDU::SupervisoryFunction(aSRejFrame); |
|
355 const TBool final = HSFramePDU::FinalBit(aSRejFrame); |
|
356 const TBool poll = HSFramePDU::PollBit(aSRejFrame); |
|
357 |
|
358 HIFramePDU* requestedIFrame = iUnackedIFrames[reqSeq]; |
|
359 // If the ReqSeq is invalid then it should've been caught earlier. |
|
360 __ASSERT_ALWAYS(requestedIFrame != NULL, Panic(EL2CAPSRejReqSeqNotOnUnackedList)); |
|
361 |
|
362 if (poll) |
|
363 { |
|
364 // Set the Final bit directly here to make sure it's in the right frame. |
|
365 requestedIFrame->SetFinalBit(ETrue); |
|
366 SendOrPendL(*requestedIFrame); |
|
367 |
|
368 if (iController.IsPollOutstanding()) |
|
369 { |
|
370 iSRejActioned = ETrue; |
|
371 iSRejSaveReqSeq = reqSeq; |
|
372 // If Poll is set, then Final must be 0, so we don't have to check for it. |
|
373 } |
|
374 } // Poll = 1 |
|
375 else |
|
376 { |
|
377 // If peer is in SREJ_SENT when it receives the Poll, then it needs to respond |
|
378 // with an SREJ[F=1]. This SREJ may contain a ReqSeq it has already sent in the |
|
379 // previous SREJ[F=0], and we need to guard against this on our side, so that we |
|
380 // don't retransmit a packet twice - it could cause the channel to be closed, as |
|
381 // the second copy would be outside of peer's receive window and thus invalid. |
|
382 TBool duplicateWithFinal = EFalse; |
|
383 |
|
384 if (iController.IsPollOutstanding()) |
|
385 { |
|
386 if (final) |
|
387 { |
|
388 if (iSRejActioned && iSRejSaveReqSeq == reqSeq) |
|
389 { |
|
390 // Peer has sent us a SREJ F=0 for the same frame before, need to |
|
391 // ignore this SREJ. |
|
392 duplicateWithFinal = ETrue; |
|
393 LOG1(_L("Received a duplicate SREJ with ReqSeq=%d with Final=1, will drop it"), |
|
394 reqSeq) |
|
395 } |
|
396 |
|
397 if (!iUnackedIFrames.IsEmpty() && !iRemoteBusy) |
|
398 { |
|
399 TimerMan().StartAckTimer(); |
|
400 } |
|
401 |
|
402 iSRejActioned = EFalse; |
|
403 iInWaitAckState = EFalse; |
|
404 // Don't go into ERetransmitAllUnackedFrames, even in WAIT_ACK: |
|
405 // - an SREJ[P=0,F=1] frame doesn't carry an acking ReqSeq, so we |
|
406 // wouldn't know at which frame we should start the retransmission; |
|
407 // - the peer has just SREJed some I-Frames so there's a chance |
|
408 // we're already retransmitting the stuff we timed out on. |
|
409 // If we're not (which is possible if acknowledgments from the |
|
410 // peer have been lost), then we'll need to wait for the |
|
411 // next Retransmission Timeout and then retransmit (unless we |
|
412 // we hit remote being in SREJ_SENT again, rinse-and-repeat then). |
|
413 OutgoingQ().SendPendingRetransmitIFramesL(); |
|
414 } |
|
415 else |
|
416 { |
|
417 iSRejActioned = ETrue; |
|
418 iSRejSaveReqSeq = reqSeq; |
|
419 } |
|
420 } // waiting for final ack |
|
421 |
|
422 if (!duplicateWithFinal) |
|
423 { |
|
424 // Clean the F-bit in case it was set during previous transmission. |
|
425 requestedIFrame->SetFinalBit(EFalse); |
|
426 SendOrPendL(*requestedIFrame); |
|
427 } |
|
428 } // Poll bit = 0 |
|
429 } |
|
430 |
|
431 void CL2CapErtmDataTransmitter::HciCompletedIFrame(HIFramePDU& aIFrame) |
|
432 { |
|
433 LOG_FUNC |
|
434 if (aIFrame.Acked()) |
|
435 { |
|
436 __ASSERT_DEBUG(iUnackedIFrames[aIFrame.TxSeqNumber()] == NULL, |
|
437 Panic(EL2CAPAckedTxSeqFoundOnUnackedList)); |
|
438 |
|
439 // This condition will happen extremely rarely or none at all on real hardware. |
|
440 // It does happen on the emulator with USB HCTL. |
|
441 LOG1(_L("I-Frame %d has been acknowledged before HCI completion"), aIFrame.TxSeqNumber()) |
|
442 // Frame has been already sent and acked - skip putting it on the Send queue, just delete. |
|
443 delete &aIFrame; |
|
444 // We'll start the retransmission timer the first time a frame that hasn't been acked is |
|
445 // completed (the else branch below). |
|
446 } |
|
447 else |
|
448 { |
|
449 __ASSERT_DEBUG(iUnackedIFrames[aIFrame.TxSeqNumber()] != NULL, |
|
450 Panic(EL2CAPUnackedTxSeqNotFoundOnUnackedList)); |
|
451 |
|
452 if (!TimerMan().IsAckTimerRunning() && !iRemoteBusy) |
|
453 { |
|
454 // It's the first frame sent out after a period of silence. |
|
455 // ... or it's the first frame of a retransmission. |
|
456 // ... or we can has a bug (LOL that's impossible, I coded this myself). |
|
457 TimerMan().StartAckTimer(); |
|
458 } |
|
459 } |
|
460 } |
|
461 |
|
462 void CL2CapErtmDataTransmitter::AckTimerExpired() |
|
463 { |
|
464 LOG_FUNC |
|
465 __ASSERT_DEBUG(!iUnackedIFrames.IsEmpty(), Panic(EL2CAPAckTimerExpiryWithoutPDUToSupervise)); |
|
466 // Signal to GetPdu that we need to enter WAIT_ACK. |
|
467 iWaitAckStatePending = ETrue; |
|
468 iController.NotifyMuxerOfPdusToSendIfHaveSome(); |
|
469 } |
|
470 |
|
471 HIFramePDU* CL2CapErtmDataTransmitter::GetIFrameToSendL() |
|
472 { |
|
473 LOG_FUNC |
|
474 HIFramePDU* pduToSend = NULL; |
|
475 |
|
476 // Can't send data in WAIT_ACK. |
|
477 // We send data in RemoteBusy until the window fills up, but with the ack timer stopped. |
|
478 if (!iInWaitAckState) |
|
479 { |
|
480 if (iUnackedIFrames[iNextTxSeq] != NULL) |
|
481 { |
|
482 // Rreceived a REJ or Ack timer expired. |
|
483 pduToSend = iUnackedIFrames[iNextTxSeq]; |
|
484 if (pduToSend->IsAwaitingHciCompletion()) |
|
485 { |
|
486 pduToSend = NULL; |
|
487 } |
|
488 else |
|
489 { |
|
490 // In case it was set for the previous transmission. |
|
491 pduToSend->SetFinalBit(EFalse); |
|
492 } |
|
493 } |
|
494 else if (HaveSpaceInOutgoingWindow()) |
|
495 { |
|
496 pduToSend = static_cast<HIFramePDU*>(iController.SDUQueue().GetPDU()); |
|
497 if (pduToSend != NULL) |
|
498 { |
|
499 pduToSend->SetTxSeqNumber(iNextTxSeq); |
|
500 // It's a new frame that hasn't been sent before, so we need to append it to the |
|
501 // unacked list. Once put on the list, it should never get delinked from it until |
|
502 // acknowledged, even during retransmissions. |
|
503 __ASSERT_DEBUG(iUnackedIFrames[iNextTxSeq] == NULL, Panic(EL2CAPNewTxSeqFoundOnUnackedList)); |
|
504 iUnackedIFrames.Append(*pduToSend); |
|
505 } |
|
506 } |
|
507 |
|
508 if (pduToSend != NULL) |
|
509 { |
|
510 iNextTxSeq = Mod64(iNextTxSeq + 1); |
|
511 } |
|
512 } // state != WAIT_ACK (can transmit data) |
|
513 return pduToSend; |
|
514 } |
|
515 |
|
516 TBool CL2CapErtmDataTransmitter::HaveSpaceInOutgoingWindow() const |
|
517 { |
|
518 LOG_FUNC |
|
519 TBool canSend = ETrue; |
|
520 if (Mod64(iNextTxSeq - iExpectedAckSeq) >= iController.Config().TXWindowSize()) |
|
521 { |
|
522 canSend = EFalse; |
|
523 } |
|
524 return canSend; |
|
525 } |
|
526 |
|
527 void CL2CapErtmDataTransmitter::HandleFinalAck() |
|
528 { |
|
529 LOG_FUNC |
|
530 |
|
531 if (iInWaitAckState) |
|
532 { |
|
533 iInWaitAckState = EFalse; |
|
534 RetransmitUnackedIFrames(); |
|
535 } |
|
536 |
|
537 // Whether it was WAIT_ACK or WAIT_F, Ack timer was stopped because Monitor timer |
|
538 // was running. |
|
539 if (!iUnackedIFrames.IsEmpty() && !iRemoteBusy) |
|
540 { |
|
541 TimerMan().StartAckTimer(); |
|
542 } |
|
543 } |
|
544 |
|
545 void CL2CapErtmDataTransmitter::HandleReqSeqAck(TUint8 aReqSeq) |
|
546 { |
|
547 LOG_FUNC |
|
548 |
|
549 __ASSERT_DEBUG((aReqSeq == iExpectedAckSeq) || !iUnackedIFrames.IsEmpty(), |
|
550 Panic(EL2CAPUnacknowledgedPdusMissingFromList)); |
|
551 |
|
552 // See if any I-Frames have been acknowledged by the peer, slide the send window, |
|
553 // send new data if window space is now available, restart ack timer. |
|
554 |
|
555 if (!iUnackedIFrames.IsEmpty() && aReqSeq != iExpectedAckSeq) |
|
556 { |
|
557 const TBool wasWindowFull = !HaveSpaceInOutgoingWindow(); |
|
558 |
|
559 TDblQueIter<HIFramePDU> iter(iUnackedIFrames.Iterator()); |
|
560 HIFramePDU* pduPtr; |
|
561 TBool ackedPDUs = EFalse; |
|
562 |
|
563 __ASSERT_DEBUG(iUnackedIFrames.First()->TxSeqNumber() == iExpectedAckSeq, |
|
564 Panic(EL2CAPOldestUnackedPduTxSeqNotMatchingExpectedAck)); |
|
565 |
|
566 while ((pduPtr = iter++) != NULL) |
|
567 { |
|
568 if (InWindow(pduPtr->TxSeqNumber(), iExpectedAckSeq, Mod64(aReqSeq - 1))) |
|
569 { |
|
570 iUnackedIFrames.Remove(*pduPtr); |
|
571 pduPtr->SetAcked(ETrue); |
|
572 ackedPDUs = ETrue; |
|
573 |
|
574 if (!pduPtr->IsAwaitingHciCompletion()) |
|
575 { |
|
576 delete pduPtr; |
|
577 } |
|
578 else |
|
579 { |
|
580 LOG1(_L("I-Frame %d has been acknowledged before HCI completion!"), |
|
581 pduPtr->TxSeqNumber()) |
|
582 // Will delete itself on HCI completion. |
|
583 pduPtr->DeregisterPduOwner(); |
|
584 } |
|
585 } // pdu in acked window |
|
586 else |
|
587 { |
|
588 // The queue is sorted chronologically - the head is always the oldest PDU. |
|
589 // First PDU outside of the acknowledged window means we can stop the loop. |
|
590 break; |
|
591 } |
|
592 } |
|
593 |
|
594 if (iUnackedIFrames.IsEmpty()) |
|
595 { |
|
596 TimerMan().StopAckTimer(); |
|
597 } |
|
598 else if (ackedPDUs && !iRemoteBusy) |
|
599 { |
|
600 // This will actually REstart the timer. |
|
601 TimerMan().StartAckTimer(); |
|
602 } |
|
603 |
|
604 iExpectedAckSeq = aReqSeq; |
|
605 LOG1(_L("New ExpectedAckSeq=%d"), aReqSeq) |
|
606 |
|
607 if (iController.IsOutgoingDataPathClosing() && iUnackedIFrames.IsEmpty()) |
|
608 { |
|
609 iController.SignalOutgoingDataDeliveredToSduQ(); |
|
610 } |
|
611 } |
|
612 } |
|
613 |
|
614 void CL2CapErtmDataTransmitter::RetransmitUnackedIFrames() |
|
615 { |
|
616 LOG_FUNC |
|
617 LOG1(_L("Setting NextTxSeq to ExpectedAckSeq = %d"), iExpectedAckSeq) |
|
618 iNextTxSeq = iExpectedAckSeq; |
|
619 // This is important when exiting WAIT_ACK: forget about all I-Frames SREJ-requested |
|
620 // by the peer. We'll retransmit them as part of the whole bunch. And we can't transmit |
|
621 // the same frame twice, which would happen had we left these hanging around. |
|
622 OutgoingQ().CancelPendingRetransmitIFrames(); |
|
623 } |
|
624 |
|
625 |
|
626 TL2CapErtmMissingTxSeqs::TL2CapErtmMissingTxSeqs() |
|
627 : iNumMissingTxSeqs(0), |
|
628 iExpectedRecvIdx(0), |
|
629 iResendIdx(0) |
|
630 {} |
|
631 |
|
632 TBool TL2CapErtmMissingTxSeqs::IsTxSeqOnTheList(TUint8 aTxSeq) const |
|
633 { |
|
634 TBool found = EFalse; |
|
635 for (TInt i = 0; i < iNumMissingTxSeqs && !found; i++) |
|
636 { |
|
637 if (iMissingTxSeqs[i] == aTxSeq) |
|
638 { |
|
639 found = ETrue; |
|
640 } |
|
641 } |
|
642 return found; |
|
643 } |
|
644 |
|
645 TBool TL2CapErtmMissingTxSeqs::ReceivedTxSeq(TUint8 aTxSeq) |
|
646 { |
|
647 LOG_FUNC |
|
648 TBool resendNeeded = EFalse; |
|
649 if (iMissingTxSeqs[iExpectedRecvIdx] == aTxSeq) |
|
650 { |
|
651 // This is the only path possible with the default of max. 1 SREJ at a time. |
|
652 iExpectedRecvIdx++; |
|
653 } |
|
654 else |
|
655 { |
|
656 // Should only fall here with the experimental KMaxSRejsInFlight > 1 |
|
657 __ASSERT_DEBUG(KMaxSRejsInFlight > 1, Panic(EL2CAPMultiSRejPathHitWhenNotSoConfigured)); |
|
658 |
|
659 LOG1(_L("SREJ resend path hit, TxSeq=%d"), aTxSeq); |
|
660 #ifdef __FLOG_ACTIVE |
|
661 Log(); |
|
662 #endif |
|
663 resendNeeded = ETrue; |
|
664 |
|
665 // General idea: reshuffle the array to maintain chronological ordering, in which |
|
666 // we expect the requested I-Frames to come through. All I-Frames between iExpectedRecvIdx |
|
667 // and the one we're processing now are considered to have been lost and will be |
|
668 // re-requested, so we need to move them to the very end of the list. |
|
669 // |
|
670 // E.g.: |
|
671 // 0. Current list is 6 elements (iNumMissingTxSeqs == 6): |
|
672 // 32 33 | 20 21 45 46 |
|
673 // 32 and 33 have been received (iExpectedRecvIdx == 2), we're still waiting for the |
|
674 // rest. |
|
675 // 1. 45 comes through, we fall here. We need to move it to right after 33 and increase |
|
676 // iExpectedRecvIdx: |
|
677 // 32 33 45 | 20 21 46 |
|
678 // 2. But the order in the array implied that 20 & 21 were requested before 45 and |
|
679 // haven't come through, so they must have been lost (remote has to respond to SREJs |
|
680 // in order they are sent). Ergo, we need to resend the SREJs for 20 and 21, which in |
|
681 // turn means we're now expecting them after all other frames, so finally: |
|
682 // 32 33 45 | 46 20 21 |
|
683 |
|
684 // Find the index of the received TxSeq. |
|
685 TInt receivedIdx = iExpectedRecvIdx; |
|
686 while (iMissingTxSeqs[receivedIdx] != aTxSeq && receivedIdx < iNumMissingTxSeqs) |
|
687 { |
|
688 receivedIdx++; |
|
689 } |
|
690 |
|
691 const TInt numToResend = receivedIdx - iExpectedRecvIdx; |
|
692 LOG2(_L("Last received = %d, num SREJs to resend = %d"), |
|
693 (iExpectedRecvIdx > 0 ? iMissingTxSeqs[iExpectedRecvIdx] : -1), numToResend); |
|
694 |
|
695 // To maintain the partitioning of the array we need to move the received |
|
696 // TxSeq towards the < iExpectedRecvIdx half, over the to-be-SREJed again TxSeqs. |
|
697 // (step 1 in the example) |
|
698 while (receivedIdx > iExpectedRecvIdx) |
|
699 { |
|
700 TUint8 tmp = iMissingTxSeqs[receivedIdx - 1]; |
|
701 iMissingTxSeqs[receivedIdx - 1] = iMissingTxSeqs[receivedIdx]; |
|
702 iMissingTxSeqs[receivedIdx] = tmp; |
|
703 receivedIdx--; |
|
704 } |
|
705 iExpectedRecvIdx++; |
|
706 |
|
707 // Now move the TxSeqs to be SREJed again onto the end of the list to maintain correct |
|
708 // ordering (step 2 in the example). |
|
709 // Note: this could be optimized a bit at least theoretically down to O(1) by |
|
710 // copying the TxSeqs to re-SREJ out to a temp array, then moving the ones currently |
|
711 // at the end, and then copying the ones from the temp array back in at the end. |
|
712 // Note 2: this is the first time I've used bubble sort in my carreer. Honest. |
|
713 for (TInt i = 0; i < numToResend; i++) |
|
714 { |
|
715 for (TInt bubble = iExpectedRecvIdx; bubble < iNumMissingTxSeqs - 1; bubble++) |
|
716 { |
|
717 TUint8 tmp = iMissingTxSeqs[bubble]; |
|
718 iMissingTxSeqs[bubble] = iMissingTxSeqs[bubble + 1]; |
|
719 iMissingTxSeqs[bubble + 1] = tmp; |
|
720 } |
|
721 } |
|
722 |
|
723 // Store the index of the beginning of the TxSeqs to re-request, they will be pulled |
|
724 // in an outer loop until the index reaches iNumMissingTxSeqs. |
|
725 iResendIdx = iNumMissingTxSeqs - numToResend; |
|
726 #ifdef __FLOG_ACTIVE |
|
727 Log(); |
|
728 #endif |
|
729 } |
|
730 return resendNeeded; |
|
731 } |
|
732 |
|
733 #ifdef __FLOG_ACTIVE |
|
734 void TL2CapErtmMissingTxSeqs::Log() |
|
735 { |
|
736 LOG3(_L("ExpectedRecvIdx=%d, ResendIdx=%d, NumMissingTxSeqs=%d"), |
|
737 iExpectedRecvIdx, iResendIdx, iNumMissingTxSeqs); |
|
738 |
|
739 TBuf<256> buf; |
|
740 for (TInt i = 0; i < iNumMissingTxSeqs; i++) |
|
741 { |
|
742 buf.AppendFormat(_L("%d "), iMissingTxSeqs[i]); |
|
743 } |
|
744 LOG1(_L("%S"), &buf) |
|
745 } |
|
746 #endif |
|
747 |
|
748 |
|
749 TL2CapErtmReceiverStateBase::TL2CapErtmReceiverStateBase(CL2CapErtmDataReceiver& aReceiver) |
|
750 : iReceiver(aReceiver) |
|
751 { |
|
752 LOG_FUNC |
|
753 } |
|
754 |
|
755 void TL2CapErtmReceiverStateBase::EnterL(RMBufChain* /*aIFrame*/) |
|
756 { |
|
757 LOG_FUNC |
|
758 } |
|
759 |
|
760 void TL2CapErtmReceiverStateBase::ExitL() |
|
761 { |
|
762 LOG_FUNC |
|
763 } |
|
764 |
|
765 TBool TL2CapErtmReceiverStateBase::IsLocalBusySupported() const |
|
766 { |
|
767 LOG_FUNC |
|
768 return EFalse; |
|
769 } |
|
770 |
|
771 |
|
772 TL2CapErtmReceiverStateRecv::TL2CapErtmReceiverStateRecv(CL2CapErtmDataReceiver& aReceiver) |
|
773 : TL2CapErtmReceiverStateBase(aReceiver) |
|
774 { |
|
775 LOG_FUNC |
|
776 } |
|
777 |
|
778 void TL2CapErtmReceiverStateRecv::EnterL(RMBufChain* /*aIFrame*/) |
|
779 { |
|
780 LOG_FUNC |
|
781 |
|
782 if (iReceiver.IsIncomingSduQFull()) |
|
783 { |
|
784 // We may have transitioned from REJ_SENT or SREJ_SENT, which don't allow LocalBusy. |
|
785 // We can enter it now. |
|
786 iReceiver.TimerMan().StopLocalBusyDelayTimer(); |
|
787 iReceiver.UpdateLocalBusyStatusL(); |
|
788 } |
|
789 |
|
790 __ASSERT_DEBUG((iReceiver.IsIncomingSduQFull() && iReceiver.LocalBusy()) || |
|
791 (!iReceiver.IsIncomingSduQFull() && !iReceiver.LocalBusy()) || |
|
792 (iReceiver.IsIncomingSduQFull() && iReceiver.TimerMan().IsLocalBusyDelayTimerRunning()) || |
|
793 (!iReceiver.IsIncomingSduQFull() && !iReceiver.TimerMan().IsLocalBusyDelayTimerRunning()), |
|
794 Panic(EL2CapSduQAndLocalBusyStateInconsistent)); |
|
795 } |
|
796 |
|
797 void TL2CapErtmReceiverStateRecv::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
798 { |
|
799 LOG_FUNC |
|
800 __ASSERT_DEBUG((iReceiver.IsIncomingSduQFull() && iReceiver.LocalBusy()) || |
|
801 (!iReceiver.IsIncomingSduQFull() && !iReceiver.LocalBusy()) || |
|
802 (iReceiver.IsIncomingSduQFull() && iReceiver.TimerMan().IsLocalBusyDelayTimerRunning()) || |
|
803 (!iReceiver.IsIncomingSduQFull() && !iReceiver.TimerMan().IsLocalBusyDelayTimerRunning()), |
|
804 Panic(EL2CapSduQAndLocalBusyStateInconsistent)); |
|
805 |
|
806 __ASSERT_DEBUG(!iReceiver.IsIncomingSduQFull() || |
|
807 InWindow(iReceiver.TxSeqExpectedBySduQ(), iReceiver.BufferSeq(), iReceiver.ExpectedTxSeq()), |
|
808 Panic(EL2CAPTxSeqExpectedBySduQNotWithinBufferSeqAndExpectedTxSeq)); |
|
809 |
|
810 __ASSERT_DEBUG(iReceiver.IsIncomingSduQFull() || |
|
811 (iReceiver.ExpectedTxSeq() == iReceiver.BufferSeq() && |
|
812 iReceiver.BufferSeq() == iReceiver.TxSeqExpectedBySduQ()), |
|
813 Panic(EL2CAPExpectedTxSeqAndBufferSeqAndTxSeqExpectedBySduQNotEqualWhenIncomingQEmptyAndInRecvState)); |
|
814 |
|
815 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
816 |
|
817 TBool freeFrame = ETrue; |
|
818 |
|
819 if (iReceiver.ExpectedTxSeq() == txSeq) |
|
820 // With-Expected-TxSeq |
|
821 { |
|
822 iReceiver.IncExpectedTxSeq(); |
|
823 if (!iReceiver.IsIncomingSduQFull()) |
|
824 { |
|
825 iReceiver.SetBufferSeq(iReceiver.ExpectedTxSeq()); |
|
826 } |
|
827 iReceiver.PassToIncomingQL(aIFrame); |
|
828 freeFrame = EFalse; |
|
829 } |
|
830 else if (!iReceiver.LocalBusy()) |
|
831 { |
|
832 if (iReceiver.IsTxSeqUnexpected(txSeq)) |
|
833 // With-Unexpected-TxSeq |
|
834 { |
|
835 if (iReceiver.IsSRejPreferredToRej(iReceiver.ExpectedTxSeq(), txSeq)) |
|
836 { |
|
837 iReceiver.SetStateSRejSentL(aIFrame); |
|
838 freeFrame = EFalse; |
|
839 } |
|
840 else |
|
841 { |
|
842 if (iReceiver.BufferSeq() == iReceiver.ExpectedTxSeq()) |
|
843 { |
|
844 iReceiver.SetStateRejSentL(); |
|
845 } |
|
846 else |
|
847 { |
|
848 // BufferSeq != ExpectedTxSeq only when SDU Q is full or in SREJ_SENT. |
|
849 __ASSERT_DEBUG(iReceiver.IsIncomingSduQFull(), |
|
850 Panic(EL2CAPBufferSeqNotEqualToExpectedTxSeqWhenInRecvAndSduQNotFull)); |
|
851 |
|
852 __ASSERT_DEBUG(iReceiver.TimerMan().IsLocalBusyDelayTimerRunning(), |
|
853 Panic(EL2CAPLocalBusyDelayTimerNotRunningWhenSduQFullButNotInLB)); |
|
854 |
|
855 iReceiver.TimerMan().StopLocalBusyDelayTimer(); |
|
856 |
|
857 iReceiver.UpdateLocalBusyStatusL(); |
|
858 } |
|
859 } |
|
860 } // Unexpected TxSeq |
|
861 // else must be duplicate (With-Duplicate-TxSeq), in which case we just drop it |
|
862 } // !LocalBusy |
|
863 // LocalBusy and !ExpectedTxSeq - drop it - the remote will initiate a retransmission |
|
864 // when we exit LocalBusy anyway. |
|
865 |
|
866 if (freeFrame) |
|
867 { |
|
868 aIFrame.Free(); |
|
869 } |
|
870 } |
|
871 |
|
872 void TL2CapErtmReceiverStateRecv::HandlePollL() |
|
873 { |
|
874 LOG_FUNC |
|
875 if (iReceiver.IsIncomingSduQFull()) |
|
876 { |
|
877 // If the Poll is a result of the peer's retransmission timer expiry, then the peer will |
|
878 // start retransmitting I-Frames from the sequence number given here by us (our current |
|
879 // BufferSeq). Basically, the point of a Poll in WAIT_ACK is the peer asking "what have |
|
880 // you received, need to know where to start retransmitting from", and we're supposed |
|
881 // to be honest. |
|
882 // Otherwise, if our upper layer Read()s and we process buffered I-Frames between now |
|
883 // and the moment the first retransmitted packet comes through, we will have moved |
|
884 // BufferSeq and render that packet invalid (a duplicate effectively). Therefore we |
|
885 // need to drop the buffered I-Frames to prevent duplicates and guarantee that BufferSeq |
|
886 // won't move. |
|
887 iReceiver.FlushBufferedIncomingIFrames(); |
|
888 |
|
889 // Incoming I-Frame buffer empty and state = RECV: |
|
890 __ASSERT_DEBUG(// no buffered I-Frames |
|
891 iReceiver.ExpectedTxSeq() == iReceiver.BufferSeq() && |
|
892 // most recent ReqSeq |
|
893 iReceiver.BufferSeq() == iReceiver.TxSeqExpectedBySduQ(), |
|
894 Panic(EL2CAPExpectedTxSeqAndBufferSeqAndTxSeqExpectedBySduQNotEqualWhenIncomingQEmptyAndInRecvState)); |
|
895 } |
|
896 // Now respond with a data frame or an ack frame with the Final bit set. |
|
897 iReceiver.Controller().SendIOrRrOrRnrL(ETrue); |
|
898 } |
|
899 |
|
900 TBool TL2CapErtmReceiverStateRecv::IsLocalBusySupported() const |
|
901 { |
|
902 LOG_FUNC |
|
903 return ETrue; |
|
904 } |
|
905 |
|
906 void TL2CapErtmReceiverStateRecv::TxSeqExpectedBySduQChanged(TUint8 aTxSeq) |
|
907 { |
|
908 LOG_FUNC |
|
909 LOG1(_L("Slipping BufferSeq to %d"), aTxSeq) |
|
910 iReceiver.SetBufferSeq(aTxSeq); |
|
911 __ASSERT_DEBUG(iReceiver.IsIncomingSduQFull() || iReceiver.BufferSeq() == iReceiver.ExpectedTxSeq(), |
|
912 Panic(EL2CAPBufferSeqNotEqualToExpectedTxSeqWhenInRecvAndSduQNotFull)); |
|
913 } |
|
914 |
|
915 |
|
916 TL2CapErtmReceiverStateRejSent::TL2CapErtmReceiverStateRejSent(CL2CapErtmDataReceiver& aReceiver) |
|
917 : TL2CapErtmReceiverStateBase(aReceiver) |
|
918 { |
|
919 LOG_FUNC |
|
920 } |
|
921 |
|
922 void TL2CapErtmReceiverStateRejSent::EnterL(RMBufChain* /*aIFrame*/) |
|
923 { |
|
924 LOG_FUNC |
|
925 |
|
926 // LocalBusy is only allowed in RECV. |
|
927 __ASSERT_DEBUG(!iReceiver.LocalBusy(), Panic(EL2CAPInRejSentAndLocalBusy)); |
|
928 |
|
929 // Otherwise by sending the REJ we'd acknowledge frames between BufferSeq and ExpectedTxSeq |
|
930 // (and if BufferSeq != ExpectedTxSeq and we're not in SREJ_SENT then incoming SDU Q is full |
|
931 // and we can not acknowledge anything new). |
|
932 __ASSERT_DEBUG(iReceiver.BufferSeq() == iReceiver.ExpectedTxSeq(), |
|
933 Panic(EL2CAPRejSentEnteredWithBufferedFrames)); |
|
934 |
|
935 iReceiver.Controller().OutgoingQ().QueueNonAckingSFrame(*HSFramePDU::NewL(EReject), iReceiver.ExpectedTxSeq()); |
|
936 } |
|
937 |
|
938 void TL2CapErtmReceiverStateRejSent::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
939 { |
|
940 LOG_FUNC |
|
941 |
|
942 __ASSERT_DEBUG(iReceiver.TxSeqExpectedBySduQ() == iReceiver.BufferSeq(), |
|
943 Panic(EL2CAPNextTxSeqExpectedBySduQNotEqualToBufferSeqWhenNotInSRejSent)); |
|
944 |
|
945 __ASSERT_DEBUG(InWindow(iReceiver.TxSeqExpectedBySduQ(), iReceiver.BufferSeq(), iReceiver.ExpectedTxSeq()), |
|
946 Panic(EL2CAPTxSeqExpectedBySduQNotWithinBufferSeqAndExpectedTxSeq)); |
|
947 |
|
948 __ASSERT_DEBUG(!iReceiver.LocalBusy(), Panic(EL2CAPInRejSentAndLocalBusy)); |
|
949 |
|
950 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
951 |
|
952 if (iReceiver.ExpectedTxSeq() == txSeq) |
|
953 // With-Expected-TxSeq |
|
954 { |
|
955 iReceiver.IncExpectedTxSeq(); |
|
956 if (!iReceiver.IsIncomingSduQFull()) |
|
957 { |
|
958 iReceiver.SetBufferSeq(iReceiver.ExpectedTxSeq()); |
|
959 } |
|
960 |
|
961 // Received the missing frame, clear REJ exception condition. |
|
962 iReceiver.SetStateRecvL(); |
|
963 |
|
964 iReceiver.PassToIncomingQL(aIFrame); |
|
965 } |
|
966 else |
|
967 { |
|
968 // else it's a duplicate or unexpected frame: |
|
969 // - drop the duplicate as usual, |
|
970 // - drop the unexpected frame as we're already in a REJ exception condition |
|
971 // and aren't allowed to send a second REJ until the first one is cleared. |
|
972 aIFrame.Free(); |
|
973 } |
|
974 } |
|
975 |
|
976 void TL2CapErtmReceiverStateRejSent::HandlePollL() |
|
977 { |
|
978 LOG_FUNC |
|
979 // General-case Poll handling: simply respond with a data frame or an ack frame with |
|
980 // the Final bit set. |
|
981 iReceiver.Controller().SendIOrRrOrRnrL(ETrue); |
|
982 } |
|
983 |
|
984 void TL2CapErtmReceiverStateRejSent::TxSeqExpectedBySduQChanged(TUint8 aTxSeq) |
|
985 { |
|
986 LOG_FUNC |
|
987 LOG1(_L("NextConsumedTxSeq moved: slipping BufferSeq to %d"), aTxSeq) |
|
988 iReceiver.SetBufferSeq(aTxSeq); |
|
989 __ASSERT_DEBUG(iReceiver.IsIncomingSduQFull() || iReceiver.BufferSeq() == iReceiver.ExpectedTxSeq(), |
|
990 Panic(EL2CAPBufferSeqNotEqualToExpectedTxSeqWhenInRecvAndSduQNotFull)); |
|
991 } |
|
992 |
|
993 |
|
994 TL2CapErtmReceiverStateSRejSent::TL2CapErtmReceiverStateSRejSent(CL2CapErtmDataReceiver& aReceiver) |
|
995 : TL2CapErtmReceiverStateBase(aReceiver), |
|
996 iGoToRej(EFalse) |
|
997 { |
|
998 LOG_FUNC |
|
999 } |
|
1000 |
|
1001 void TL2CapErtmReceiverStateSRejSent::EnterL(RMBufChain* aIFrame) |
|
1002 { |
|
1003 LOG_FUNC |
|
1004 |
|
1005 __ASSERT_DEBUG(!iReceiver.LocalBusy(), Panic(EL2CAPInSRejSentAndLocalBusy)); |
|
1006 __ASSERT_DEBUG(iMissingTxSeqs.IsEmpty(), Panic(EL2CAPNormalReceiveStateWhenMissingSRejFramesListIsNotEmpty)); |
|
1007 __ASSERT_DEBUG(aIFrame != NULL, Panic(EL2CAPDataFrameNotPassedOnEntryToSRejSent)); |
|
1008 |
|
1009 iGoToRej = EFalse; |
|
1010 SendSRejsUpToReceivedIFrameL(*aIFrame); |
|
1011 } |
|
1012 |
|
1013 void TL2CapErtmReceiverStateSRejSent::ExitL() |
|
1014 { |
|
1015 LOG_FUNC |
|
1016 TL2CapErtmReceiverStateBase::ExitL(); |
|
1017 |
|
1018 iMissingTxSeqs.Reset(); |
|
1019 |
|
1020 // BufferSeq was frozen once SREJ_SENT was entered. Now we can move it forward. |
|
1021 if (iReceiver.IsIncomingSduQFull()) |
|
1022 { |
|
1023 // If incoming SDU Q filled up during SREJ_SENT, then we can only move BufferSeq up to |
|
1024 // the point at which that happened, not ExpectedTxSeq. |
|
1025 iReceiver.SetBufferSeq(iReceiver.TxSeqExpectedBySduQ()); |
|
1026 } |
|
1027 else |
|
1028 { |
|
1029 // Bring BufferSeq back in sync with ExpectedTxSeq. |
|
1030 iReceiver.SetBufferSeq(iReceiver.ExpectedTxSeq()); |
|
1031 } |
|
1032 LOG2(_L("On exit from SREJ_SENT[IsIncomingSduQFull = %d]: slipped BufferSeq to %d"), |
|
1033 iReceiver.IsIncomingSduQFull(), iReceiver.BufferSeq()) |
|
1034 } |
|
1035 |
|
1036 void TL2CapErtmReceiverStateSRejSent::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
1037 { |
|
1038 LOG_FUNC |
|
1039 |
|
1040 __ASSERT_DEBUG(InWindow(iReceiver.TxSeqExpectedBySduQ(), iReceiver.BufferSeq(), iReceiver.ExpectedTxSeq()), |
|
1041 Panic(EL2CAPTxSeqExpectedBySduQNotWithinBufferSeqAndExpectedTxSeq)); |
|
1042 |
|
1043 __ASSERT_DEBUG(!iReceiver.LocalBusy(), Panic(EL2CAPInSRejSentAndLocalBusy)); |
|
1044 |
|
1045 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
1046 |
|
1047 TBool freeFrame = ETrue; |
|
1048 |
|
1049 if (iMissingTxSeqs.ExpectedSRejTxSeq() == txSeq) |
|
1050 // With-Expected-TxSeq-Srej |
|
1051 { |
|
1052 LOG1(_L("With-Expected-TxSeq-Srej: TxSeq=%d"), txSeq) |
|
1053 iReceiver.PassToIncomingQL(aIFrame); |
|
1054 freeFrame = EFalse; |
|
1055 |
|
1056 TBool resendPreviousSRej = iMissingTxSeqs.ReceivedTxSeq(txSeq); |
|
1057 __ASSERT_ALWAYS(!resendPreviousSRej, Panic(EL2CAPHaveSRejsToResendEvenThoughReceivedFirstInOrder)); |
|
1058 |
|
1059 if (iMissingTxSeqs.AllRequestedFramesReceived()) |
|
1060 { |
|
1061 if (iGoToRej) |
|
1062 { |
|
1063 if (iReceiver.IsIncomingSduQFull()) |
|
1064 { |
|
1065 // We couldn't have entered LocalBusy in SREJ_SENT, but now we can transition |
|
1066 // to RECV with LocalBusy instead of REJ_SENT. The retransmission will be |
|
1067 // started when we exit LocalBusy anyway. |
|
1068 iReceiver.SetStateRecvL(); |
|
1069 // We rely on this... |
|
1070 __ASSERT_DEBUG(iReceiver.LocalBusy(), |
|
1071 Panic(EL2CAPNotInLocalBusyAfterTransitionToRecvFromSrejSentWithSduQFull)); |
|
1072 } |
|
1073 else |
|
1074 { |
|
1075 iReceiver.SetStateRejSentL(); |
|
1076 } |
|
1077 } |
|
1078 else // !iGoToRej |
|
1079 { |
|
1080 iReceiver.SetStateRecvL(); |
|
1081 } |
|
1082 } // all SREJed frames received |
|
1083 } // With-Expected-TxSeq-Srej |
|
1084 else |
|
1085 { |
|
1086 if (iReceiver.ExpectedTxSeq() == txSeq) |
|
1087 { |
|
1088 // With-Expected-TxSeq |
|
1089 if (!iGoToRej) |
|
1090 { |
|
1091 LOG1(_L("With-Expected-TxSeq: TxSeq=%d"), txSeq) |
|
1092 iReceiver.IncExpectedTxSeq(); |
|
1093 iReceiver.PassToIncomingQL(aIFrame); |
|
1094 freeFrame = EFalse; |
|
1095 } |
|
1096 } |
|
1097 else if (InWindow(txSeq, iReceiver.BufferSeq(), iReceiver.ExpectedTxSeq())) |
|
1098 { |
|
1099 if (iMissingTxSeqs.IsTxSeqOnTheList(txSeq)) |
|
1100 // With-Unexpected-TxSeq-Srej |
|
1101 { |
|
1102 __ASSERT_DEBUG(TL2CapErtmMissingTxSeqs::KMaxSRejsInFlight > 1, |
|
1103 Panic(EL2CAPMultiSRejPathHitWhenNotSoConfigured)); |
|
1104 |
|
1105 // Multiple SRej requests have been made and some of the retransmitted I-Frames |
|
1106 // were lost again. Send new SREJs for those frames. |
|
1107 |
|
1108 __ASSERT_DEBUG(!iMissingTxSeqs.IsEmpty(), Panic(EL2CAPOldestSRejedFrameNotOnMissingList)); |
|
1109 LOG2(_L("With-Unexpected-TxSeq-Srej: TxSeq=%d. Expected was=%d"), |
|
1110 txSeq, iMissingTxSeqs.ExpectedSRejTxSeq()) |
|
1111 |
|
1112 TBool resendSRej = iMissingTxSeqs.ReceivedTxSeq(txSeq); |
|
1113 while (resendSRej) |
|
1114 { |
|
1115 TUint8 resendTxSeq; |
|
1116 resendSRej = iMissingTxSeqs.GetNextTxSeqForResend(resendTxSeq); |
|
1117 iReceiver.Controller().OutgoingQ().QueueNonAckingSFrame(*HSFramePDU::NewL(ESelectiveReject), resendTxSeq); |
|
1118 LOG1(_L("Resending SREJ for TxSeq=%d"), resendTxSeq) |
|
1119 } |
|
1120 iReceiver.PassToIncomingQL(aIFrame); |
|
1121 freeFrame = EFalse; |
|
1122 } |
|
1123 else // else must be a duplicate: With-duplicate-TxSeq-Srej |
|
1124 { |
|
1125 LOG1(_L("With-duplicate-TxSeq-Srej: TxSeq=%d"), txSeq) |
|
1126 } |
|
1127 } |
|
1128 else if (!iGoToRej) // With-Unexpected-TxSeq |
|
1129 { |
|
1130 LOG1(_L("With-Unexpected-TxSeq: TxSeq=%d."), txSeq) |
|
1131 if (iReceiver.IsSRejPreferredToRej(iReceiver.ExpectedTxSeq(), txSeq) && |
|
1132 iMissingTxSeqs.HaveSpaceForNewTxSeqs(Mod64(txSeq - iReceiver.ExpectedTxSeq()))) |
|
1133 { |
|
1134 __ASSERT_DEBUG(TL2CapErtmMissingTxSeqs::KMaxSRejsInFlight > 1, |
|
1135 Panic(EL2CAPMultiSRejPathHitWhenNotSoConfigured)); |
|
1136 SendSRejsUpToReceivedIFrameL(aIFrame); |
|
1137 freeFrame = EFalse; |
|
1138 } |
|
1139 else |
|
1140 { |
|
1141 // Don't send more SREJs. Wait for I-Frames requested so far to be |
|
1142 // retransmitted and go to REJ mode. |
|
1143 iGoToRej = ETrue; |
|
1144 LOG1(_L("NumMissingTxSeqs=%d, GoToRej=1"), iMissingTxSeqs.NumMissingTxSeqs()) |
|
1145 } |
|
1146 } |
|
1147 } // !With-Expected-TxSeq-Srej |
|
1148 |
|
1149 if (freeFrame) |
|
1150 { |
|
1151 aIFrame.Free(); |
|
1152 } |
|
1153 } |
|
1154 |
|
1155 void TL2CapErtmReceiverStateSRejSent::HandlePollL() |
|
1156 { |
|
1157 LOG_FUNC |
|
1158 __ASSERT_DEBUG(!iMissingTxSeqs.IsEmpty(), Panic(EL2CAPCaughtInSRejSentWithNoMissingTxSeqs)); |
|
1159 |
|
1160 HSFramePDU* frame = HSFramePDU::NewL(ESelectiveReject); |
|
1161 frame->SetFinalBit(ETrue); |
|
1162 iReceiver.OutgoingQ().QueueNonAckingSFrame(*frame, iMissingTxSeqs.LastTxSeq()); |
|
1163 } |
|
1164 |
|
1165 void TL2CapErtmReceiverStateSRejSent::TxSeqExpectedBySduQChanged(TUint8 /*aTxSeq*/) |
|
1166 { |
|
1167 LOG_FUNC |
|
1168 // Can't slip BufferSeq until SREJ_SENT is left. |
|
1169 } |
|
1170 |
|
1171 void TL2CapErtmReceiverStateSRejSent::SendSRejsUpToReceivedIFrameL(RMBufChain& aIFrame) |
|
1172 { |
|
1173 LOG_FUNC |
|
1174 |
|
1175 const TUint8 receivedTxSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
1176 |
|
1177 for (TUint8 sRejSeq = iReceiver.ExpectedTxSeq(); sRejSeq != receivedTxSeq; sRejSeq = Mod64(sRejSeq + 1)) |
|
1178 { |
|
1179 iMissingTxSeqs.AppendTxSeq(sRejSeq); |
|
1180 iReceiver.OutgoingQ().QueueNonAckingSFrame(*HSFramePDU::NewL(ESelectiveReject), sRejSeq); |
|
1181 } |
|
1182 |
|
1183 iReceiver.SetExpectedTxSeq(Mod64(receivedTxSeq + 1)); |
|
1184 iReceiver.PassToIncomingQL(aIFrame); |
|
1185 |
|
1186 LOG3(_L("ExpectedTxSeq = %d, First Expected SREJed TxSeq = %d, Last Expected SREJed TxSeq = %d"), |
|
1187 iReceiver.ExpectedTxSeq(), iMissingTxSeqs.ExpectedSRejTxSeq(), iMissingTxSeqs.LastTxSeq()) |
|
1188 } |
|
1189 |
|
1190 RL2CapErtmIncomingIFrameQueue::RL2CapErtmIncomingIFrameQueue() |
|
1191 : iTxSeqExpectedBySduQ(0) |
|
1192 { |
|
1193 LOG_FUNC |
|
1194 } |
|
1195 |
|
1196 void RL2CapErtmIncomingIFrameQueue::Close() |
|
1197 { |
|
1198 LOG_FUNC |
|
1199 if (!iQueue.IsEmpty()) |
|
1200 { |
|
1201 LOG(_L("Incoming I-Frame queue not empty, freeing mbufs.")) |
|
1202 iQueue.Free(); |
|
1203 } |
|
1204 } |
|
1205 |
|
1206 |
|
1207 void RL2CapErtmIncomingIFrameQueue::HandleIncomingIFrameL(RMBufChain& aIFrame, const CL2CapErtmDataReceiver& aReceiver) |
|
1208 { |
|
1209 LOG_FUNC |
|
1210 Insert(aIFrame); |
|
1211 if (!aReceiver.IsIncomingSduQFull()) |
|
1212 { |
|
1213 ConsumeUpToFirstGapL(aReceiver); |
|
1214 } |
|
1215 } |
|
1216 |
|
1217 void RL2CapErtmIncomingIFrameQueue::Insert(RMBufChain& aIFrame) |
|
1218 { |
|
1219 LOG_FUNC |
|
1220 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
1221 LOG2(_L("TxSeq=%d, NextConsumedTxSeq=%d"), txSeq, iTxSeqExpectedBySduQ) |
|
1222 |
|
1223 if (iQueue.IsEmpty() || !InWindow(txSeq, iTxSeqExpectedBySduQ, HIFramePDU::TxSeqNumber(iQueue.Last()))) |
|
1224 // Fast path for the most common cases. |
|
1225 { |
|
1226 __ASSERT_DEBUG(iQueue.IsEmpty() || txSeq != HIFramePDU::TxSeqNumber(iQueue.Last()), |
|
1227 Panic(EL2CapDuplicateIFramePassedToIncomingQ)); |
|
1228 iQueue.Append(aIFrame); |
|
1229 LOG(_L("Appending on fast path")) |
|
1230 } |
|
1231 else |
|
1232 // Generic insertion algorithm. |
|
1233 // Depends on there not being duplicate TxSeqs on the queue, i.e. the queue mustn't contain |
|
1234 // acknowledged frames. It can only contain frames within the current receive window. |
|
1235 { |
|
1236 TBool inserted = EFalse; |
|
1237 for (TMBufPktQIter iter(iQueue); !inserted && iter.More(); iter++) |
|
1238 { |
|
1239 TUint8 currentTxSeq = HIFramePDU::TxSeqNumber(iter.Current()); |
|
1240 __ASSERT_DEBUG(txSeq != currentTxSeq, Panic(EL2CapDuplicateIFramePassedToIncomingQ)); |
|
1241 |
|
1242 if (InWindow(txSeq, iTxSeqExpectedBySduQ, currentTxSeq)) |
|
1243 { |
|
1244 LOG1(_L("Inserting before %d"), currentTxSeq) |
|
1245 iter.Insert(aIFrame); |
|
1246 inserted = ETrue; |
|
1247 } |
|
1248 } |
|
1249 if (!inserted) |
|
1250 { |
|
1251 // It's actually impossible to get here with the fast path in the beginning |
|
1252 // of the function, but it's here for testing of the loop. Might change to |
|
1253 // __ASSERT_DEBUG when the testing dust settles. |
|
1254 LOG(_L("Gone through the Q, appending")) |
|
1255 iQueue.Append(aIFrame); |
|
1256 } |
|
1257 } |
|
1258 #ifdef _DEBUG |
|
1259 LogQ(); |
|
1260 #endif |
|
1261 } |
|
1262 |
|
1263 #ifdef _DEBUG |
|
1264 void RL2CapErtmIncomingIFrameQueue::LogQ() |
|
1265 { |
|
1266 LOG_FUNC |
|
1267 TMBufPktQIter i(iQueue); |
|
1268 TBuf<512> buf; |
|
1269 while (i.More()) |
|
1270 { |
|
1271 buf.AppendFormat(_L("%d "), HIFramePDU::TxSeqNumber(i++)); |
|
1272 } |
|
1273 LOG1(_L("Q: %S"), &buf) |
|
1274 } |
|
1275 #endif |
|
1276 |
|
1277 void RL2CapErtmIncomingIFrameQueue::ConsumeUpToFirstGapL(const CL2CapErtmDataReceiver& aReceiver) |
|
1278 { |
|
1279 LOG_FUNC |
|
1280 while (!iQueue.IsEmpty() && iTxSeqExpectedBySduQ == HIFramePDU::TxSeqNumber(iQueue.First()) |
|
1281 && !aReceiver.IsIncomingSduQFull()) |
|
1282 { |
|
1283 RMBufChain frame; |
|
1284 //Check on return value of iQueue.Remove() is unnecessary, since we've checked iQueue.IsEmpty() |
|
1285 static_cast<void>(iQueue.Remove(frame)); |
|
1286 iTxSeqExpectedBySduQ = Mod64(iTxSeqExpectedBySduQ + 1); |
|
1287 // This feeds the frame to the SDU Queue. This is also the place where we get notified |
|
1288 // if the queue gets full. If that happens, SetIncomingSduQFull is synchronously |
|
1289 // called by SDU Q here in the same stack frame - hence the guard in the loop condition. |
|
1290 aReceiver.PassToSduQL(frame); |
|
1291 } |
|
1292 LOG3(_L("On return from ConsumeUpToFirstGap: Queue empty=%d, NextConsumedTxSeq=%d, IsIncomingSduQFull=%d"), |
|
1293 iQueue.IsEmpty(), iTxSeqExpectedBySduQ, aReceiver.IsIncomingSduQFull()) |
|
1294 |
|
1295 #ifdef _DEBUG |
|
1296 LogQ(); |
|
1297 #endif |
|
1298 } |
|
1299 |
|
1300 |
|
1301 CL2CapErtmDataReceiver* CL2CapErtmDataReceiver::NewL(CL2CapEnhancedReTxController& aController) |
|
1302 { |
|
1303 LOG_STATIC_FUNC |
|
1304 CL2CapErtmDataReceiver* receiver = new (ELeave) CL2CapErtmDataReceiver(aController); |
|
1305 CleanupStack::PushL(receiver); |
|
1306 receiver->ConstructL(); |
|
1307 CleanupStack::Pop(receiver); |
|
1308 return receiver; |
|
1309 } |
|
1310 |
|
1311 void CL2CapErtmDataReceiver::ConstructL() |
|
1312 { |
|
1313 LOG_FUNC |
|
1314 iReceiveState = &iStateRecv; |
|
1315 iReceiveState->EnterL(NULL); |
|
1316 } |
|
1317 |
|
1318 CL2CapErtmDataReceiver::CL2CapErtmDataReceiver(CL2CapEnhancedReTxController& aController) |
|
1319 : iController(aController), |
|
1320 iExpectedTxSeq(0), |
|
1321 iBufferSeq(0), |
|
1322 iLastAckReqSeq(0), |
|
1323 iIncomingSduQFull(EFalse), |
|
1324 iLocalBusy(EFalse), |
|
1325 iInWaitFState(EFalse), |
|
1326 iWaitFStatePending(EFalse), |
|
1327 iSendAck(EFalse), |
|
1328 iStateRecv(*this), |
|
1329 iStateRejSent(*this), |
|
1330 iStateSRejSent(*this) |
|
1331 { |
|
1332 LOG_FUNC |
|
1333 } |
|
1334 |
|
1335 CL2CapErtmDataReceiver::~CL2CapErtmDataReceiver() |
|
1336 { |
|
1337 LOG_FUNC |
|
1338 iIncomingIFrameQ.Close(); |
|
1339 } |
|
1340 |
|
1341 void CL2CapErtmDataReceiver::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
1342 { |
|
1343 LOG_FUNC |
|
1344 LOG3(_L("ExpectedTxSeq=%d, BufferSeq=%d, LastAckReqSeq=%d"), |
|
1345 iExpectedTxSeq, iBufferSeq, iLastAckReqSeq) |
|
1346 |
|
1347 if (HIFramePDU::FinalBit(aIFrame)) |
|
1348 { |
|
1349 // It's important that this is executed first, we wouldn't like to drop an I-Frame that |
|
1350 // carries the Final Ack if we're in WAIT_F. If the remote has set F=1 then it must have |
|
1351 // received the Poll and is therefore aware of the ReqSeq we've sent in RR[P=1]. |
|
1352 // So if the remote is a correct implementation, then this I-Frame is the one we're |
|
1353 // expecting and we shouldn't drop it. |
|
1354 HandleFinalAckL(); |
|
1355 } |
|
1356 |
|
1357 if (// While we're in WAIT_F, peer may be still sending us I-Frames that are newer than those |
|
1358 // acknowledged by the RR[P=1] frame. They will be retransmitted when it receives the RR, |
|
1359 // so we can't accept the original transmissions, as that would move ExpectedAckSeq and |
|
1360 // thus cause the retransmissions to be invalid - we'd close the connection. |
|
1361 !iInWaitFState && |
|
1362 // ... also need to drop I-Frames when waiting to enter WAIT_F - if we're in WAIT_ACK, |
|
1363 // then iWaitFStatePending persists for an extended period of time during which we may |
|
1364 // have sent an RR due to some other unrelated reason. The peer started retransmitting |
|
1365 // when it got that RR, which makes the situation identical to being in WAIT_F. |
|
1366 // Ideally the spec would say that RR[P=1] makes the peer start retransmitting from |
|
1367 // the given ReqSeq and RR[P=0] just makes it pick up where it left it, but it's not |
|
1368 // the case - both restart the transmission, so both must be treated equally. |
|
1369 !iWaitFStatePending) |
|
1370 { |
|
1371 const TUint8 bufferSeqBefore = iBufferSeq; |
|
1372 |
|
1373 iReceiveState->HandleIncomingIFrameL(aIFrame); |
|
1374 |
|
1375 if (iBufferSeq != bufferSeqBefore // anything new to ack ? |
|
1376 && !iSendAck) // an ack already pending ? |
|
1377 { |
|
1378 iSendAck = IsEndOfReceiveWindowApproaching(); |
|
1379 if (!iSendAck) |
|
1380 { |
|
1381 // Note that we'll never fall here if PeerTxWin <= KReceiveWinFreeSpaceLeftToTriggerAck |
|
1382 if (!TimerMan().IsSendPeerAckTimerRunning()) |
|
1383 { |
|
1384 if (!TimerMan().StartSendPeerAckTimer()) |
|
1385 { |
|
1386 // The timer could not be started. Send an ack immediately. |
|
1387 iSendAck = ETrue; |
|
1388 } |
|
1389 } |
|
1390 } |
|
1391 } |
|
1392 } // !WAIT_F |
|
1393 else |
|
1394 { |
|
1395 aIFrame.Free(); |
|
1396 } |
|
1397 } |
|
1398 |
|
1399 void CL2CapErtmDataReceiver::HandleIncomingSFrameL(RMBufChain& aSFrame) |
|
1400 { |
|
1401 LOG_FUNC |
|
1402 LOG3(_L("ExpectedTxSeq=%d, BufferSeq=%d, LastAckReqSeq=%d"), |
|
1403 iExpectedTxSeq, iBufferSeq, iLastAckReqSeq) |
|
1404 |
|
1405 const TBool poll = HSFramePDU::PollBit(aSFrame); |
|
1406 const TBool final = HSFramePDU::FinalBit(aSFrame); |
|
1407 const TSupervisoryFunction function = HSFramePDU::SupervisoryFunction(aSFrame); |
|
1408 |
|
1409 if (poll && final) |
|
1410 { |
|
1411 LOG(_L("Incoming S-Frame has both P and F bits set!")) |
|
1412 LEAVEL(KErrL2CAPIllegalRemoteBehavior); |
|
1413 } |
|
1414 |
|
1415 if (final) |
|
1416 { |
|
1417 HandleFinalAckL(); |
|
1418 } |
|
1419 |
|
1420 if (poll && function != ESelectiveReject) // SREJ[P=1] is handled by the transmitter. |
|
1421 { |
|
1422 iReceiveState->HandlePollL(); |
|
1423 } |
|
1424 } |
|
1425 |
|
1426 void CL2CapErtmDataReceiver::HandleFinalAckL() |
|
1427 { |
|
1428 LOG_FUNC |
|
1429 if (iInWaitFState) |
|
1430 { |
|
1431 iInWaitFState = EFalse; |
|
1432 if (iIncomingSduQFull) |
|
1433 { |
|
1434 // Incoming SDU Q filled up again while we were exiting the previous LB condition. |
|
1435 UpdateLocalBusyStatusL(); |
|
1436 } |
|
1437 } |
|
1438 } |
|
1439 |
|
1440 void CL2CapErtmDataReceiver::SetIncomingSduQFullL(TBool aIncomingSduQFull) |
|
1441 { |
|
1442 LOG_FUNC |
|
1443 LOG2(_L("Incoming SDU Q full %d -> %d"), iIncomingSduQFull, aIncomingSduQFull) |
|
1444 |
|
1445 if (!iIncomingSduQFull && aIncomingSduQFull) |
|
1446 { |
|
1447 // Don't enter LocalBusy even if we can, start the delay timer instead. |
|
1448 // If the queue remains full until its expiry, we'll enter LocalBusy then. |
|
1449 // LocalBusy means we inform the peer of our busy condition by sending RNRs |
|
1450 // instead of RRs. |
|
1451 // We refrain from entering LocalBusy right off because exiting it means |
|
1452 // that the peer will have to restart the transmission from a seqnum given by us |
|
1453 // in the RR exiting the LocalBusy condition, which in turn means some frames |
|
1454 // which are already in transit (if there are any) will be lost. So if the full |
|
1455 // SDU Q is just a momentary hiccup, we hide this from the peer and just buffer |
|
1456 // the incoming frames and anchor BufferSeq at its current value to prevent the |
|
1457 // receive window from moving. |
|
1458 TimerMan().StartLocalBusyDelayTimer(); |
|
1459 } |
|
1460 else if (iIncomingSduQFull && !aIncomingSduQFull) |
|
1461 { |
|
1462 TimerMan().StopLocalBusyDelayTimer(); |
|
1463 } |
|
1464 |
|
1465 iIncomingSduQFull = aIncomingSduQFull; |
|
1466 UpdateLocalBusyStatusL(); |
|
1467 } |
|
1468 |
|
1469 // This routine manages the LocalBusy status by evaluating the necessary conditions: |
|
1470 // - whether the incoming SDU queue is full at the moment, |
|
1471 // - whether LocalBusy delay timer is still running, |
|
1472 // - whether we're exiting a previous LocalBusy condition, |
|
1473 // - whether we're able to enter LB in current receive state (LB is only allowed in RECV). |
|
1474 void CL2CapErtmDataReceiver::UpdateLocalBusyStatusL() |
|
1475 { |
|
1476 LOG_FUNC |
|
1477 LOG5(_L("iIncomingSduQFull=%d, iLocalBusy=%d, iWaitF=%d, iWaitFPending=%d, recv state = 0x%08x"), |
|
1478 iIncomingSduQFull, iLocalBusy, iInWaitFState, iWaitFStatePending, iReceiveState) |
|
1479 |
|
1480 if (iIncomingSduQFull) |
|
1481 { |
|
1482 if (!iLocalBusy && !TimerMan().IsLocalBusyDelayTimerRunning()) |
|
1483 { |
|
1484 if (!iInWaitFState && !iWaitFStatePending // have to wait until previous LB is properly finished |
|
1485 && iReceiveState->IsLocalBusySupported()) // only RECV |
|
1486 { |
|
1487 EnterLocalBusyL(); |
|
1488 } |
|
1489 } |
|
1490 // Once we enter LB the receive state is locked onto RECV so don't have to check whether |
|
1491 // it's changed. |
|
1492 } |
|
1493 else // !iIncomingSduQFull |
|
1494 { |
|
1495 // First we need to consume the frames on the incoming Q, which may cause the SDU Q to |
|
1496 // fill up again. |
|
1497 iIncomingIFrameQ.ConsumeUpToFirstGapL(*this); |
|
1498 |
|
1499 if (!iIncomingSduQFull) |
|
1500 // Incoming SDU Q didn't fill up again in ConsumeUpToFirstGapL(). |
|
1501 { |
|
1502 if (iLocalBusy) |
|
1503 { |
|
1504 // iLocalBusy is only possible when iInWaitFState && iWaitFStatePending are false |
|
1505 // and the only receive state in LB is RECV, so we can exit it anytime. |
|
1506 __ASSERT_DEBUG(iReceiveState == &iStateRecv && !iInWaitFState && !iWaitFStatePending, |
|
1507 Panic(EL2CAPLocalBusyUnderIllegalConditions)); |
|
1508 ExitLocalBusy(); |
|
1509 } |
|
1510 } |
|
1511 else // Incoming SDU Q filled up again in ConsumeUpToFirstGapL(). |
|
1512 { |
|
1513 // Some frames have been consumed and we've restarted the LB delay timer, |
|
1514 // so it's a good idea to ack now. |
|
1515 iSendAck = ETrue; |
|
1516 } |
|
1517 |
|
1518 // Give the receive state a chance to sync BufferSeq with TxSeqExpectedBySduQ. |
|
1519 // Must keep them in sync with if we can - there're reasons for that - see |
|
1520 // TL2CapErtmReceiverStateRecv::HandlePollL. We don't do that in SREJ_SENT though |
|
1521 // as BufferSeq can't change in that state but it's cool because our response to |
|
1522 // a Poll in SREJ_SENT will be SREJ which doesn't trigger retransmission of all |
|
1523 // unacked I-Frames and there's a separate mechanism for the peer to protect |
|
1524 // itself against a duplicate SREJ[F=1]. |
|
1525 // This is asserted through the code. |
|
1526 iReceiveState->TxSeqExpectedBySduQChanged(iIncomingIFrameQ.TxSeqExpectedBySduQ()); |
|
1527 |
|
1528 __ASSERT_DEBUG(iIncomingSduQFull || |
|
1529 ((iReceiveState != &iStateSRejSent && |
|
1530 iIncomingIFrameQ.TxSeqExpectedBySduQ() == iBufferSeq && |
|
1531 iBufferSeq == iExpectedTxSeq) || |
|
1532 (iReceiveState == &iStateSRejSent)), |
|
1533 Panic(EL2CAPWindowInformationInconsistentWhenExitingSduQFull)); |
|
1534 |
|
1535 __ASSERT_DEBUG(!iIncomingSduQFull || |
|
1536 ((iReceiveState != &iStateSRejSent && |
|
1537 iIncomingIFrameQ.TxSeqExpectedBySduQ() == iBufferSeq) || |
|
1538 (iReceiveState == &iStateSRejSent)), |
|
1539 Panic(EL2CAPWindowInformationInconsistentAfterMovingBufferSeqWhenSduQFull)); |
|
1540 } // !iIncomingSduQFull |
|
1541 } |
|
1542 |
|
1543 void CL2CapErtmDataReceiver::EnterLocalBusyL() |
|
1544 { |
|
1545 LOG_FUNC |
|
1546 __ASSERT_DEBUG(!TimerMan().IsLocalBusyDelayTimerRunning(), |
|
1547 Panic(EL2CAPEnterLocalBusyCalledWhileDelayTimerStillRunning)); |
|
1548 |
|
1549 iLocalBusy = ETrue; |
|
1550 // Send an RNR immediately. |
|
1551 iSendAck = ETrue; |
|
1552 iController.NotifyMuxerOfPdusToSendIfHaveSome(); |
|
1553 } |
|
1554 |
|
1555 void CL2CapErtmDataReceiver::ExitLocalBusy() |
|
1556 { |
|
1557 LOG_FUNC |
|
1558 iLocalBusy = EFalse; |
|
1559 // Signal to GetPdu that we need to enter WAIT_F. |
|
1560 iWaitFStatePending = ETrue; |
|
1561 iController.NotifyMuxerOfPdusToSendIfHaveSome(); |
|
1562 } |
|
1563 |
|
1564 template<typename FrameType> |
|
1565 void CL2CapErtmDataReceiver::StampWithReqSeq(FrameType& aFrame) |
|
1566 { |
|
1567 LOG_FUNC |
|
1568 __ASSERT_DEBUG(!aFrame.IsQueuedForSend(), Panic(EL2CAPReqSeqSetOnFrameAlreadyQueuedForSend)); |
|
1569 |
|
1570 aFrame.SetReqSeqNumber(iLastAckReqSeq = iBufferSeq); |
|
1571 TimerMan().StopSendPeerAckTimer(); |
|
1572 iSendAck = EFalse; |
|
1573 } |
|
1574 |
|
1575 TBool CL2CapErtmDataReceiver::IsSRejPreferredToRej(TUint8 aExpectedTxSeq, TUint8 aReceivedTxSeq) |
|
1576 { |
|
1577 LOG_FUNC |
|
1578 return InWindow(aReceivedTxSeq, aExpectedTxSeq, Mod64(aExpectedTxSeq + KSRejMissingFrameThreshold)); |
|
1579 } |
|
1580 |
|
1581 void CL2CapErtmDataReceiver::LocalBusyDelayTimerExpired() |
|
1582 { |
|
1583 LOG_FUNC |
|
1584 |
|
1585 // This guards from the classic state-changed-between-timer-expiry-and-handler-entry |
|
1586 // race condition. |
|
1587 if (iIncomingSduQFull) |
|
1588 { |
|
1589 TRAPD(err, UpdateLocalBusyStatusL()); |
|
1590 if (err != KErrNone) |
|
1591 { |
|
1592 iController.ErrorD(err); |
|
1593 // Just joined the majority. |
|
1594 } |
|
1595 } |
|
1596 } |
|
1597 |
|
1598 TBool CL2CapErtmDataReceiver::IsEndOfReceiveWindowApproaching() const |
|
1599 { |
|
1600 LOG_FUNC |
|
1601 TBool ackNeeded = EFalse; |
|
1602 |
|
1603 const TUint8 numFramesReceivedSinceLastAck = Mod64(iExpectedTxSeq - iLastAckReqSeq); |
|
1604 const TInt numFramesReceivedBeforeWantToSendAck = iController.Config().PeerTXWindowSize() - KReceiveWinFreeSpaceLeftToTriggerAck; |
|
1605 if (numFramesReceivedSinceLastAck >= numFramesReceivedBeforeWantToSendAck) |
|
1606 { |
|
1607 LOG2(_L("LastAckReqSeq = %d, ExpectedTxSeq = %d. Reaching end of window, will send an ack."), |
|
1608 iLastAckReqSeq, iExpectedTxSeq) |
|
1609 ackNeeded = ETrue; |
|
1610 } |
|
1611 return ackNeeded; |
|
1612 } |
|
1613 |
|
1614 void CL2CapErtmDataReceiver::SendPeerAckTimerExpiredL() |
|
1615 { |
|
1616 LOG_FUNC |
|
1617 if (iBufferSeq != iLastAckReqSeq) |
|
1618 { |
|
1619 iSendAck = ETrue; |
|
1620 iController.NotifyMuxerOfPdusToSendIfHaveSome(); |
|
1621 } |
|
1622 } |
|
1623 |
|
1624 HSFramePDU* CL2CapErtmDataReceiver::GetAckFrameL(TBool aFinal) |
|
1625 { |
|
1626 HSFramePDU* frame = HSFramePDU::NewL(iLocalBusy ? EReceiverNotReady : EReceiverReady); |
|
1627 frame->SetFinalBit(aFinal); |
|
1628 return frame; |
|
1629 } |
|
1630 |
|
1631 void CL2CapErtmDataReceiver::SetStateL(TL2CapErtmReceiverStateBase& aState, RMBufChain* aIFrame) |
|
1632 { |
|
1633 LOG_FUNC |
|
1634 iReceiveState->ExitL(); |
|
1635 iReceiveState = &aState; |
|
1636 iReceiveState->EnterL(aIFrame); |
|
1637 } |
|
1638 |
|
1639 |
|
1640 RL2CapErtmOutgoingQueue::RL2CapErtmOutgoingQueue(CL2CapEnhancedReTxController& aController) |
|
1641 : iController(aController), |
|
1642 iOutgoingQ(_FOFF(HL2CapPDU, iDataControllerInternalQLink)), |
|
1643 iPendRetransmitIFrameQ(_FOFF(HL2CapPDU, iDataControllerInternalQLink)) |
|
1644 { |
|
1645 LOG_FUNC |
|
1646 } |
|
1647 |
|
1648 void RL2CapErtmOutgoingQueue::Close() |
|
1649 { |
|
1650 LOG_FUNC |
|
1651 DeleteAllFrames(); |
|
1652 } |
|
1653 |
|
1654 void RL2CapErtmOutgoingQueue::QueueIFrameL(HIFramePDU& aIFrame) |
|
1655 { |
|
1656 LOG_FUNC |
|
1657 if (!TRetransmissionAndFlowControlOption::EnhancedMaxTransmitLessOrEqual(aIFrame.TransmissionCount() + 1, |
|
1658 iController.Config().MaxTransmit())) |
|
1659 { |
|
1660 LOG2(_L("MaxTransmit=%d exceeded by I-Frame no %d"), |
|
1661 iController.Config().MaxTransmit(), aIFrame.TxSeqNumber()) |
|
1662 LEAVEL(KErrL2CAPMaxTransmitExceeded); |
|
1663 } |
|
1664 else if (aIFrame.IsQueuedForSend()) |
|
1665 { |
|
1666 // This is either due to the I-Frame being SREJ-requested twice or a bug |
|
1667 // in our code. We don't have enough information to tell between the two, |
|
1668 // so have to assume it's the former. |
|
1669 LOG1(_L("I-Frame no %d already queued for send"), aIFrame.TxSeqNumber()) |
|
1670 LEAVEL(KErrL2CAPIllegalRemoteBehavior); |
|
1671 } |
|
1672 |
|
1673 iController.StampWithReqSeq(aIFrame); |
|
1674 iOutgoingQ.AddLast(aIFrame); |
|
1675 aIFrame.SetQueuedForSend(ETrue); |
|
1676 LOG3(_L("Queued I-Frame for send, TxSeq=%d, ReqSeq=%d, F=%d"), |
|
1677 aIFrame.TxSeqNumber(), aIFrame.ReqSeqNumber(), aIFrame.FinalBit()) |
|
1678 } |
|
1679 |
|
1680 void RL2CapErtmOutgoingQueue::QueueAckingSFrame(HSFramePDU& aSFrame) |
|
1681 { |
|
1682 LOG_FUNC |
|
1683 // This method is meant only for those S-Frames which carry an acknowledgement number. |
|
1684 __ASSERT_DEBUG(aSFrame.SupervisoryFunction() != ESelectiveReject || aSFrame.PollBit(), |
|
1685 Panic(EL2CAPSendSFrameWithAckCalledForSRejP0)); |
|
1686 // S-Frames are fire-n-forget, no healthy S-Frame gets queued twice! |
|
1687 __ASSERT_DEBUG(!aSFrame.IsQueuedForSend(), Panic(EL2CAPSFrameQueuedForSendTwice)); |
|
1688 |
|
1689 iController.StampWithReqSeq(aSFrame); |
|
1690 iOutgoingQ.AddLast(aSFrame); |
|
1691 aSFrame.SetQueuedForSend(ETrue); |
|
1692 LOG4(_L("Queued S-Frame for send, S=%d, ReqSeq=%d, P=%d, F=%d"), |
|
1693 aSFrame.SupervisoryFunction(), aSFrame.ReqSeqNumber(), aSFrame.PollBit(), aSFrame.FinalBit()) |
|
1694 } |
|
1695 |
|
1696 void RL2CapErtmOutgoingQueue::QueueNonAckingSFrame(HSFramePDU& aSFrame, TUint8 aReqSeq) |
|
1697 { |
|
1698 LOG_FUNC |
|
1699 // S-Frames are fire-n-forget, no healthy S-Frame gets queued twice! |
|
1700 __ASSERT_DEBUG(!aSFrame.IsQueuedForSend(), Panic(EL2CAPSFrameQueuedForSendTwice)); |
|
1701 |
|
1702 aSFrame.SetReqSeqNumber(aReqSeq); |
|
1703 iOutgoingQ.AddLast(aSFrame); |
|
1704 aSFrame.SetQueuedForSend(ETrue); |
|
1705 LOG4(_L("Queued S-Frame for send, S=%d, ReqSeq=%d, P=%d, F=%d"), |
|
1706 aSFrame.SupervisoryFunction(), aSFrame.ReqSeqNumber(), aSFrame.PollBit(), aSFrame.FinalBit()) |
|
1707 } |
|
1708 |
|
1709 void RL2CapErtmOutgoingQueue::PendRetransmitIFrameL(HIFramePDU& aIFrame) |
|
1710 { |
|
1711 LOG_FUNC |
|
1712 if (aIFrame.IsQueuedForSend()) |
|
1713 { |
|
1714 // This is either due to the I-Frame being SREJ-requested twice or a bug |
|
1715 // in our code. We don't have enough information to tell between the two, |
|
1716 // so have to assume it's the former. |
|
1717 LOG1(_L("I-Frame no %d already queued for send!"), aIFrame.TxSeqNumber()) |
|
1718 LEAVEL(KErrL2CAPIllegalRemoteBehavior); |
|
1719 } |
|
1720 iPendRetransmitIFrameQ.AddLast(aIFrame); |
|
1721 aIFrame.SetQueuedForSend(ETrue); |
|
1722 LOG3(_L("Queued I-Frame pending retransmission, TxSeq=%d, ReqSeq=%d, F=%d"), |
|
1723 aIFrame.TxSeqNumber(), aIFrame.ReqSeqNumber(), aIFrame.FinalBit()) |
|
1724 } |
|
1725 |
|
1726 void RL2CapErtmOutgoingQueue::SendPendingRetransmitIFramesL() |
|
1727 { |
|
1728 LOG_FUNC |
|
1729 if (!iPendRetransmitIFrameQ.IsEmpty()) |
|
1730 { |
|
1731 TSglQueIter<HIFramePDU> iter(iPendRetransmitIFrameQ); |
|
1732 while (HIFramePDU* eyeFrame = iter++) |
|
1733 { |
|
1734 eyeFrame->SetQueuedForSend(EFalse); // QueueIFrameL would leave if this flag was set. |
|
1735 QueueIFrameL(*eyeFrame); |
|
1736 } |
|
1737 iPendRetransmitIFrameQ.Reset(); |
|
1738 } |
|
1739 } |
|
1740 |
|
1741 void RL2CapErtmOutgoingQueue::CancelPendingRetransmitIFrames() |
|
1742 { |
|
1743 LOG_FUNC |
|
1744 if (!iPendRetransmitIFrameQ.IsEmpty()) |
|
1745 { |
|
1746 TSglQueIter<HIFramePDU> iter(iPendRetransmitIFrameQ); |
|
1747 while (HIFramePDU* eyeFrame = iter++) |
|
1748 { |
|
1749 LOG1(_L("Cancelling SREJ-requested pending retransmission of I-Frame %d"), |
|
1750 eyeFrame->TxSeqNumber()) |
|
1751 eyeFrame->SetQueuedForSend(EFalse); |
|
1752 } |
|
1753 iPendRetransmitIFrameQ.Reset(); |
|
1754 } |
|
1755 } |
|
1756 |
|
1757 void RL2CapErtmOutgoingQueue::DeleteAllFrames() |
|
1758 { |
|
1759 LOG_FUNC |
|
1760 if (!iPendRetransmitIFrameQ.IsEmpty()) |
|
1761 { |
|
1762 TSglQueIter<HIFramePDU> iter(iPendRetransmitIFrameQ); |
|
1763 while (HIFramePDU* eyeFrame = iter++) |
|
1764 { |
|
1765 delete eyeFrame; |
|
1766 } |
|
1767 iPendRetransmitIFrameQ.Reset(); |
|
1768 } |
|
1769 |
|
1770 if (!iOutgoingQ.IsEmpty()) |
|
1771 { |
|
1772 TSglQueIter<HL2CapPDU> iter(iOutgoingQ); |
|
1773 while (HL2CapPDU* pdu = iter++) |
|
1774 { |
|
1775 delete pdu; |
|
1776 } |
|
1777 iOutgoingQ.Reset(); |
|
1778 } |
|
1779 } |
|
1780 |
|
1781 HL2CapPDU* RL2CapErtmOutgoingQueue::DequeueNextToSend() |
|
1782 { |
|
1783 LOG_FUNC |
|
1784 HL2CapPDU* pdu = NULL; |
|
1785 if (!iOutgoingQ.IsEmpty()) |
|
1786 { |
|
1787 pdu = iOutgoingQ.First(); |
|
1788 if (!pdu->IsAwaitingHciCompletion()) |
|
1789 { |
|
1790 iOutgoingQ.Remove(*pdu); |
|
1791 pdu->SetQueuedForSend(EFalse); |
|
1792 } |
|
1793 else |
|
1794 { |
|
1795 LOG(_L("OutgoingQ stalled pending HCI Completion of the previous transmission of the next PDU")) |
|
1796 pdu = NULL; |
|
1797 } |
|
1798 } |
|
1799 return pdu; |
|
1800 } |
|
1801 |
|
1802 |
|
1803 CL2CapEnhancedReTxController* CL2CapEnhancedReTxController::NewL(TL2CAPPort aLocalCID, |
|
1804 TL2CAPPort aRemoteCID, |
|
1805 CL2CAPMux& aMuxer, |
|
1806 CL2CapSDUQueue& aSDUQueue, |
|
1807 TL2CapDataControllerConfig* aConfig) |
|
1808 { |
|
1809 LOG_STATIC_FUNC |
|
1810 CL2CapEnhancedReTxController* controller = new (ELeave) CL2CapEnhancedReTxController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig); |
|
1811 CleanupStack::PushL(controller); |
|
1812 controller->ConstructL(); |
|
1813 CleanupStack::Pop(controller); |
|
1814 return controller; |
|
1815 } |
|
1816 |
|
1817 void CL2CapEnhancedReTxController::ConstructL() |
|
1818 { |
|
1819 LOG_FUNC |
|
1820 iTransmitter = CL2CapErtmDataTransmitter::NewL(*this); |
|
1821 iReceiver = CL2CapErtmDataReceiver::NewL(*this); |
|
1822 } |
|
1823 |
|
1824 // ***** CL2CapEnhancedReTxController Implementation |
|
1825 CL2CapEnhancedReTxController::CL2CapEnhancedReTxController(TL2CAPPort aLocalCID, |
|
1826 TL2CAPPort aRemoteCID, |
|
1827 CL2CAPMux& aMuxer, |
|
1828 CL2CapSDUQueue& aSDUQueue, |
|
1829 TL2CapDataControllerConfig* aConfig) |
|
1830 : CL2CapBasicDataController(aLocalCID, aRemoteCID, aMuxer, aSDUQueue, aConfig, EFalse), |
|
1831 iDeliverOutgoingDataAndSignalToSduQWhenDone(EFalse), |
|
1832 iOutgoingQ(*this), |
|
1833 iTimerMan(*this) |
|
1834 { |
|
1835 LOG_FUNC |
|
1836 LOG2(_L("CL2CapEnhancedReTxController: local CID = %d, remote CID = %d"), aLocalCID, aRemoteCID) |
|
1837 } |
|
1838 |
|
1839 CL2CapEnhancedReTxController::~CL2CapEnhancedReTxController() |
|
1840 { |
|
1841 LOG_FUNC |
|
1842 iTimerMan.Close(); |
|
1843 iOutgoingQ.Close(); |
|
1844 delete iTransmitter; |
|
1845 delete iReceiver; |
|
1846 } |
|
1847 |
|
1848 void CL2CapEnhancedReTxController::HandleIncomingIFrameL(RMBufChain& aIFrame) |
|
1849 { |
|
1850 LOG_FUNC |
|
1851 const TUint8 txSeq = HIFramePDU::TxSeqNumber(aIFrame); |
|
1852 const TUint8 reqSeq = HIFramePDU::ReqSeqNumber(aIFrame); |
|
1853 const TBool final = HIFramePDU::FinalBit(aIFrame); |
|
1854 |
|
1855 LOG3(_L("Incoming I-Frame: TxSeq = %d, F = %d, ReqSeq = %d"), |
|
1856 txSeq, final, reqSeq) |
|
1857 |
|
1858 if (iReceiver->IsTxSeqInvalid(txSeq)) |
|
1859 { |
|
1860 LOG3(_L("Received invalid TxSeq num %d, [BufferSeq = %d, Receive TxWin = %d]"), |
|
1861 txSeq, iReceiver->BufferSeq(), iConfig->PeerTXWindowSize()) |
|
1862 LEAVEL(KErrL2CAPInvalidPacketSequenceNumber); |
|
1863 } |
|
1864 else if (!iTransmitter->IsReqSeqValid(reqSeq)) |
|
1865 { |
|
1866 LOG3(_L("Received invalid ReqSeq num %d, [ExpectedAckSeq = %d, NextTxSeq = %d]"), |
|
1867 reqSeq, iTransmitter->ExpectedAckSeq(), iTransmitter->NextTxSeq()) |
|
1868 LEAVEL(KErrL2CAPInvalidAcknowledgementNumber); |
|
1869 } |
|
1870 else if (IsFBitValid(final)) // ... and TxSeq and ReqSeq are valid |
|
1871 { |
|
1872 // ReqSeq & FBit valid: use this information whatever TxSeq value is, as long as it's |
|
1873 // within window. |
|
1874 |
|
1875 if (final) |
|
1876 { |
|
1877 HandleFinalAck(); |
|
1878 } |
|
1879 |
|
1880 iTransmitter->HandleIncomingIFrame(aIFrame); |
|
1881 iReceiver->HandleIncomingIFrameL(aIFrame); |
|
1882 |
|
1883 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
1884 } // ReqSeq & Final Valid, TxSeq within window |
|
1885 else |
|
1886 { |
|
1887 LOG(_L("F-bit invalid, dropping the I-Frame")) |
|
1888 aIFrame.Free(); |
|
1889 } |
|
1890 } |
|
1891 |
|
1892 void CL2CapEnhancedReTxController::HandleIncomingSFrameL(RMBufChain& aSFrame) |
|
1893 { |
|
1894 LOG_FUNC |
|
1895 |
|
1896 const TUint8 reqSeq = HSFramePDU::ReqSeqNumber(aSFrame); |
|
1897 const TBool poll = HSFramePDU::PollBit(aSFrame); |
|
1898 const TBool final = HSFramePDU::FinalBit(aSFrame); |
|
1899 |
|
1900 LOG4(_L("Incoming S-Frame: S = %d, P = %d, F = %d, ReqSeq = %d"), |
|
1901 HSFramePDU::SupervisoryFunction(aSFrame), poll, final, reqSeq) |
|
1902 |
|
1903 if (!iTransmitter->IsReqSeqValid(reqSeq)) |
|
1904 { |
|
1905 LOG3(_L("Received invalid ReqSeq num %d, [ExpectedAckSeq = %d, NextTxSeq = %d]"), |
|
1906 reqSeq, iTransmitter->ExpectedAckSeq(), iTransmitter->NextTxSeq()) |
|
1907 LEAVEL(KErrL2CAPInvalidAcknowledgementNumber); |
|
1908 } |
|
1909 else if (IsFBitValid(final)) // ... and TxSeq and ReqSeq are valid |
|
1910 { |
|
1911 // ReqSeq & FBit valid: use this information whatever TxSeq value is, as long as it's |
|
1912 // within window. |
|
1913 |
|
1914 if (final) |
|
1915 { |
|
1916 HandleFinalAck(); |
|
1917 } |
|
1918 |
|
1919 iTransmitter->HandleIncomingSFrameL(aSFrame); |
|
1920 iReceiver->HandleIncomingSFrameL(aSFrame); |
|
1921 |
|
1922 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
1923 } |
|
1924 else |
|
1925 { |
|
1926 LOG(_L("F-bit invalid, dropping the S-Frame")) |
|
1927 aSFrame.Free(); |
|
1928 } |
|
1929 } |
|
1930 |
|
1931 void CL2CapEnhancedReTxController::HandleFinalAck() |
|
1932 { |
|
1933 LOG_FUNC |
|
1934 // Just do housekeeping here. Transmitter/Receiver maintain their respective WAIT_* states |
|
1935 // and know what to do with the final ack. |
|
1936 iTimerMan.StopMonitorTimer(); |
|
1937 |
|
1938 iPollSFrameTransmitCount = 0; |
|
1939 } |
|
1940 |
|
1941 void CL2CapEnhancedReTxController::SendIOrRrOrRnrL(TBool aFinal) |
|
1942 { |
|
1943 LOG_FUNC |
|
1944 // Try piggybacking on an I-Frame first... |
|
1945 HIFramePDU* eyeFrame = iTransmitter->GetIFrameToSendL(); |
|
1946 if (eyeFrame) |
|
1947 { |
|
1948 eyeFrame->SetFinalBit(aFinal); |
|
1949 iOutgoingQ.QueueIFrameL(*eyeFrame); |
|
1950 } |
|
1951 else |
|
1952 { |
|
1953 // ... no I-Frame to send or can't send one. |
|
1954 iOutgoingQ.QueueAckingSFrame(*iReceiver->GetAckFrameL(aFinal)); |
|
1955 } |
|
1956 } |
|
1957 |
|
1958 HL2CapPDU* CL2CapEnhancedReTxController::GetPduL() |
|
1959 { |
|
1960 LOG_FUNC |
|
1961 // Note that: |
|
1962 // - the queue contains S-Frames (naturally) and I-Frames (if they're SREJ-requested by |
|
1963 // the peer or a Poll request was received and we had a data frame to piggyback the Final |
|
1964 // response on); |
|
1965 // - once a packet is put on the Q, it should be virtually considered to be on the air from |
|
1966 // a logical POV. |
|
1967 if (!iOutgoingQ.HaveFramesToTransmit()) |
|
1968 { |
|
1969 // Check for async events to handle. |
|
1970 // Note: polls are only sent when the OutgoingQ is empty. |
|
1971 // Reason: |
|
1972 // 1. The frames on the queue may be I-Frames queued in response to SREJs from the peer. |
|
1973 // Sending the Poll before responding to the SREJs would lead to a race condition |
|
1974 // (in WAIT_F) - the SREJs were received when XMIT state = Normal and so SRejActioned was |
|
1975 // not set to True. So if they're not responded to before the Poll, we'll receive a |
|
1976 // duplicate SREJ with the Final ack and respond to it with a duplicate I-Frame, which |
|
1977 // causes disconnect. |
|
1978 // |
|
1979 // 2. Even though this may increase the latency of handling an Ack timer expiry if |
|
1980 // there're packets on the queue, it actually bets on the assumption that these packets are |
|
1981 // I-Frames SREJ-requested by the peer (same one(s) that caused us to time out) and |
|
1982 // sending them before the Poll packet still gives the SREJ chance to work and hence |
|
1983 // minimizes the amount of stuff we'll have to retransmit once we receive the final ack.] |
|
1984 if ((iReceiver->IsWaitFStatePending() || iTransmitter->IsWaitAckStatePending()) && |
|
1985 !IsPollOutstanding()) |
|
1986 // ^- this serializes poll cycles - only one poll can be outstanding at a time |
|
1987 // but the conditions for WAIT_F and WAIT_ACK are independent and can occur |
|
1988 // simultaneously. |
|
1989 { |
|
1990 // Start a new Poll cycle. |
|
1991 __ASSERT_DEBUG(iPollSFrameTransmitCount == 0, Panic(EL2CAPPollFrameNumberTransmitIsNotZero)); |
|
1992 |
|
1993 HSFramePDU* sFrame = iReceiver->GetAckFrameL(); |
|
1994 sFrame->SetPollBit(ETrue); |
|
1995 |
|
1996 // Give WAIT_ACK preference in case both are outstanding. |
|
1997 if (iTransmitter->IsWaitAckStatePending()) |
|
1998 { |
|
1999 LOG(_L("Entering WaitAck")) |
|
2000 iTransmitter->EnterWaitAckState(); |
|
2001 } |
|
2002 else |
|
2003 { |
|
2004 LOG(_L("Entering WaitF")) |
|
2005 iReceiver->EnterWaitFState(); |
|
2006 } |
|
2007 |
|
2008 iPollSFrameTransmitCount++; |
|
2009 iTimerMan.StartMonitorTimer(); |
|
2010 |
|
2011 iOutgoingQ.QueueAckingSFrame(*sFrame); |
|
2012 } |
|
2013 else // outgoing Q empty & no async events outstanding, can send data |
|
2014 { |
|
2015 HIFramePDU* eyeFrame = iTransmitter->GetIFrameToSendL(); |
|
2016 if (eyeFrame) |
|
2017 { |
|
2018 iOutgoingQ.QueueIFrameL(*eyeFrame); |
|
2019 } |
|
2020 } |
|
2021 } |
|
2022 |
|
2023 // If an acking frame was queued in the previous step, this flag has been cleared. |
|
2024 if (iReceiver->SendAck()) |
|
2025 { |
|
2026 SendIOrRrOrRnrL(EFalse); |
|
2027 } |
|
2028 |
|
2029 // If there's anything ready to send it's on the queue by now. |
|
2030 HL2CapPDU* pduToSend = iOutgoingQ.DequeueNextToSend(); |
|
2031 if (pduToSend) |
|
2032 { |
|
2033 pduToSend->DeliverOutgoingPDU(*this); |
|
2034 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
2035 } |
|
2036 |
|
2037 return pduToSend; |
|
2038 } |
|
2039 |
|
2040 void CL2CapEnhancedReTxController::HandlePduSendComplete(HL2CapPDU& aPdu) |
|
2041 { |
|
2042 LOG_FUNC |
|
2043 // We only claim ownership of I-Frames. |
|
2044 iTransmitter->HciCompletedIFrame(static_cast<HIFramePDU&>(aPdu)); |
|
2045 // May be waiting for the current I-Frame to complete if it's already been |
|
2046 // requested for retransmission. |
|
2047 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
2048 } |
|
2049 |
|
2050 void CL2CapEnhancedReTxController::HandlePduSendError(HL2CapPDU& /*aPdu*/) |
|
2051 { |
|
2052 LOG_FUNC |
|
2053 // We use protocol-level retransmissions for I-Frames. |
|
2054 } |
|
2055 |
|
2056 TInt CL2CapEnhancedReTxController::HandleOutgoingIFrame(HIFramePDU* aIFrame) |
|
2057 { |
|
2058 LOG_FUNC |
|
2059 __ASSERT_DEBUG(!iTransmitter->InWaitAckState(), Panic(EL2CAPIFrameSentInWaitAck)); |
|
2060 |
|
2061 aIFrame->SetPDUCID(iRemoteCID); |
|
2062 aIFrame->CalculateAndSetFCS(); |
|
2063 |
|
2064 aIFrame->SetPduOwner(this); |
|
2065 |
|
2066 LOG3(_L("Outgoing I-Frame: TxSeq = %d, F = %d, ReqSeq = %d"), |
|
2067 aIFrame->TxSeqNumber(), aIFrame->FinalBit(), aIFrame->ReqSeqNumber()) |
|
2068 |
|
2069 return KErrNone; |
|
2070 } |
|
2071 |
|
2072 TInt CL2CapEnhancedReTxController::HandleOutgoingSFrame(HSFramePDU* aSFrame) |
|
2073 { |
|
2074 LOG_FUNC |
|
2075 aSFrame->SetPDUCID(iRemoteCID); |
|
2076 aSFrame->CalculateAndSetFCS(); |
|
2077 |
|
2078 LOG4(_L("Outgoing S-Frame: S = %d, P = %d, F = %d, ReqSeq = %d"), |
|
2079 aSFrame->SupervisoryFunction(), aSFrame->PollBit(), aSFrame->FinalBit(), aSFrame->ReqSeqNumber()) |
|
2080 |
|
2081 return KErrNone; |
|
2082 } |
|
2083 |
|
2084 void CL2CapEnhancedReTxController::SendPeerAckTimerExpired() |
|
2085 { |
|
2086 LOG_FUNC |
|
2087 TRAPD(err, iReceiver->SendPeerAckTimerExpiredL()); |
|
2088 if (err != KErrNone) |
|
2089 { |
|
2090 ErrorD(err); |
|
2091 // RIP |
|
2092 } |
|
2093 } |
|
2094 |
|
2095 void CL2CapEnhancedReTxController::AckTimerExpired() |
|
2096 { |
|
2097 LOG_FUNC |
|
2098 // Reset the POLL transmit count (it will be incremented when the SFrame[POLL] is pulled for sending |
|
2099 iPollSFrameTransmitCount = 0; |
|
2100 iTransmitter->AckTimerExpired(); |
|
2101 } |
|
2102 |
|
2103 void CL2CapEnhancedReTxController::LocalBusyDelayTimerExpired() |
|
2104 { |
|
2105 LOG_FUNC |
|
2106 iReceiver->LocalBusyDelayTimerExpired(); |
|
2107 } |
|
2108 |
|
2109 void CL2CapEnhancedReTxController::MonitorTimerExpired() |
|
2110 { |
|
2111 LOG_FUNC |
|
2112 __ASSERT_DEBUG(IsPollOutstanding(), Panic(EL2CAPUnexpectedMonitorTimeout)); |
|
2113 __ASSERT_DEBUG(iPollSFrameTransmitCount > 0, Panic(EL2CAPPollFrameNumberTransmitIsZero)); |
|
2114 |
|
2115 TInt err = KErrNone; |
|
2116 |
|
2117 if (!TRetransmissionAndFlowControlOption::EnhancedMaxTransmitLessOrEqual(iPollSFrameTransmitCount + 1, |
|
2118 iConfig->MaxTransmit())) |
|
2119 { |
|
2120 LOG1(_L("MaxTransmit=%d exceeded by a Poll S-Frame"), iConfig->MaxTransmit()) |
|
2121 err = KErrL2CAPMaxTransmitExceeded; |
|
2122 } |
|
2123 else |
|
2124 { |
|
2125 HSFramePDU* frame = NULL; |
|
2126 TRAP(err, frame = iReceiver->GetAckFrameL()); |
|
2127 if (err == KErrNone) |
|
2128 { |
|
2129 frame->SetPollBit(ETrue); |
|
2130 iOutgoingQ.QueueAckingSFrame(*frame); |
|
2131 |
|
2132 iPollSFrameTransmitCount++; |
|
2133 iTimerMan.StartMonitorTimer(); |
|
2134 |
|
2135 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
2136 } |
|
2137 } |
|
2138 if (err != KErrNone) |
|
2139 { |
|
2140 ErrorD(err); |
|
2141 // RIP |
|
2142 } |
|
2143 } |
|
2144 |
|
2145 TUint16 CL2CapEnhancedReTxController::MonitorTimeout() |
|
2146 { |
|
2147 return iConfig->MonitorTimeout(); |
|
2148 } |
|
2149 |
|
2150 TUint16 CL2CapEnhancedReTxController::RetransmissionTimeout() |
|
2151 { |
|
2152 return iConfig->RetransmissionTimeout(); |
|
2153 } |
|
2154 |
|
2155 TUint16 CL2CapEnhancedReTxController::PeerRetransmissionTimeout() |
|
2156 { |
|
2157 return iConfig->PeerRetransmissionTimeout(); |
|
2158 } |
|
2159 |
|
2160 void CL2CapEnhancedReTxController::OutgoingPduAvailableOnSduQ() |
|
2161 { |
|
2162 LOG_FUNC |
|
2163 NotifyMuxerOfPdusToSendIfHaveSome(); |
|
2164 } |
|
2165 |
|
2166 void CL2CapEnhancedReTxController::SetIncomingSduQFull(TBool aIncomingSduQFull) |
|
2167 { |
|
2168 LOG_FUNC |
|
2169 TRAPD(err, iReceiver->SetIncomingSduQFullL(aIncomingSduQFull)); |
|
2170 if (err != KErrNone) |
|
2171 { |
|
2172 ErrorD(err); |
|
2173 // RIP |
|
2174 } |
|
2175 } |
|
2176 |
|
2177 TBool CL2CapEnhancedReTxController::DeliverOutgoingDataAndSignalToSduQWhenDone() |
|
2178 { |
|
2179 LOG_FUNC |
|
2180 iDeliverOutgoingDataAndSignalToSduQWhenDone = ETrue; |
|
2181 // Returning true means we don't have any outstanding data to deliver and |
|
2182 // hence can be deleted immediately. |
|
2183 return !iTransmitter->HaveUnackedIFrames(); |
|
2184 } |
|
2185 |
|
2186 inline void CL2CapEnhancedReTxController::NotifyMuxerOfPdusToSendIfHaveSome() |
|
2187 { |
|
2188 LOG_FUNC |
|
2189 // This is intended to be your one-stop kick-the-muxer routine. |
|
2190 // It should evaluate all conditions that may cause us to want to send |
|
2191 // a PDU and should be called at the end of handling of every event which |
|
2192 // may cause us to want to send stuff. |
|
2193 // |
|
2194 // The conditions are: |
|
2195 // - if there's something on the OutgoingQ, then always transmit it ASAP, |
|
2196 // Outgoing Q is "the air" from the protocols point of view; |
|
2197 // - if we're not in WAIT_ACK (now called WAIT_F in the spec), then send |
|
2198 // data: |
|
2199 // - I-Frames requested for retransmission (with REJ or ack timer expiry, |
|
2200 // SREJ-requested ones are put on the OutgoingQ), |
|
2201 // - new I-Frames from SDUs on the SDU Q. |
|
2202 // - if there's some signalling to be send that hasn't been directly put |
|
2203 // on the OutgoingQ - send it: |
|
2204 // - need to go through WAIT_ACK and can enter it (WAIT_F not in progress), |
|
2205 // - need to go through WAIT_F and can enter it (WAIT_ACK not in progress); |
|
2206 // - time to send an acknowledgement to the peer. |
|
2207 |
|
2208 if (iOutgoingQ.HaveFramesToTransmit() || // various stuff already on the transmit Q, |
|
2209 // ... or data: |
|
2210 (!iTransmitter->InWaitAckState() && |
|
2211 // ... in need of retransmission ... |
|
2212 ((iTransmitter->IsRetransmittingUnackedIFrames() && !iTransmitter->IsNextUnackedIFrameAwaitingHciCompletion()) || |
|
2213 // ... or waiting to be pulled from SDU Q, |
|
2214 (!iTransmitter->IsRetransmittingUnackedIFrames() && iSDUQueue.HavePDUToSend() && iTransmitter->HaveSpaceInOutgoingWindow())) |
|
2215 ) || |
|
2216 // or some boring signalling: |
|
2217 // ... want to enter WAIT_ACK and not already in WAIT_F ... |
|
2218 (iTransmitter->IsWaitAckStatePending() && !iReceiver->InWaitFState()) || |
|
2219 // ... want to enter WAIT_F and not already in WAIT_ACK ... |
|
2220 (iReceiver->IsWaitFStatePending() && !iTransmitter->InWaitAckState()) || |
|
2221 // ... time to send an acknowledgement. |
|
2222 iReceiver->SendAck()) |
|
2223 { |
|
2224 iMuxer.PDUAvailable(); |
|
2225 } |
|
2226 |
|
2227 #ifdef __L2CAP_ERTM_GETPDU_DEBUG |
|
2228 LOG1(_L("iOutgoingQ.HaveFramesToTransmit(): %d"), iOutgoingQ.HaveFramesToTransmit()) |
|
2229 LOG1(_L("iTransmitter->HaveSpaceInOutgoingWindow(): %d"), iTransmitter->HaveSpaceInOutgoingWindow()) |
|
2230 LOG1(_L("iTransmitter->InWaitAckState(): %d"), iTransmitter->InWaitAckState()) |
|
2231 LOG1(_L("iTransmitter->IsRetransmittingUnackedIFrames(): %d"), iTransmitter->IsRetransmittingUnackedIFrames()) |
|
2232 if (iTransmitter->IsRetransmittingUnackedIFrames()) |
|
2233 { |
|
2234 LOG1(_L("iTransmitter->IsNextUnackedIFrameAwaitingHciCompletion(): %d"), iTransmitter->IsNextUnackedIFrameAwaitingHciCompletion()) |
|
2235 } |
|
2236 LOG1(_L("iChannel.DataQueue().HavePDUToSend(): %d"), iSDUQueue.HavePDUToSend()) |
|
2237 LOG1(_L("iTransmitter->IsWaitAckStatePending(): %d"), iTransmitter->IsWaitAckStatePending()) |
|
2238 LOG1(_L("iReceiver->InWaitFState(): %d"), iReceiver->InWaitFState()) |
|
2239 LOG1(_L("iReceiver->IsWaitFStatePending(): %d"), iReceiver->IsWaitFStatePending()) |
|
2240 LOG1(_L("iTransmitter->InWaitAckState(): %d"), iTransmitter->InWaitAckState()) |
|
2241 LOG1(_L("iReceiver->SendAck(): %d"), iReceiver->SendAck()) |
|
2242 #endif |
|
2243 } |