// Copyright (c) 1999-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:// This implements the CL2CAPProtocol object that is the contact point from// BT PRT to the L2cap stack// //#include <bluetooth/logger.h>#include <bt_sock.h>#include <bluetooth/aclsockaddr.h>#include "l2cap.h"#include "l2sapstates.h"#include "l2util.h"#include "linkmgr.h"#include "l2capSAPSignalHandler.h"#include "l2sap.h"#ifdef _DEBUG#include "L2CapDebugControlInterface.h"#endif#ifdef __FLOG_ACTIVE_LIT8(KLogComponent, LOG_COMPONENT_L2CAP);#endif// Construction & InitialisationCL2CAPProtocol::CL2CAPProtocol(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan) : CBluetoothProtocolBase(aSecMan, aControlPlane, aCodMan) { LOG_FUNC TCallBack cb(TryToClose, this); iIdleTimerEntry.Set(cb); }CL2CAPProtocol::~CL2CAPProtocol() { LOG_FUNC RemoveIdleTimerEntry(); delete iStateFactory; delete iSigStateFactory; if(LowerProtocol()) { LowerProtocol()->Close(); } // Delete the Mux controller. delete iMuxController;#ifdef _DEBUG SBtTls* tls = static_cast<SBtTls*>(Dll::Tls()); CDebugControlInterface* ptr = tls->iDebugCtrlIF; delete ptr; tls->iDebugCtrlIF = NULL;#endif#ifdef __FLOG_ACTIVE CLOSE_LOGGER#endif }CL2CAPProtocol* CL2CAPProtocol::NewL(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan) {#ifdef __FLOG_ACTIVE CONNECT_LOGGER#endif LOG_STATIC_FUNC CL2CAPProtocol* prot = new (ELeave) CL2CAPProtocol(aSecMan, aControlPlane, aCodMan); CleanupStack::PushL(prot); prot->ConstructL(); CleanupStack::Pop(); return prot; }void CL2CAPProtocol::ConstructL() { LOG_FUNC iMuxController = new (ELeave) CL2CAPMuxController(*this); }void CL2CAPProtocol::InitL(TDesC& /*aTag*/)/** Pre-binding initialise. Allocate any objects we need here. The socket ensures that this function will only be called once per object of this class, regardless of how long it hangs around.**/ { LOG_FUNC // Init __ASSERT_DEBUG(!iClosePending, Panic(EL2CAPProtocolOpenedAfterClose)); __ASSERT_DEBUG(!iIdleEntryQueued, Panic(EL2CAPProtocolOpenedAfterClose)); __ASSERT_DEBUG(!iStateFactory, Panic(EL2CAPProtocolOpenedAfterClose)); __ASSERT_DEBUG(!iSigStateFactory, Panic(EL2CAPProtocolOpenedAfterClose)); // Create all the things we need now LOG(_L("L2CAP : Initialising states")); iStateFactory=CL2CAPSAPStateFactory::NewL(); iSigStateFactory=CL2CAPSignalStateFactory::NewL(); LOG(_L("L2CAP : Initialising complete"));#ifdef _DEBUG SBtTls* tls = static_cast<SBtTls*>(Dll::Tls()); tls->iDebugCtrlIF = CDebugControlInterface::NewL();#endif }void CL2CAPProtocol::StartL()/** Binding complete. Startup call from socket. Do nothing**/ { LOG_FUNC }// From higher protocolvoid CL2CAPProtocol::BindL(CProtocolBase* /*aProtocol*/, TUint /*aId*/) { // Could register the protocol that's bound to us LOG_FUNC }void CL2CAPProtocol::BindToL(CProtocolBase* aProtocol) { LOG_FUNC#ifdef _DEBUG TServerProtocolDesc prtDesc; aProtocol->Identify(&prtDesc); if(prtDesc.iAddrFamily!=KBTAddrFamily || prtDesc.iProtocol!=KBTLinkManager) { LEAVEL(KErrBtEskError); }#endif aProtocol->BindL(this, 0); aProtocol->Open(); iLowerProtocol = static_cast<CBluetoothProtocolBase*>(aProtocol); }// Factory functionsCServProviderBase* CL2CAPProtocol::NewSAPL(TUint aSockType)/** Create a new SAP. The SAP returned is owned by the caller -- this protocol will not clean it up. The socket uses this function to create a new SAP, and the socket will delete when it is finished with it.**/ { LOG_FUNC CL2CAPConnectionSAP* lsap = NULL; switch(aSockType) { case KSockSeqPacket: // packet interface lsap=CL2CAPConnectionSAP::NewL(*this); break; default: LEAVEL(KErrNotSupported); break; } return lsap; }// Query functionsvoid CL2CAPProtocol::Identify(TServerProtocolDesc *aDesc)const//// Identify request from SOCKET server// { LOG_FUNC CL2CAPProtocol::ProtocolIdentity(aDesc); }void CL2CAPProtocol::ProtocolIdentity(TServerProtocolDesc* aDesc) { LOG_STATIC_FUNC _LIT(name,"L2CAP"); aDesc->iProtocol=KL2CAP; aDesc->iName=name; aDesc->iAddrFamily=KBTAddrFamily; aDesc->iSockType=KSockSeqPacket; aDesc->iVersion=TVersion(KBTMajor,KBTMinor,KBTBuild); aDesc->iByteOrder=ELittleEndian; aDesc->iServiceInfo=KL2CAPSeqPacketServiceInfo; aDesc->iNamingServices=0; aDesc->iSecurity=KSocketNoSecurity; aDesc->iMessageSize=KSocketMessageSizeNoLimit; //This is the MAX packet size. aDesc->iServiceTypeInfo=ESocketSupport|ETransport|EPreferMBufChains|ENeedMBufs|EUseCanSend; aDesc->iNumSockets=KL2CAPSockets; }void CL2CAPProtocol::CloseNow()/** Close command from base class. Called when ref count reaches 0. We don't actually have to close now, but when we finally do, we must call CanClose (done within TryToClose). That will actually delete us. In the mean time, if a new client tries to connect to L2CAP, the socket will use this existing one and just call Open on it. What we do here, is queue an idle timer entry. It's expiry will call TryToClose, which will actually do the close.**/ { LOG_FUNC iClosePending = ETrue; QueIdleTimerEntry(); }void CL2CAPProtocol::Open()/** Open L2CAP protocol. Called every time a new client (of L2CAP) wants to use it.**/ { LOG_FUNC iClosePending = EFalse; RemoveIdleTimerEntry(); CProtocolBase::Open(); }void CL2CAPProtocol::Close() { LOG_FUNC CProtocolBase::Close(); }void CL2CAPProtocol::QueIdleTimerEntry()/** Queue idle timer entry. When this timer expires, it'll call TryToClose, which actually causes the thing to finally close down.**/ { LOG_FUNC RemoveIdleTimerEntry(); iIdleEntryQueued = ETrue; BTSocketTimer::Queue(KL2ProtocolIdleTimeout*KL2ProtocolSecondTimerMultiplier, iIdleTimerEntry); }void CL2CAPProtocol::RemoveIdleTimerEntry()/** Called whenever we're opened. Checks there are no idle timer entries queued.**/ { LOG_FUNC if (!iIdleEntryQueued) return; BTSocketTimer::Remove(iIdleTimerEntry); iIdleEntryQueued = EFalse; }void CL2CAPProtocol::TryToClose() { LOG_FUNC if (!iIdleEntryQueued && iClosePending && MuxController().CanProtocolClose()) { CanClose(); } }TInt CL2CAPProtocol::TryToClose(TAny* aProtocol)/* Actually try to close the protocol. Called after the idle timeout period by the BTSocketTimer. If we're all set to close down, the thing is closed.*/ { LOG_STATIC_FUNC CL2CAPProtocol* p=static_cast<CL2CAPProtocol*>(aProtocol); p->iIdleEntryQueued = EFalse; p->TryToClose(); return EFalse; }CL2CAPSAPStateFactory& CL2CAPProtocol::StateFactory() const { LOG_FUNC return *iStateFactory; }CL2CAPSignalStateFactory& CL2CAPProtocol::SigStateFactory() const { LOG_FUNC return *iSigStateFactory; }TInt CL2CAPProtocol::BearerConnectComplete(const TBTDevAddr& aAddr, CServProviderBase* aSAP) { LOG_FUNC return iMuxController->BearerConnectComplete(aAddr, aSAP); }const TBTDevAddr& CL2CAPProtocol::LocalBTAddr() const { LOG_FUNC return static_cast<CLinkMgrProtocol*>(iLowerProtocol)->LocalBTAddress(); }TInt CL2CAPProtocol::StartProtocolListening()// forward L2CAPs listening requirements to listener { LOG_FUNC return CBluetoothProtocolBase::StartListening(EACLPortL2CAP, KSockBluetoothTypeACL, KL2CAPIncomingConnQueueSize, KUidServiceL2CAP); }