diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/l2cap/L2CapEnhancedDataController.inl --- /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 RL2CapErtmUnacknowledgedIFrames::Iterator() + { + return TDblQueIter(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 +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*/