diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/rfcomm/rfcommsap.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/rfcomm/rfcommsap.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,983 @@ +// Copyright (c) 1997-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: +// + +#include +#include +#include +#include "rfcommsap.h" +#include "rfcommconsts.h" +#include "rfcommstates.h" +#include "rfcomm.h" +#include "rfcommmuxer.h" +#include "rfcommflow.h" +#include "AsyncErrorKicker.h" +#include "IncomingConnListener.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_RFCOMM); +#endif + +CRfcommSAP* CRfcommSAP::NewL(CRfcommProtocol& aProtocol) + { + CRfcommSAP* sap= new (ELeave) CRfcommSAP(aProtocol); + CleanupStack::PushL(sap); + sap->ConstructL(); + CleanupStack::Pop(); + return sap; + } + +CRfcommSAP::CRfcommSAP(CRfcommProtocol& aProtocol) + : CBluetoothSAP(aProtocol.SecMan(), aProtocol.CodMan()), + iClearToSend(ETrue), + iClearToRecv(ETrue), + iSendBlocked(EFalse), + #ifdef _DEBUG + iLocalCreditsSupplied(0), + iLocalCreditsUsed(0), + iProxyForRemoteCreditsSupplied(0), + iProxyForRemoteCreditsUsed(0), + #endif + iSignals(KInitialModemStatus), + iProtocol(aProtocol) + { + iState=iProtocol.StateFactory()->GetState(CRfcommStateFactory::EClosed); + + // set default Port Parameters as per 07.10 + iLocalPortParams.SetBitRate(EBps9600); + iLocalPortParams.SetDataBits(EData8); + iLocalPortParams.SetStopBit(EStop1); + iLocalPortParams.SetParity(EParityNone); + iLocalPortParams.SetFlowCtrl(0); + iLocalPortParams.SetXOnChar(0x11); //DC1 + iLocalPortParams.SetXOffChar(0x13); //DC3 + } + +void CRfcommSAP::ConstructL() + /** + Construct the SAP + **/ + { + CBluetoothSAP::ConstructL(); + TCallBack nnd(NotifyNewDataCallback,this); + iNotifyNewDataCallback=new (ELeave) CAsyncCallBack(nnd, ECAsyncDeferredPriority); + + iErrorKicker=new (ELeave) CAsyncErrorKicker(*this, ECAsyncImmediatePriority); + } + +CRfcommSAP::~CRfcommSAP() + { + // Assert that we aren't in the Listening state + __ASSERT_DEBUG(iState!=iProtocol.StateFactory()-> + GetState(CRfcommStateFactory::EListening), Panic(ERfcommBadStateForDestruction)); + LOG1(_L("RFCOMM: ~CRfcommSAP 0x%08x"), this); + delete iNotifyNewDataCallback; + delete iErrorKicker; + + CancelAccessRequest(); + + if (iProtocol.IsListening()) + iProtocol.Listener().CancelIoctl(*this); + + if(iProtocol.SAPIsBound(*this)) + { + iProtocol.RemoveBoundSAP(*this); + } + + if(iMux) + { + iMux->DetachSAP(*this); + } + } + +// CServProviderBase functions +void CRfcommSAP::Start() + { + iState->Start(*this); + } + +void CRfcommSAP::LocalName(TSockAddr& aAddr) const + /** + Return the BT address of local host controller together with + the channel ID and security provided by user at 'Bind'. + @param holder for returned data . + @see SetLocalName + */ + { + // Construct with supplied address: future proof against additions to + // TRfcommSockAddr, also to balance with parallel functions in L2Cap. + TRfcommSockAddr addr(aAddr); + // Copy in BT address of local host controller + addr.SetBTAddr(iProtocol.LocalBTAddr()); + // Copy in channel ID and security provided by user at 'Bind' + addr.SetPort(iServerChannel); + addr.SetSecurity(iSecurity); + aAddr=addr; // Convert back + } + +TInt CRfcommSAP::SetLocalName(TSockAddr& aAddr) + /** + Set the local address (port and security). + (the port is specified in terms of server channels) + @param contains server channel and security + */ + { + TRfcommSockAddr rfcommAddr = TRfcommSockAddr::Cast(aAddr); + TUint port = rfcommAddr.Port(); + TInt err = KErrNone; + + if (port == KRfcommPassiveAutoBind) + { + // user wishes for us to choose free ServerChannel + err = PassiveAutoBind(rfcommAddr); + } + else + { + // explicit server channel provided + if(IsValidServerChannel(port)) + { + if (iProtocol.FindBoundSAP(rfcommAddr) || + iProtocol.FindIdleSAP(rfcommAddr) || + iProtocol.FindInboundConnectedSAP(rfcommAddr)) + { + // not available! + err = KErrInUse; + } + } + else + { + // user provided bogus server channel + err = KErrRfcommBadAddress; + } + } + + if (err == KErrNone) + { + // everything OK here, so store details + iServerChannel=static_cast(rfcommAddr.Port()); + iSecurity = rfcommAddr.BTSecurity(); + iProtocol.AddBoundSAP(*this); + } + return err; + } + + +TInt CRfcommSAP::PassiveAutoBind(TRfcommSockAddr& aAddress) + { +// provide the next free server channel as local port +// ESOCK doesn't itself support Autobind for passive connections! + TInt result = iProtocol.FindFreeServerChannel(); + + if (result >= KMinRfcommServerChannel) + { + aAddress.SetPort(result); + result = KErrNone; + } + + else + { + // error - none left: convert to a more meaningful error + // can't change error in FindFreeServerChannel for BC reasons + result = KErrRfcommNoMoreServerChannels; + } + + return result; + } + + +void CRfcommSAP::RemName(TSockAddr& aAddr) const + /** + Return the ServerChannel/DLCI value and remote device address, + provided by user at 'Connect' + @param holder for returned data + @see SetRemName() + */ + { + // Construct with supplied address: future proof against additions to + // TRfcommSockAddr, also to balance with parallel functions in L2Cap. + TRfcommSockAddr addr(aAddr); + addr.SetBTAddr(iRemoteDev); + addr.SetPort(iServerChannel); + addr.SetSecurity(iSecurity); + aAddr=addr; + } + + +TInt CRfcommSAP::SetRemName(TSockAddr& aAddr) + /** + Set the remote device address and ServerChannel. + @param contains values required + */ + { + TRfcommSockAddr rfcommAddr = TRfcommSockAddr::Cast(aAddr); + + if(IsValidServerChannel(rfcommAddr.Port())) + { + iServerChannel=static_cast(rfcommAddr.Port()); + iRemoteDev=rfcommAddr.BTAddr(); + iSecurity = rfcommAddr.BTSecurity(); + return KErrNone; + } + else + { + return KErrRfcommBadAddress; + } + } + + +TInt CRfcommSAP::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const + // Get an option for user + { + LOG(_L("RFCOMM [rfcommsap.cpp]: CRfcommSAP::GetOption")); + + // Make sure it's for us + if (aLevel!=KSolBtRFCOMM) + { + // What we do next depends on whether we have a muxer... + if(iMux) + { + // Pass it down to our muxer + return iMux->GetOption(aLevel, aName, aOption); + } + else + { + // If we have no muxer, we can't do anything here. + return KErrNotSupported; + } + } + + switch (aName) + { + case KRFCOMMLocalPortParameter: + { + // Don't care what state RFCOMM is in, just send back + // our local settings + TPckgBuf pckg(iLocalPortParams); + aOption=pckg; +// aOption = TPtr8((TUint8*)(&iLocalPortParams), +// sizeof(TRfcommRemotePortParams)); + return KErrNone; + } + case KRFCOMMGetAvailableServerChannel: + { + TPckgBuf intpckg(iProtocol.FindFreeServerChannel()); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMGetDebug1: + { + TPckgBuf intpckg((TInt)(static_cast(Dll::Tls()))->iPort); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMMaximumSupportedMTU: + { + TPckgBuf intpckg(iUserDefinedMTU); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMGetRemoteModemStatus: + { + TPckgBuf intpckg(iRemoteModemStatus); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMGetReceiveCredit: + { + TPckgBuf intpckg(ProxyForRemoteCredit()); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMGetTransmitCredit: + { + TPckgBuf intpckg(LocalCredit()); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMGetReUsedCount: + { + TInt value; + if(!NegotiatedMTU()) + value = -1; //-1 indicates use of get option before meaningful + else + value = FreeCreditCalculation(); + TPckgBuf intpckg(value); + aOption=intpckg; + return KErrNone; + } + case KRFCOMMFlowTypeCBFC: + { + if (iMux) + { + TPckgBuf intpckg(iMux->FlowStrategy()->FlowType()); + aOption=intpckg; + return KErrNone; + } + else + { + return KErrDisconnected; + } + } + case KRFCOMMLocalModemStatus: + { + TPckgBuf intpckg(iSignals); + aOption=intpckg; + return KErrNone; + } + case KBTSecurityDeviceOverride: + { + // aspectoriented programming would be nice :-) + return GetDeviceOverride(aOption); + } + case KRFCOMMMaximumMTU: + { + if (iMux) + { + // Allow for possible credit in header, 1 byte + TPckgBuf intpckg(iMTU - 1); + aOption=intpckg; + return KErrNone; + } + else + { + return KErrDisconnected; + } + } + default: + return KErrNotSupported; + } + } + + +TInt CRfcommSAP::SAPSetOption(TUint aLevel, TUint aName, const TDesC8 &aOption) + // Set option from user + { + return iState->SetOption(*this, aLevel, aName, aOption); + } + +void CRfcommSAP::Ioctl(TUint aLevel,TUint aName,TDes8* aOption) +/** + Perform an ioctl. + + If it is not for RFCOMM it is simply pushed down to the + layer below. If it is for RFCOMM and it is valid, it is handled in the state machine + If it is not valid, an error occurs. +**/ + { + __ASSERT_DEBUG(iIoctlLevel == 0, Panic(ERfcommSAPTwoIoctls)); + __ASSERT_DEBUG(iIoctlName == 0, Panic(ERfcommSAPTwoIoctls)); + + iIoctlLevel=aLevel; + iIoctlName=aName; + + if (aLevel == KSolBtRFCOMM) + iState->Ioctl(*this, aLevel, aName, aOption); + else + { + if (!iMux && iProtocol.IsListening()) + iProtocol.Listener().Ioctl(*this, aLevel, aName, aOption); + else if (iMux) + iMux->Ioctl(aLevel, aName, aOption); + else + { + iSocket->Error(KErrNotReady, MSocketNotify::EErrorIoctl); + } + + } + } + +void CRfcommSAP::CancelIoctl(TUint aLevel,TUint aName) + { + iState->CancelIoctl(*this, aLevel, aName); + //Cancel the Ioctl which has gone into muxer + if(aLevel != KSolBtRFCOMM && iMux) + { + iMux->CancelIoctl(aLevel, aName); + } + } + +TUint CRfcommSAP::Write(const TDesC8& aDesc,TUint /*aOptions*/, TSockAddr* /*aAddr*/) + { + return iState->Send(*this, aDesc); + } + +void CRfcommSAP::GetData(TDes8& aDesc,TUint /*aOptions*/,TSockAddr* /*aAddr*/) + { + iState->Read(*this, aDesc); + } + +void CRfcommSAP::ActiveOpen() + /** + Request the SAP to open a connection. + **/ + { + iState->ActiveOpen(*this); + } + +void CRfcommSAP::ActiveOpen(const TDesC8& /*aConnectionData*/) + { + LOG(_L("CRfcommSAP::ActiveOpen - with data called")); + Panic(ERfcommConnectWithData); + } + +TInt CRfcommSAP::PassiveOpen(TUint aQueSize) + { + return iState->PassiveOpen(*this, aQueSize); + } + +TInt CRfcommSAP::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/) + { + return KErrNotSupported; + } + +void CRfcommSAP::Shutdown(TCloseType aOption) + { + if(aOption!=EImmediate) + { + // Normal closedown, ESOCK will wait for us to say we can end + LOG1(_L("RFCOMM: Shutdown, sap %08x"), this); + iState->Shutdown(*this); + } + else + { + LOG1(_L("RFCOMM: Fast Shutdown, sap %08x"), this); + iState->FastShutdown(*this); + } + } + +void CRfcommSAP::Shutdown(TCloseType /*aOption*/,const TDesC8& /*aDisconnectionData*/) + { + LOG(_L("CRfcommSAP::Shutdown - with data")); + Panic(ERfcommDisconnectDataNotSupported); + } + +void CRfcommSAP::AutoBind() + /** + Pick an appropriate local port. + This is a no-op for RFCOMM since the local and remote ports + are the same. + **/ + { + } + +void CRfcommSAP::Error(TInt aErrorCode, TErrorTypes aType) + { + iState->Error(*this, aErrorCode, aType); + } + +TUint16 CRfcommSAP::NegotiatedMTU() const + { + return iMTU; + } + +TUint16 CRfcommSAP::UsableMTU(TUint8 aCredit) const + { + return iMux->FlowStrategy()->UsableMTU(*this, aCredit); + } + +/* + Query and util functions +*/ + +TUint8 CRfcommSAP::DLCI() const + { + return iDLCI; + } + +TUint16 CRfcommSAP::MaximumMTU() const + /** + Calculates the maximum MTU that we can possibly allow in terms of the underlying + L2CAP SAP MTU, and any user defined upper limit on the MTU. + + This is not a misnaming - the SAPs actual MTU might be negotiated down from + the Maximum Maximum Transfer Unit! + **/ + { + TInt frameSize=iMux->GetMaxDataSize(); + // size is currently the raw L2CAP MTU at this point. + // Adjust it to allow for the header and tail fields. + frameSize-=(frameSize>KMaxL2CAPMTUFor1LengthByte)? + (KLongFrameHeaderLength+KFCSFieldLength): + (KShortFrameHeaderLength+KFCSFieldLength); + + //Check the RFComm MTU negotiated in PN commands is + //less than the TS 07.10 defined maximum. + frameSize = (KRfcommMaxMTU0 && frameSize<=KRfcommMaxMTU,Panic(ERfcommBadCalculatedMTU)); + return STATIC_CAST(TUint16,frameSize); + } + +TRfcommChannel CRfcommSAP::ServerChannel() const + { + return iServerChannel; + } + +TBool CRfcommSAP::ServerChannelValid() const + /** + Checks the ServerChannel for validity. + The DLCI must be in the range 2-30. + **/ + { + return IsValidServerChannel(iServerChannel); + } + +TBool CRfcommSAP::IsValidServerChannel(TInt aChan) const + { + return (aChan >= KMinRfcommServerChannel && aChan <= KMaxRfcommServerChannel); + } + +CRfcommMuxer* CRfcommSAP::Mux() + { + return iMux; + } + +CCirBuffer& CRfcommSAP::DataBuffer() + { + return iDataBuffer; + } + +TInt CRfcommSAP::UnusedBufferSpace() const + { + return iDataBuffer.Length() - iDataBuffer.Count(); + } + +TInt CRfcommSAP::NotifyNewDataCallback(TAny* aSAP) + { + CRfcommSAP& sap = *static_cast(aSAP); + sap.iState->NotifyNewDataCallback(sap); + return EFalse; + } + +TBool CRfcommSAP::IsCloned() + { + return iCloned; + } + +CRfcommSAP* CRfcommSAP::CloneMe() + /** + Provides a cloning service. + + The return value is either NULL (when the clone could not be created for lack of + memory, or hitting the limitations set on the maximum number of child clones waiting + for start as set in PassiveOpen aQue) or the address of a new SAP. + **/ + { + __ASSERT_DEBUG(iState==iProtocol.StateFactory()-> + GetState(CRfcommStateFactory::EListening), Panic(ERfcommBadStateForCloning)); + CRfcommSAP* clone = NULL; + + if(iClonedChildren.Count() + iClonesWaitingForStart>=iMaxClonesWaitingForStart) + return NULL; // We want the listening queue to hold at iMaxClonesWaitingForStart. + + TRAPD(err, clone = NewL(iProtocol)); + if(err != KErrNone) + return NULL; + + // Mark new SAP as cloned + clone->iCloned = ETrue; + + // Ensure the clone knows it's parent + clone->iParentSAP=this; + + // Ensure the parent doesn't forget its clone + iClonedChildren.Append(clone); + + return clone; + } + +void CRfcommSAP::ChildConnected(CRfcommSAP& aRfcommSAP) + /** + Called by cloned child SAPs on their parent when they get hit by an incoming SABM. + + This is a cue for the parent (listening) SAP to increment iClonesWaitingForStart + and to call ConnectComplete on their MSocketNotify. At this point, the cloned child + SAP should also be removed from the Parent SAPs list of children. + **/ + { + TInt index=iClonedChildren.Find(&aRfcommSAP); + if(indexConnectComplete(aRfcommSAP); + } + +void CRfcommSAP::ChildConnectFailed(CRfcommSAP& aRfcommSAP) + /** + One of our cloned child SAPs has failed to connect. + + This could be because of a RFCOMM shutdown of the connection + before it completes, or because of a security check failure. + Either way, We can delete the SAP with no ill effects since ESOCK + has no knowledge of the clone. + **/ + { + TInt index=iClonedChildren.Find(&aRfcommSAP); + + __ASSERT_DEBUG(index>=KErrNone, Panic(ERfcommUnknownChildSecurityFailed)); //child not found! + + delete iClonedChildren[index]; + iClonedChildren.Remove(index); + } + +void CRfcommSAP::ChildStarted(CRfcommSAP& /*aRfcommSAP*/) + /** + Notification from a child that they have received a Start. + **/ + { + iClonesWaitingForStart--; + } + +void CRfcommSAP::AccessRequestComplete(TInt aResult) + /** + Callback from the BTSecurityRequester with result of security check + **/ + { + iState->AccessRequestComplete(*this, aResult); + } + +void CRfcommSAP::ParentClosed() + /** + Notification from our parent that it has been closed. + **/ + { + iState->ParentClosed(*this); + } + + +TBool CRfcommSAP::ListeningTo(const TBTSockAddr& aBTSockAddr) const + /** + Is the current SAP listening for connections from the specified address? + + When called on a given SAP, this function returns ETrue if; + a) The SAP is listening + b) The SAP is listening for connections incoming from the given Server Channel + **/ + { + return ( iState==iProtocol.StateFactory()->GetState(CRfcommStateFactory::EListening) && + aBTSockAddr.Port()==iServerChannel ); + } + +TBool CRfcommSAP::BoundTo(const TBTSockAddr& aBTSockAddr) const + { + return aBTSockAddr.Port()==iServerChannel; + } + +void CRfcommSAP::StopListening() + /** + Called on destruction, or on Shutdown or FastShutdown of a listening SAP. + + Removes this SAP from the Protocol's list of listening SAPs, and also informs all + the cloned child SAPs of their parent's imminent destruction. + **/ + { + TInt index=0; + for(;indexParentClosed(); + } + + iClonedChildren.ResetAndDestroy(); + iClonedChildren.Close(); + iProtocol.DecrementListeners(); + iProtocol.RemoveIdleSAP(*this); + } + +/* + Events coming in from the muxer/protocol +*/ + + +void CRfcommSAP::MuxUp() + /** + Notification that a mux has been started. + **/ + { + iState->MuxUp(*this); + } + +void CRfcommSAP::LinkDown() + /** + Notification that the link has gone down. + **/ + { + iState->LinkDown(*this); + } + +void CRfcommSAP::DISC() + /** + A DISC frame has come in for this SAP + **/ + { + iState->DISC(*this); + } + +void CRfcommSAP::UA() + /** + A UA frame has come in for this SAP + **/ + { + iState->UA(*this); + } + +void CRfcommSAP::DM() + /** + A DM frame has come in for this SAP + **/ + { + iState->DM(*this); + } + + +void CRfcommSAP::RPN(const TRfcommRPNTransaction* aRPNTransactionPtr, CRfcommMuxer& aMuxer, TUint8 aDLCI) + /** + An RPN command has come in from the remote end for this SAP + + This is either: + 1) A negotiation command or + 2) A request for our local port parameters + **/ + { + // If there's transaction data it be either a negotiation or a request(query) (having been through state machine) + if(aRPNTransactionPtr) + { + LOG(_L("RPN command received - Passing onto RFCOMM state machine\n")); + iState->RPN(*this, *aRPNTransactionPtr, aMuxer, aDLCI); + return; + } + + // Otherwise it's a request (query) + LOG(_L("RPN Request received - Sending our local settings\n")); + + TRfcommRPNTransaction localRPNTransaction; + // Copy the local port params into the transaction structure + localRPNTransaction.iPortParams = iLocalPortParams; + + // Set the parameter mask to whatever is valid in the port params + TUint16& paramMask = localRPNTransaction.iParamMask; + paramMask = 0; + + if(iLocalPortParams.IsValid() & EVMBitRate) + paramMask |= EPMBitRate; + + if(iLocalPortParams.IsValid() & EVMDataBits) + paramMask |= EPMDataBits; + + if(iLocalPortParams.IsValid() & EVMStopBit) + paramMask |= EPMStopBit; + + if(iLocalPortParams.IsValid() & EVMParity) + { + paramMask |= EPMParity; + paramMask |= EPMParityType; + } + + if(iLocalPortParams.IsValid() & EVMFlowCtrl) + { + // Not sure which *parts* of Flow control are valid + // - assume all of it is + paramMask |= EPMXOnOffInput; + paramMask |= EPMXOnOffOutput; + paramMask |= EPMRTRInput; + paramMask |= EPMRTROutput; + paramMask |= EPMRTCInput; + paramMask |= EPMRTCOutput; + } + + if(iLocalPortParams.IsValid() & EVMXOnChar) + paramMask |= EPMXOnChar; + + if(iLocalPortParams.IsValid() & EVMXOffChar) + paramMask |= EPMXOffChar; + + //Call the state machine to process this RPN, including local transaction + iState->RPN(*this, localRPNTransaction, aMuxer, aDLCI); + + } + +void CRfcommSAP::RPNRsp(const TRfcommRPNTransaction& aRPNTransaction) + /** + A response to a RPN command has come in for this SAP + **/ + { + // Depends on what state we're in so pass it on + iState->RPNRsp(*this, aRPNTransaction); + } + +void CRfcommSAP::PNResp(TRfcommPortParams& aParams) + /** + A response to a PN command has come in for this SAP + **/ + { + iState->PNResp(*this, aParams); + } + +void CRfcommSAP::MSC(TUint8 aSignals) + /** + A MSC command or response has come in for this SAP + from the remote end + **/ + { + iState->MSC(*this, aSignals); + } + +void CRfcommSAP::RLS(TUint8 aStatus) + /** + A RLS command or response has come in for this SAP + from the remote end + **/ + { + iState->RLS(*this, aStatus); + } + +void CRfcommSAP::Data(const TDesC8& aData) + /** + Data has arrived for this SAP + **/ + { + LOG1(_L("RFCOMM: Reading 0x%x"), aData[0]); + iState->NewData(*this, aData); + } + +void CRfcommSAP::CanSend() + /** + Clear to send from the mux + **/ + { + iState->CanSend(*this); + } + +//TRY_CBFC +void CRfcommSAP::DisallowCBFC() + { + iProtocol.DisallowCBFC(); + } + +void CRfcommSAP::AllowCBFC() + { + iProtocol.AllowCBFC(); + } + +TUint8 CRfcommSAP::FreeCredit() + { + return iState->FreeCredit(*this); + } + +TUint8 CRfcommSAP::FreeCreditCalculation() const + { + __ASSERT_DEBUG(NegotiatedMTU(), Panic(ERfcommBadCalculatedMTU)); + TInt value = UnusedBufferSpace()/NegotiatedMTU() - iProxyForRemoteCredit; + #ifdef _DEBUG + TInt divResult = 0; //two lines here to avoid compiler warning + divResult = UnusedBufferSpace()/NegotiatedMTU(); + + LOG(_L("RFCOMM: Calculating the maximum number of extra credits we can send to the remote .....")); + LOG6(_L("RFCOMM: ..... %d/%d - %d = %d - %d = %d"), + UnusedBufferSpace(), + NegotiatedMTU(), + iProxyForRemoteCredit, + divResult, + iProxyForRemoteCredit, + value); + #endif + value = Max(value, 0); //ignore negative values...FIXME + return STATIC_CAST(TUint8, Min(value, KMaxTUint8)); + } + +TInt CRfcommSAP::ProxyForRemoteCredit() const + { + return iState->ProxyForRemoteCredit(*this); + } + +void CRfcommSAP::SetProxyForRemoteCredit(TInt aCredit) + { + iState->SetProxyForRemoteCredit(*this, aCredit); + } + +void CRfcommSAP::ProxyForRemoteCreditDecrement() + { + iState->ProxyForRemoteCreditDecrement(*this); + } + +void CRfcommSAP::ProxyForRemoteCreditAddCredit(TUint8 aCredit) + { + iState->ProxyForRemoteCreditAddCredit(*this, aCredit); + } + +TInt CRfcommSAP::LocalCredit() const + { + return iState->LocalCredit(*this); + } + +void CRfcommSAP::SetInitialLocalCredit(TInt aCredit) + { + iState->SetInitialLocalCredit(*this, aCredit); + } +void CRfcommSAP::LocalCreditDecrement() + { + iState->LocalCreditDecrement(*this); + } + +void CRfcommSAP::LocalCreditAddCredit(TUint8 aCredit) + { + iState->LocalCreditAddCredit(*this, aCredit); + } + + + +TBool CRfcommSAP::HandleFrameResponseTimeout() + /** + There has been a timeout while waiting for a response to a previously sent frame. + **/ + { + return iState->HandleFrameResponseTimeout(*this); + } + +void CRfcommSAP::IoctlComplete(TInt aErr, TUint aLevel, TUint aName, TDesC8* aBuf) + { + if (iIoctlLevel!=aLevel || iIoctlName!=aName) + return; // wasn't for us + + if (iIoctlLevel == KSolBtRFCOMM) + iState->IoctlComplete(*this, aErr, aLevel, aName, aBuf); // the state machine is the best place to find out what to do + else + { + iIoctlLevel = 0; + iIoctlName = 0; + + if (aErr==KErrNone) + iSocket->IoctlComplete(aBuf); + else if(iSocket) + iSocket->Error(aErr, MSocketNotify::EErrorIoctl); + } + } + +void CRfcommSAP::PN(TRfcommPortParams& aParams, CRfcommMuxer& aMuxer, TUint8 aDLCI) + { + iState->PN(*this, aParams, aMuxer, aDLCI); + } + +void CRfcommSAP::SABM(CRfcommMuxer& aMuxer, TUint8 aDLCI) + { + iState->SABM(*this, aMuxer, aDLCI); + } +