// 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 file implements the generic interface to a ESOCK PRT
// for the Bluetooth PRT module
//
//
// The Bluetooth protocol family also provides Control-plane facilities
// thereby relieving the user-plane SAPs and muxers of these duties
#include <bluetooth/logger.h>
#include "Avctp.h"
#include "bt.h"
#include "linkmgr.h"
#include "l2cap.h"
#include "rfcomm.h"
#include "sdp.h"
#include "avdtp.h"
#include "IncomingConnListener.h"
#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_BT_PRT);
#endif
#ifdef _DEBUG
PANICCATEGORY("btprt");
#endif
_LIT(KBTPrtPanic, "BluetoothPRT Panic");
void Panic(TBluetoothFamilyPanic aPanic)
{
LOG_STATIC_FUNC
User::Panic(KBTPrtPanic, aPanic);
}
extern "C"
{
IMPORT_C CProtocolFamilyBase* InstallBTProtocolFamily(); // Force export
}
EXPORT_C CProtocolFamilyBase* InstallBTProtocolFamily()
// Create a new protocol family
{
LOG_STATIC_FUNC
//Return NULL if CBTProtocolFamily::NewL() leaves
CProtocolFamilyBase* result=NULL;
TRAP_IGNORE(result=CBTProtocolFamily::NewL());
return result;
}
CBTProtocolFamily* CBTProtocolFamily::NewL()
{
#ifdef __FLOG_ACTIVE
CONNECT_LOGGER
#endif
LOG_STATIC_FUNC
// Flogging can start after the installation of the Blogger
// and the instantiation of the HCI
// LOG(_L("+CBTProtocolFamily::NewL"));
CBTProtocolFamily* pf= new (ELeave) CBTProtocolFamily();
CleanupStack::PushL(pf);
pf->ConstructL();
CleanupStack::Pop();
return pf;
}
CBTProtocolFamily::CBTProtocolFamily()
: CProtocolFamilyBase(),
iBTRefCount(0)
{
LOG_FUNC
}
void CBTProtocolFamily::ConstructL()
{
LOG_FUNC
// install TLS
Dll::SetTls(&iBTTls);
LOG(_L("+CBTProtocolFamily::ConstructL"));
iCallback = new (ELeave) CAsyncCallBack(EPriorityHigh);
}
CBTProtocolFamily::~CBTProtocolFamily()
{
LOG_FUNC
LOG(_L("+CBTProtocolFamily::~CBTProtocolFamily"));
BTSocketTimer::Close();
delete iSecurityMgr;
delete iCallback;
delete iCodServiceMan;
iControlPlane.Close();
Dll::FreeTls();
#ifdef __FLOG_ACTIVE
CLOSE_LOGGER
#endif
}
TInt CBTProtocolFamily::Install()
{
LOG_FUNC
TRAPD(err, BTSocketTimer::InitL());
return err;
}
TInt CBTProtocolFamily::Remove()
{
LOG_FUNC
// set the asynccallback to delete us cleanly
return KErrNone;
}
TUint CBTProtocolFamily::ProtocolList(TServerProtocolDesc*& aProtocolPointer)
{
LOG_FUNC
// This is cleaned up by ESOCK
aProtocolPointer = new TServerProtocolDesc[6];
if (!aProtocolPointer)
return 0;
// Note it helps if the protocols are defined here in the same order
// as in the .esk file or Esock's tags will get mis-assigned.
CLinkMgrProtocol::ProtocolIdentity(&aProtocolPointer[0]);
CL2CAPProtocol::ProtocolIdentity (&aProtocolPointer[1]);
#ifdef TCI
return 2;
#else // !TCI
CRfcommProtocol::ProtocolIdentity (&aProtocolPointer[2]);
CSdpProtocol::ProtocolIdentity (&aProtocolPointer[3]);
#ifndef BLUETOOTH_NO_AV
CAvctpProtocol::ProtocolIdentity (&aProtocolPointer[4]);
CAvdtpProtocol::ProtocolIdentity (&aProtocolPointer[5]);
return 6;
#else
#pragma message("Note: Bluetooth stack will not contain AVCTP or AVDTP");
return 4;
#endif // BLUETOOTH_NO_AV
#endif // TCI
};
CProtocolBase* CBTProtocolFamily::NewProtocolL(TUint /*aSockType*/,TUint aProtocol)
/**
Called by the socket server to create an instance of a new
Protocol (layer) of the specified name - must be a subclass of
CProtocolBase.
**/
{
LOG_FUNC
// Create the Security mgr
if (!iSecurityMgr)
{
iSecurityMgr = CBTSecMan::NewL();
}
// We create our one instance of our protocols
CBluetoothProtocolBase* p = NULL;
// Create the Cod Service manager with reference to linkmgr
if (!iCodServiceMan)
{
iCodServiceMan = CBTCodServiceMan::NewL(/*reinterpret_cast<CLinkMgrProtocol&>(p)*/);
}
switch (aProtocol)
{
case KBTLinkManager:
LOG(_L("CBTProtocolFamily::NewProtocolL - BTLinkMgr"));
p = CLinkMgrProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan);
iCodServiceMan->iLinkMgr = reinterpret_cast<CLinkMgrProtocol*>(p);
break;
#ifdef TCI
case KTCIL2CAP:
#endif
case KL2CAP:
LOG(_L("CBTProtocolFamily::NewProtocolL - L2CAP"));
p = CL2CAPProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan);
break;
#ifndef TCI
case KRFCOMM:
LOG(_L("CBTProtocolFamily::NewProtocolL - RFCOMM"));
p = CRfcommProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan );
break;
case KSDP:
LOG(_L("CBTProtocolFamily::NewProtocolL - SDP"));
p = CSdpProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan);
break;
case KAVCTP:
#ifndef BLUETOOTH_NO_AV
LOG(_L("CBTProtocolFamily::NewProtocolL - AVCTP"));
p = CAvctpProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan);
#else
LOG(_L("CBTProtocolFamily::NewProtocolL - AVCTP: NOT SUPPORTED, Leaving"));
User::Leave(KErrNotSupported);
#endif //BLUETOOTH_NO_AV
break;
case KAVDTP:
#ifndef BLUETOOTH_NO_AV
LOG(_L("CBTProtocolFamily::NewProtocolL - AVDTP"));
p = CAvdtpProtocol::NewL(*iSecurityMgr, iControlPlane, *iCodServiceMan);
#else
LOG(_L("CBTProtocolFamily::NewProtocolL - AVDTP: NOT SUPPORTED, Leaving"));
User::Leave(KErrNotSupported);
#endif //BLUETOOTH_NO_AV
break;
#endif //TCI
default:
User::Leave(KErrArgument);
}
CleanupStack::PushL(p);
iControlPlane.AttachProtocolL(aProtocol, *p);
CleanupStack::Pop(p);
return p;
}
void CBTProtocolFamily::Open()
{
LOG_FUNC
// we don't use the reference-counting of the base-class. We prefer to async close
// so we override Open amd implement our own ref counting.
iBTRefCount++;
}
void CBTProtocolFamily::Close()
{
LOG_FUNC
if(--iBTRefCount <= 0)
{
iBTRefCount = 0;
iCallback->Cancel();
// defer calling d'tor
TCallBack cb(Destruct, this);
iCallback->Set(cb);
iCallback->CallBack();
}
}
/*static*/ TInt CBTProtocolFamily::Destruct(TAny* aProtocolFamily)
{
LOG_STATIC_FUNC
// self-destruct
CProtocolFamilyBase* p = reinterpret_cast<CProtocolFamilyBase*>(aProtocolFamily);
delete p;
return EFalse;
}
CBluetoothProtocolBase::CBluetoothProtocolBase(CBTSecMan& aSecMan, RBTControlPlane& aControlPlane, CBTCodServiceMan& aCodMan)
: iSecMan(aSecMan), iControlPlane(aControlPlane), iCodMan(aCodMan)
{
LOG_FUNC
}
CBluetoothProtocolBase::~CBluetoothProtocolBase()
{
LOG_FUNC
// detach from control plane
ControlPlane().DetachProtocol(*this);
delete iListener;
}
TInt CBluetoothProtocolBase::IncrementListeners()
/**
A protocol object (typically a SAP) has declared that it is listening
This may mean that the protocol has to provide a bearer-listener
**/
{
LOG_FUNC
TInt retVal = KErrNone;
if (!iListeningEntities++)
{
// need our own listener to bring up lower layers if required for this protocol-level listening SAPs
retVal = StartProtocolListening();
}
return retVal;
}
void CBluetoothProtocolBase::DecrementListeners()
/**
A protocol object (typically a SAP) has declared that it is not listening
This may mean that the protocol can cleanup the bearer-listener
**/
{
LOG_FUNC
--iListeningEntities;
ASSERT_DEBUG(iListeningEntities>=0);
if (!iListeningEntities)
{
// stop protocol listening
StopProtocolListening();
}
}
TInt CBluetoothProtocolBase::StartListening(TUint aPort, TUint aSockType, TUint aQueSize, TUid aUid)
{
LOG_FUNC
TRAPD(err, DoStartListeningL(aPort, aSockType, aQueSize, aUid));
return err;
}
TInt CBluetoothProtocolBase::StartProtocolListening()
{
LOG_FUNC
// protocol doesnt support listening
Panic(EBTPrtProtocolCannotListen);
return KErrNotSupported;
}
// default implementation for stopping a protocol listening
void CBluetoothProtocolBase::StopProtocolListening()
{
LOG_FUNC
delete iListener;
iListener = NULL;
}
void CBluetoothProtocolBase::DoStartListeningL(TUint aPort, TUint aSockType, TUint aQueSize, TUid aUid)
{
LOG_FUNC
CServProviderBase* sap =iLowerProtocol->NewSAPL(aSockType);
iListener=CIncomingConnectionListener::NewL(*this, sap, aPort, aQueSize, aUid);
}
TInt CBluetoothProtocolBase::ControlPlaneMessage(TBTControlPlaneMessage /*aMessage*/, TAny* /*aParam*/)
{
LOG_FUNC
__DEBUGGER(); // a C-plane message was targetted for a protocol that didnt implement C-plane stuff
return KErrNotSupported;
}
void CBluetoothProtocolBase::Error(TInt /*aError*/,CProtocolBase* /*aSourceProtocol=NULL*/)
{
LOG_FUNC
//Don't do anything, overrides CProtocolBase::Error which causes a Panic
}
void RBTControlPlane::AttachProtocolL(TInt aProtocolNum, CBluetoothProtocolBase& aProtocol)
/**
Called when a protocol is instantiated - allows the Control plane to
be aware of it
**/
{
LOG_FUNC
if (Protocol(aProtocolNum))
{
User::Leave(KErrAlreadyExists);
}
TBTProtocol protocol;
protocol.iProtocolNum = aProtocolNum;
protocol.iProtocol = &aProtocol;
User::LeaveIfError(iProtocols.Append(protocol));
}
void RBTControlPlane::DetachProtocol(CBluetoothProtocolBase& aProtocol)
{
LOG_FUNC
for (TInt i=0; i<iProtocols.Count();i++)
{
if (iProtocols[i].iProtocol == &aProtocol)
{
iProtocols.Remove(i);
break;
}
}
}
void RBTControlPlane::Close()
{
LOG_FUNC
iProtocols.Close();
}
CBluetoothProtocolBase* RBTControlPlane::Protocol(TInt aProtocolNum) const
{
LOG_FUNC
CBluetoothProtocolBase* p= NULL;
for (TInt i=0; i<iProtocols.Count(); i++)
{
if (iProtocols[i].iProtocolNum == aProtocolNum)
p = iProtocols[i].iProtocol;
}
return p; // does not pass ownership
}
/*
a C-plane message to send a signal to the (possible) SAP handling the physical link
to the address aAddr
*/
TInt RBTControlPlane::ModifyPhysicalLink(TBTControlPlaneMessage aMessage, const TBTDevAddr& aAddr) const
{
LOG_FUNC
// link mgr must be there!
CBluetoothProtocolBase* linkmgr = Protocol(KBTLinkManager);
ASSERT_DEBUG(linkmgr);
return linkmgr->ControlPlaneMessage(aMessage, const_cast<TAny*>(reinterpret_cast<const TAny*>(&aAddr)));
}
void RBTControlPlane::TryToAndThenPreventHostEncryptionKeyRefresh(const TBTDevAddr& aAddr, MBluetoothControlPlaneToken*& aOutToken)
{
LOG_FUNC
CBluetoothProtocolBase* linkmgr = Protocol(KBTLinkManager);
ASSERT_DEBUG(linkmgr);
const TBTDevAddr* addrPtr = &aAddr;
TAny* ptr = reinterpret_cast<TAny*>(&addrPtr);
TInt err = linkmgr->ControlPlaneMessage(ETryToAndThenPreventHostEncryptionKeyRefresh, ptr);
if (err == KErrNone)
{
aOutToken = *reinterpret_cast<MBluetoothControlPlaneToken**>(ptr);
}
else
{
aOutToken = NULL;
}
}
/*
a C-plane message to send a message to a target protocol telling them not to authorise a device
used for multiple protocols taking part in a single use-case that requires only
one authorisation - eg AVCTP and AVDTP doing A2DP + AVRCP stereo headset
*/
TInt RBTControlPlane::Preauthorise(TInt aTargetProtocolNum,
const TOverrideAuthorise& aSetPreauthorisation)
{
LOG_FUNC
// either protocol may not be running
CBluetoothProtocolBase* target = Protocol(aTargetProtocolNum);
if (target)
{
return target->ControlPlaneMessage(EPreauthoriseDevice, const_cast<TAny*>(reinterpret_cast<const TAny*>(&aSetPreauthorisation)));
}
else
{
return KErrNotFound;
}
}
TPhysicalLinkPresent RBTControlPlane::PhysicalLinkPresent(const TBTDevAddr& aAddr) const
{
LOG_FUNC
// need to stick down a control plane message to ascertain whether a physical channel is in place
// linkmgr must be there
CBluetoothProtocolBase* linkmgr = Protocol(KBTLinkManager);
ASSERT_DEBUG(linkmgr);
return static_cast<TPhysicalLinkPresent>(
linkmgr->ControlPlaneMessage(EPresent,
const_cast<TAny*>(reinterpret_cast<const TAny*>(&aAddr))));
}
/*
a C-plane message to send a signal to the (possible) SAP handling the Physical Link(aAddr)
to add aObserver to its list of subscribers.
*/
TInt RBTControlPlane::SubscribePhysicalLink(MPhysicalLinkObserver& aObserver, TBTDevAddr aAddr) const
{
LOG_FUNC
// link mgr must be there!
CBluetoothProtocolBase* linkmgr = Protocol(KBTLinkManager);
ASSERT_DEBUG(linkmgr);
TPhysicalLinkSubscriptionInfo subscriptionInfo(aObserver,aAddr);
return linkmgr->ControlPlaneMessage(ESubscribePhysicalLink, const_cast<TAny*>(reinterpret_cast<const TAny*>(&subscriptionInfo)));
}
/*
a C-plane message to send a signal to the (possible) SAP handling the Physical Link(aAddr)
to remove aObserver its list of subscribers.
*/
TInt RBTControlPlane::UnsubscribePhysicalLink(MPhysicalLinkObserver& aObserver, TBTDevAddr aAddr) const
{
LOG_FUNC
// link mgr must be there!
CBluetoothProtocolBase* linkmgr = Protocol(KBTLinkManager);
ASSERT_DEBUG(linkmgr);
TPhysicalLinkSubscriptionInfo subscriptionInfo(aObserver,aAddr);
return linkmgr->ControlPlaneMessage(EUnsubscribePhysicalLink, const_cast<TAny*>(reinterpret_cast<const TAny*>(&subscriptionInfo)));
}
void MBluetoothControlPlaneToken::Release(MBluetoothControlPlaneToken*& aToken)
{
if(aToken)
{
aToken->Release();
aToken = NULL;
}
}