--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/L2CapEnhancedDataController.inl Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,441 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#ifndef L2CAPENHANCEDDATACONTROLLER_INL
+#define L2CAPENHANCEDDATACONTROLLER_INL
+
+
+inline TBool RL2CapErtmTimerManager::IsLocalBusyDelayTimerRunning() const
+ {
+ return iLocalBusyDelayTimerRunning;
+ }
+
+
+inline void RL2CapErtmUnacknowledgedIFrames::Append(HIFramePDU& aFrame)
+ {
+ __ASSERT_DEBUG(iFrameIndex[aFrame.TxSeqNumber()] == NULL,
+ Panic(EL2CAPTryingToAppendSameTxSeqIFrameTwice));
+
+ iFrameList.AddLast(aFrame);
+ iFrameIndex[aFrame.TxSeqNumber()] = &aFrame;
+ }
+
+inline void RL2CapErtmUnacknowledgedIFrames::Remove(HIFramePDU& aFrame)
+ {
+ __ASSERT_DEBUG(iFrameIndex[aFrame.TxSeqNumber()] == &aFrame,
+ Panic(EL2CAPTryingToRemoveUnackedIFrameWithSameTxSeqButDifferentAddress));
+
+ aFrame.iLink.Deque();
+ iFrameIndex[aFrame.TxSeqNumber()] = NULL;
+ }
+
+inline HIFramePDU* RL2CapErtmUnacknowledgedIFrames::First() const
+ {
+ return iFrameList.First();
+ }
+
+inline HIFramePDU* RL2CapErtmUnacknowledgedIFrames::Last() const
+ {
+ return iFrameList.Last();
+ }
+
+inline HIFramePDU* RL2CapErtmUnacknowledgedIFrames::operator[](TUint8 aTxSeq) const
+ {
+ return iFrameIndex[aTxSeq];
+ }
+
+inline TBool RL2CapErtmUnacknowledgedIFrames::IsEmpty() const
+ {
+ return iFrameList.IsEmpty();
+ }
+
+inline TDblQueIter<HIFramePDU> RL2CapErtmUnacknowledgedIFrames::Iterator()
+ {
+ return TDblQueIter<HIFramePDU>(iFrameList);
+ }
+
+
+inline TBool CL2CapErtmDataTransmitter::RemoteBusy() const
+ {
+ return iRemoteBusy;
+ }
+
+inline TBool CL2CapErtmDataTransmitter::IsWaitAckStatePending() const
+ {
+ return iWaitAckStatePending;
+ }
+
+inline void CL2CapErtmDataTransmitter::EnterWaitAckState()
+ {
+ __ASSERT_DEBUG(!iController.IsPollOutstanding(),
+ Panic(EL2CAPAttemptToEnterWaitAckWhenAlreadyInAWaitState));
+
+ iWaitAckStatePending = EFalse;
+ iInWaitAckState = ETrue;
+ }
+
+inline TBool CL2CapErtmDataTransmitter::InWaitAckState() const
+ {
+ return iInWaitAckState;
+ }
+
+inline void CL2CapErtmDataTransmitter::SendOrPendL(HIFramePDU& aIFrame)
+ {
+ if (iInWaitAckState)
+ {
+ iController.OutgoingQ().PendRetransmitIFrameL(aIFrame);
+ }
+ else
+ {
+ iController.OutgoingQ().QueueIFrameL(aIFrame);
+ }
+ }
+
+inline RL2CapRetransmissionModeTimerManager& CL2CapErtmDataTransmitter::TimerMan()
+ {
+ return iController.TimerMan();
+ }
+
+inline RL2CapErtmOutgoingQueue& CL2CapErtmDataTransmitter::OutgoingQ()
+ {
+ return iController.OutgoingQ();
+ }
+
+inline TBool CL2CapErtmDataTransmitter::HaveUnackedIFrames() const
+ {
+ return !iUnackedIFrames.IsEmpty();
+ }
+
+inline TBool CL2CapErtmDataTransmitter::IsRetransmittingUnackedIFrames() const
+ {
+ return iUnackedIFrames[iNextTxSeq] != NULL;
+ }
+
+inline TBool CL2CapErtmDataTransmitter::IsNextUnackedIFrameAwaitingHciCompletion() const
+ {
+ __ASSERT_DEBUG(IsRetransmittingUnackedIFrames(), Panic(EL2CapReferencingUnackedIFrameWhenNoRetransmissionGoing));
+ return iUnackedIFrames[iNextTxSeq]->IsAwaitingHciCompletion();
+ }
+
+inline TBool CL2CapErtmDataTransmitter::IsReqSeqValid(TUint8 aReqSeq)
+ {
+ // Per the spec:
+ // With-Valid-ReqSeq: The ReqSeq of the received frame is in the range
+ // ExpectedAckSeq <= ReqSeq <= NextTxSeq.
+ //
+ // We can't just use NextTxSeq though because in our implementation we slip it back when we
+ // retransmit all unacked I-Frames, which means it doesn't always point to the next TxSeq to
+ // allocate, it's rather the next TxSeq to allocate OR retransmit. The real boundary of the
+ // TxSeqs sent out so far in the current window is the youngest I-Frame on the unacknowledged
+ // list, so we use that in this check.
+ //
+ // Note: ideally we should just be able to use NextTxSeq because the protocol is designed
+ // so that you only retransmit all unacked I-Frames once you've made sure they haven't been
+ // received by the peer, which would mean that we only slip NextTxSeq back having made
+ // sure that the peer will not acknowledge anything beyond that value. There is however
+ // one loophole in the protocol: when the peer exits LocalBusy and sends us an RR (we need
+ // to restart the transmission from the ReqSeq given in that RR) while we keep on sending
+ // I-Frames during the RR's travel time. These I-Frames will obviously have newer TxSeqs
+ // than the ReqSeq from the RR acknowledges and will thus be retransmitted when we receive
+ // the RR. So if the peer didn't ignore the original transmissions that came through
+ // when it was in WAIT_F, it will detect the retransmissions as duplicates and (if it's a
+ // correct implementation) close the connection. Some unwisely coded remotes however will
+ // accept the originals and ignore the duplicates, and in that case we may receive a ReqSeq
+ // for the originals while we're retransmitting them, which means it will be a younger
+ // seqNum than NextTxSeq.
+
+ const TUint8 lastValidReqSeq = iUnackedIFrames.IsEmpty() ? iNextTxSeq : L2CapDataUtils::Mod64(iUnackedIFrames.Last()->TxSeqNumber() + 1);
+ return L2CapDataUtils::InWindow(aReqSeq, iExpectedAckSeq, lastValidReqSeq);
+ }
+
+inline TUint8 CL2CapErtmDataTransmitter::ExpectedAckSeq() const
+ {
+ return iExpectedAckSeq;
+ }
+
+inline TUint8 CL2CapErtmDataTransmitter::NextTxSeq() const
+ {
+ return iNextTxSeq;
+ }
+
+
+inline void TL2CapErtmMissingTxSeqs::AppendTxSeq(TUint8 aTxSeq)
+ {
+ __ASSERT_DEBUG(iNumMissingTxSeqs < KMaxSRejsInFlight,
+ Panic(EL2CAPGivenMoreSRejedTxSeqsToTraceThanCanStore));
+
+ iMissingTxSeqs[iNumMissingTxSeqs++] = aTxSeq;
+ }
+
+inline TBool TL2CapErtmMissingTxSeqs::GetNextTxSeqForResend(TUint8& aTxSeq)
+ {
+ __ASSERT_DEBUG(iResendIdx < iNumMissingTxSeqs,
+ Panic(EL2CAPStrayCallToGetTxSeqForResend));
+
+ aTxSeq = iMissingTxSeqs[iResendIdx++];
+ return iResendIdx < iNumMissingTxSeqs;
+ }
+
+inline TUint8 TL2CapErtmMissingTxSeqs::LastTxSeq() const
+ {
+ __ASSERT_DEBUG(!IsEmpty(),
+ Panic(EL2CAPLastTxSeqCalledWhenNoneAreExpected));
+
+ return iMissingTxSeqs[iNumMissingTxSeqs - 1];
+ }
+
+inline TBool TL2CapErtmMissingTxSeqs::IsEmpty() const
+ {
+ return iNumMissingTxSeqs == 0;
+ }
+
+inline TBool TL2CapErtmMissingTxSeqs::AllRequestedFramesReceived() const
+ {
+ return iExpectedRecvIdx == iNumMissingTxSeqs;
+ }
+
+inline TUint8 TL2CapErtmMissingTxSeqs::ExpectedSRejTxSeq() const
+ {
+ __ASSERT_DEBUG(!IsEmpty() && !AllRequestedFramesReceived(),
+ Panic(EL2CAPNextExpectedTxSeqCalledWhenNoneAreExpected));
+ return iMissingTxSeqs[iExpectedRecvIdx];
+ }
+
+inline TInt TL2CapErtmMissingTxSeqs::NumMissingTxSeqs() const
+ {
+ return iNumMissingTxSeqs;
+ }
+
+inline TBool TL2CapErtmMissingTxSeqs::HaveSpaceForNewTxSeqs(TInt aNumTxSeqs) const
+ {
+ return KMaxSRejsInFlight - iNumMissingTxSeqs >= aNumTxSeqs;
+ }
+
+
+inline void TL2CapErtmMissingTxSeqs::Reset()
+ {
+ iNumMissingTxSeqs = iExpectedRecvIdx = iResendIdx = 0;
+ }
+
+
+inline TBool RL2CapErtmIncomingIFrameQueue::IsEmpty() const
+ {
+ return iQueue.IsEmpty();
+ }
+
+inline void RL2CapErtmIncomingIFrameQueue::DeleteAllFrames()
+ {
+ iQueue.Free();
+ }
+
+inline TUint8 RL2CapErtmIncomingIFrameQueue::TxSeqExpectedBySduQ() const
+ {
+ return iTxSeqExpectedBySduQ;
+ }
+
+inline void CL2CapErtmDataReceiver::PassToIncomingQL(RMBufChain& aIFrame)
+ {
+ iIncomingIFrameQ.HandleIncomingIFrameL(aIFrame, *this);
+ }
+
+inline void CL2CapErtmDataReceiver::PassToSduQL(RMBufChain& aIFrame) const
+ {
+ iController.PassToSduQL(aIFrame);
+ }
+
+inline TBool CL2CapErtmDataReceiver::IsIncomingSduQFull() const
+ {
+ return iIncomingSduQFull;
+ }
+
+inline TBool CL2CapErtmDataReceiver::LocalBusy() const
+ {
+ return iLocalBusy;
+ }
+
+inline void CL2CapErtmDataReceiver::FlushBufferedIncomingIFrames()
+ {
+ __ASSERT_DEBUG(iReceiveState == &iStateRecv,
+ Panic(EL2CAPFlushingIncomingIFramesInStateOtherThanRecv));
+ iIncomingIFrameQ.DeleteAllFrames();
+ iExpectedTxSeq = iIncomingIFrameQ.TxSeqExpectedBySduQ();
+ }
+
+inline TBool CL2CapErtmDataReceiver::IsWaitFStatePending() const
+ {
+ return iWaitFStatePending;
+ }
+
+inline void CL2CapErtmDataReceiver::EnterWaitFState()
+ {
+ __ASSERT_DEBUG(!iController.IsPollOutstanding(),
+ Panic(EL2CAPAttemptToEnterWaitFWhenAlreadyInAWaitState));
+
+ iWaitFStatePending = EFalse;
+ iInWaitFState = ETrue;
+ }
+
+inline TBool CL2CapErtmDataReceiver::InWaitFState() const
+ {
+ return iInWaitFState;
+ }
+
+inline TBool CL2CapErtmDataReceiver::SendAck() const
+ {
+ return iSendAck;
+ }
+
+inline RL2CapErtmTimerManager& CL2CapErtmDataReceiver::TimerMan()
+ {
+ return iController.TimerMan();
+ }
+
+inline RL2CapErtmOutgoingQueue& CL2CapErtmDataReceiver::OutgoingQ()
+ {
+ return iController.OutgoingQ();
+ }
+
+inline TUint8 CL2CapErtmDataReceiver::ExpectedTxSeq() const
+ {
+ return iExpectedTxSeq;
+ }
+
+inline void CL2CapErtmDataReceiver::SetExpectedTxSeq(TUint8 aTxSeq)
+ {
+ iExpectedTxSeq = aTxSeq;
+ }
+
+inline void CL2CapErtmDataReceiver::IncExpectedTxSeq()
+ {
+ iExpectedTxSeq = L2CapDataUtils::Mod64(iExpectedTxSeq + 1);
+ }
+
+inline TUint8 CL2CapErtmDataReceiver::BufferSeq() const
+ {
+ return iBufferSeq;
+ }
+
+inline void CL2CapErtmDataReceiver::SetBufferSeq(TUint8 aTxSeq)
+ {
+ iBufferSeq = aTxSeq;
+ }
+
+inline TUint8 CL2CapErtmDataReceiver::LastAckReqSeq() const
+ {
+ return iLastAckReqSeq;
+ }
+
+inline TUint8 CL2CapErtmDataReceiver::TxSeqExpectedBySduQ() const
+ {
+ return iIncomingIFrameQ.TxSeqExpectedBySduQ();
+ }
+
+inline void CL2CapErtmDataReceiver::SetStateRecvL()
+ {
+ SetStateL(iStateRecv, NULL);
+ }
+
+inline void CL2CapErtmDataReceiver::SetStateRejSentL()
+ {
+ SetStateL(iStateRejSent, NULL);
+ }
+
+inline void CL2CapErtmDataReceiver::SetStateSRejSentL(RMBufChain& aUnexpectedIFrame)
+ {
+ SetStateL(iStateSRejSent, &aUnexpectedIFrame);
+ }
+
+inline CL2CapEnhancedReTxController& CL2CapErtmDataReceiver::Controller() const
+ {
+ return iController;
+ }
+
+inline TBool CL2CapErtmDataReceiver::IsTxSeqUnexpected(TUint8 aTxSeq)
+ {
+ // With-unexpected-TxSeq: The TxSeq of the received I-frame is within the
+ // TxWindow of the L2CAP entity receiving the I-frame but has a TxSeq "greater"
+ // than ExpectedTxSeq where "greater" means later in sequence than ExpectedTxSeq.
+ return // in sender's window
+ L2CapDataUtils::InWindow(aTxSeq, iBufferSeq, L2CapDataUtils::Mod64(iBufferSeq + iController.Config().PeerTXWindowSize() - 1)) &&
+ // ... and "greater" than the expected one
+ !L2CapDataUtils::InWindow(aTxSeq, iBufferSeq, iExpectedTxSeq);
+ }
+
+inline TBool CL2CapErtmDataReceiver::IsTxSeqInvalid(TUint8 aTxSeq)
+ {
+ // With-Invalid-TxSeq: The TxSeq of the received I-frame is not within the
+ // TxWindow of the L2CAP entity receiving the frame.
+ return !L2CapDataUtils::InWindow(aTxSeq, iBufferSeq, L2CapDataUtils::Mod64(iBufferSeq + iController.Config().PeerTXWindowSize() - 1));
+ }
+
+
+inline TBool RL2CapErtmOutgoingQueue::HaveFramesToTransmit() const
+ {
+ return !iOutgoingQ.IsEmpty();
+ }
+
+inline TBool RL2CapErtmOutgoingQueue::HavePendingRetransmitIFrames() const
+ {
+ return !iPendRetransmitIFrameQ.IsEmpty();
+ }
+
+
+template<typename FrameType>
+inline void CL2CapEnhancedReTxController::StampWithReqSeq(FrameType& aFrame)
+ {
+ iReceiver->StampWithReqSeq(aFrame);
+ }
+
+inline RL2CapErtmOutgoingQueue& CL2CapEnhancedReTxController::OutgoingQ()
+ {
+ return iOutgoingQ;
+ }
+
+inline RL2CapErtmTimerManager& CL2CapEnhancedReTxController::TimerMan()
+ {
+ return iTimerMan;
+ }
+
+inline TBool CL2CapEnhancedReTxController::IsOutgoingDataPathClosing()
+ {
+ return iDeliverOutgoingDataAndSignalToSduQWhenDone;
+ }
+
+inline void CL2CapEnhancedReTxController::SignalOutgoingDataDeliveredToSduQ()
+ {
+ iSDUQueue.DataControllerDeliveredOutgoingData();
+ }
+
+inline void CL2CapEnhancedReTxController::PassToSduQL(RMBufChain& aIFrame)
+ {
+ User::LeaveIfError(iSDUQueue.PutIFramePDU(aIFrame));
+ }
+
+inline TBool CL2CapEnhancedReTxController::IsPollOutstanding() const
+ {
+ return iTransmitter->InWaitAckState() || iReceiver->InWaitFState();
+ }
+
+inline TBool CL2CapEnhancedReTxController::IsFBitValid(TBool aFinal)
+ {
+ // With-Valid-F-bit: The F-bit of a received frame is valid if it is 0 or if it is 1 and
+ // a frame sent with P=1 by the local L2CAP entity is unanswered (i.e. the local
+ // L2CAP entity send a frame with P=1 and has not yet received a frame with F=1
+ // until receiving this one). If the Transmitter state machine is in the WAIT_ACK or
+ // WAIT_F states then a frame sent with P=1 is unanswered.
+ return (aFinal && IsPollOutstanding()) || !aFinal;
+ }
+
+#endif /*L2CAPENHANCEDDATACONTROLLER_INL*/