bluetooth/btstack/secman/pairingserver.cpp
changeset 0 29b1cd4cb562
child 8 2b6718f05bdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/secman/pairingserver.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1214 @@
+// 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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <e32base.h>
+#include <bttypes.h>
+#include <bluetooth/pairing.h>
+#include <bluetooth/pairingservershared.h>
+
+#include "pairingserversecuritypolicy.h"
+#include "oobdata.h"
+#include "pairingserver.h"
+
+#include <bluetooth/logger.h>
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAIRING_SERVER);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("pairingsrv");
+#endif
+
+// These come after the logging to ensure that debug.h knows we're using the
+// bluetooth logger.
+#include "physicallinksmanager.h"
+#include "ProxySAP.h"
+
+//
+// CPairingServer
+//
+
+CPairingServer* CPairingServer::NewL(COobDataManager& aOobDataManager, CSimplePairingResultList& aSimplePairingResultList, CAuthenticationResultList& aAuthenticationResultList)
+	{
+	LOG_STATIC_FUNC
+
+	CPairingServer* self = new(ELeave) CPairingServer(aOobDataManager, aSimplePairingResultList, aAuthenticationResultList);
+	CleanupStack::PushL(self);
+	// StartL is where the kernel checks that there isn't already an instance
+	// of the same server running, so do it before ConstructL.
+	self->StartL(KPairingServerName);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CPairingServer::~CPairingServer()
+	{
+	LOG_FUNC
+	delete iContainerIndex;
+	}
+
+CPairingServer::CPairingServer(COobDataManager& aOobDataManager, CSimplePairingResultList& aSimplePairingResultList, CAuthenticationResultList& aAuthenticationResultList)
+	: CPolicyServer(CActive::EPriorityStandard, KPairingServerPolicy)
+	, iOobDataManager(aOobDataManager)
+	, iSimplePairingResultList(aSimplePairingResultList)
+	, iAuthenticationResultList(aAuthenticationResultList)
+	{
+	LOG_FUNC
+	}
+
+void CPairingServer::ConstructL()
+	{
+	LOG_FUNC
+	iContainerIndex = CObjectConIx::NewL();
+	}
+
+// Callback to LinksMgrProtocol to add a pairing session
+void CPairingServer::AddSession()
+	{
+	LOG_FUNC
+	if(iSessionCount++ == 0)
+		{
+		// While we have clients we need to make sure that the protocol remains alive.
+		iLinkMgrProtocol->LocalOpen();
+		}
+	}
+
+// Callback to LinksMgrProtocol to remove a pairing session
+void CPairingServer::DropSession()
+	{
+	LOG_FUNC
+	if(--iSessionCount == 0)
+		{
+		// There are no longer any clients
+		iLinkMgrProtocol->LocalClose();
+		}
+	}
+
+void CPairingServer::SetPhysicalLinksManager(CPhysicalLinksManager& aLinksMan)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(!iLinksMan, PANIC(KPairingServerFaultCat, EPairingServerLinkManagerAlreadyProvided));
+	iLinksMan = &aLinksMan;
+	}
+
+void CPairingServer::ClearPhysicalLinkMgr()
+	{
+	LOG_FUNC
+	iLinksMan = NULL;
+	}
+
+// Save a reference to the LinksMgrProtocol
+void CPairingServer::SetLinksMgrProtocol(CLinkMgrProtocol& aLinkMgrProtocol)
+	{
+	LOG_FUNC
+	iLinkMgrProtocol = &aLinkMgrProtocol;
+	}
+
+// Clear the reference to the LinksMgrProtocol
+void CPairingServer::ClearLinksMgrProtocol()
+	{
+	LOG_FUNC
+	iLinkMgrProtocol = NULL;
+	}
+
+CSession2* CPairingServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
+	{
+	LOG_FUNC
+	LOG3(_L("aVersion = (%d, %d, %d)"), aVersion.iMajor, aVersion.iMinor, aVersion.iBuild)
+
+	// Version number check...
+	TVersion v(KPairingServerMajorVersionNumber,
+			   KPairingServerMinorVersionNumber,
+			   KPairingServerBuildVersionNumber);
+	if(!User::QueryVersionSupported(v, aVersion))
+		{
+		User::LeaveIfError(KErrNotSupported);
+		}
+
+	// Ensure that the reference to the LinksMgrProtocol has been receieved
+	if(!iLinkMgrProtocol)
+		{
+		User::Leave(KErrNotReady);
+		}
+	// Cast 'this' to allow use in Constructor 
+	CPairingServer* ncThis = const_cast<CPairingServer*>(this);
+	CPairingSession* sess = CPairingSession::NewL(*ncThis);
+	return sess;
+	}
+
+CObjectCon* CPairingServer::NewContainerL()
+	{
+	LOG_FUNC
+	return iContainerIndex->CreateL();
+	}
+
+void CPairingServer::DeleteContainer(CObjectCon* aContainer)
+	{
+	LOG_FUNC
+	iContainerIndex->Remove(aContainer);
+	}
+
+CPhysicalLinksManager& CPairingServer::LinksManL() const
+	{
+	LOG_FUNC
+	if(!iLinksMan)
+		{
+		LEAVEL(KErrNotReady);
+		}
+	return *iLinksMan;
+	}
+
+COobDataManager& CPairingServer::OobDataManager() const
+	{
+	LOG_FUNC
+	return iOobDataManager;
+	}
+
+CSimplePairingResultList& CPairingServer::SimplePairingResultList() const
+	{
+	LOG_FUNC
+	return iSimplePairingResultList;
+	}
+
+CAuthenticationResultList& CPairingServer::AuthenticationResultList() const
+	{
+	LOG_FUNC
+	return iAuthenticationResultList;
+	}
+
+//
+// CPairingSession
+//
+
+CPairingSession* CPairingSession::NewL(CPairingServer& aPairingServer)
+	{
+	LOG_STATIC_FUNC
+	CPairingSession* self = new(ELeave) CPairingSession(aPairingServer);
+	aPairingServer.AddSession();
+	return self;
+	}
+
+CPairingSession::CPairingSession(CPairingServer& aPairingServer)
+	: iPairingServer(aPairingServer)
+	{
+	LOG_FUNC
+	}
+
+CPairingServer& CPairingSession::Server() const
+	{
+	LOG_FUNC
+	return *static_cast<CPairingServer*>(const_cast<CServer2*>(CSession2::Server()));
+	}
+
+CPairingSession::~CPairingSession()
+	{
+	LOG_FUNC
+	iPairingServer.DropSession();
+	delete iSubSessions; // Must be deleted before container to ensure ref counting is correct
+	Server().DeleteContainer(iContainer);
+	}
+
+void CPairingSession::CreateL()
+	{
+	LOG_FUNC
+	iSubSessions = CObjectIx::NewL();
+	iContainer = Server().NewContainerL();
+	__TEST_INVARIANT;
+	}
+
+#ifdef _DEBUG
+void CPairingSession::__DbgTestInvariant() const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iContainer->Count() == iSubSessions->ActiveCount(),
+			PANIC(KPairingServerFaultCat, EPairingServerSessionContainerAndIndexMismatch));
+	}
+#endif // _DEBUG
+
+void CPairingSession::ServiceL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	LOG1(_L("aMessage.Function() = &d"), aMessage.Function());
+//	__TEST_INVARIANT; // Not needed as all major functional exits are checked
+	TBool handled = DispatchSessMessageL(aMessage);
+	if(!handled)
+		{
+		// if not handled, it must be a subsession request.
+		DispatchSubSessMessageL(aMessage);
+		}
+	__TEST_INVARIANT;
+	}
+
+void CPairingSession::ServiceError(const RMessage2& aMessage, TInt aError)
+	{
+	LOG_FUNC
+	LOG1(_L("aError = %d"), aError);
+	if(aError == KErrBadDescriptor)
+		{
+		// If a KErrBadDescriptor is received then the request is bad so punish.
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerBadDescriptor);
+		}
+	else
+		{
+		aMessage.Complete(aError);
+		}
+	__TEST_INVARIANT;
+	}
+
+TBool CPairingSession::DispatchSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	TBool handled = ETrue;
+	switch(aMessage.Function())
+		{
+	case EPairingServerCreateOobDataSubSession:
+		NewOobDataSubSessionL(aMessage);
+		break;
+
+	case EPairingServerCreateDedicatedBondingSubSession:
+		NewDedicatedBondingSubSessionL(aMessage);
+		break;
+
+	case EPairingServerCreateSimplePairingResultSubSession:
+		NewSimplePairingResultSubSessionL(aMessage);
+		break;
+
+	case EPairingServerCreateAuthenticationResultSubSession:
+		NewAuthenticationResultSubSessionL(aMessage);
+		break;
+
+	case EPairingServerCloseSubSession:
+		DeleteSubSession(aMessage);
+		break;
+
+	default:
+		handled = EFalse;
+		break;
+		}
+	return handled;
+	}
+
+void CPairingSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	CPairingSubSession* ss = SubSessionFromHandle(aMessage.Int3());
+	if(!ss)
+		{
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerBadSubSessionHandle);
+		}
+	else
+		{
+		ss->DispatchSubSessMessageL(aMessage);
+		}
+	}
+
+CPairingSubSession* CPairingSession::SubSessionFromHandle(TInt aHandle)
+	{
+	LOG_FUNC
+	LOG1(_L("aHandle = %d"), aHandle);
+	return static_cast<CPairingSubSession*>(iSubSessions->At(aHandle));
+	}
+
+void CPairingSession::NewOobDataSubSessionL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	COobDataSession* oob = COobDataSession::NewLC(*this, Server().OobDataManager());
+	SubSessionConstructL(aMessage, oob); // handles oob on CleanupStack
+	}
+
+void CPairingSession::NewDedicatedBondingSubSessionL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	CDedicatedBondingSession* ded = CDedicatedBondingSession::NewLC(*this, Server().LinksManL());
+	SubSessionConstructL(aMessage, ded); // handles ded on CleanupStack
+	}
+
+void CPairingSession::NewSimplePairingResultSubSessionL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	CSimplePairingResultSession* sim = CSimplePairingResultSession::NewLC(*this, Server().SimplePairingResultList());
+	SubSessionConstructL(aMessage, sim);
+	}
+
+
+void CPairingSession::NewAuthenticationResultSubSessionL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	CAuthenticationResultSession* aut = CAuthenticationResultSession::NewLC(*this, Server().AuthenticationResultList());
+	SubSessionConstructL(aMessage, aut);
+	}
+
+/**
+This function handles the subsession handle binding to the subsession that has been
+created.
+*/
+void CPairingSession::SubSessionConstructL(const RMessage2& aMessage, CPairingSubSession* aSubSession)
+	{
+	LOG_FUNC
+	// The subsession is on the cleanup stack when this function is called.
+	TInt subSessionHandleLength = aMessage.GetDesMaxLengthL(3);
+	if(subSessionHandleLength != sizeof(TInt))
+		{
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerBadDescriptor);
+		CleanupStack::PopAndDestroy(aSubSession);
+		}
+	else
+		{
+		iContainer->AddL(aSubSession);
+		TInt handle = iSubSessions->AddL(aSubSession);
+		CleanupStack::Pop(aSubSession); // Now lifetime is controlled by the binding CObjectIx
+		TPckg<TInt> pckgHandle(handle);
+		TRAPD(err, aMessage.WriteL(3, pckgHandle));
+		if(err != KErrNone)
+			{
+			iSubSessions->Remove(handle);
+			LEAVEL(err);
+			}
+		aMessage.Complete(KErrNone);
+		}
+	}
+
+void CPairingSession::DeleteSubSession(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	TInt handle = aMessage.Int3();
+	CPairingSubSession* ss = SubSessionFromHandle(handle);
+	if(!ss)
+		{
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerBadSubSessionHandle);
+		}
+	else
+		{
+		iSubSessions->Remove(handle);
+		aMessage.Complete(KErrNone);
+		}
+	}
+
+
+//
+// CPairingSubSession
+//
+
+CPairingSubSession::CPairingSubSession(CPairingSession& aSession)
+	: iSession(aSession)
+	{
+	LOG_FUNC
+	}
+
+CPairingSubSession::~CPairingSubSession()
+	{
+	LOG_FUNC
+	}
+
+void CPairingSubSession::DispatchSubSessMessageL(const RMessage2& /*aMessage*/)
+	{
+	LOG_FUNC
+	LEAVEL(KErrNotSupported);
+	}
+
+void CPairingSubSession::ConstructL()
+	{
+	LOG_FUNC
+	}
+
+CPairingSession& CPairingSubSession::Session() const
+	{
+	LOG_FUNC
+	return iSession;
+	}
+
+
+//
+// COobDataSession
+//
+
+COobDataSession* COobDataSession::NewLC(CPairingSession& aSession, COobDataManager& aOobDataManager)
+	{
+	LOG_STATIC_FUNC
+	COobDataSession* self = new(ELeave) COobDataSession(aSession, aOobDataManager);
+	//As its a CObject derived class so we should use CleanupClosePushL
+	CleanupClosePushL(*self);
+	self->ConstructL();
+	return self;
+	}
+
+COobDataSession::COobDataSession(CPairingSession& aSession, COobDataManager& aOobDataManager)
+	: CPairingSubSession(aSession)
+	, iOobDataManager(aOobDataManager)
+	{
+	LOG_FUNC
+	}
+
+COobDataSession::~COobDataSession()
+	{
+	LOG_FUNC
+	TryCancelReadLocalOobData();
+	}
+
+COobDataManager& COobDataSession::OobDataManager() const
+	{
+	LOG_FUNC
+	return iOobDataManager;
+	}
+
+void COobDataSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	switch(aMessage.Function())
+		{
+	case EPairingServerOobDataRefreshLocal:
+		iOobDataManager.RefreshLocalOobData();
+		aMessage.Complete(KErrNone);
+		break;
+	case EPairingServerOobDataReadLocal:
+		ReadLocalOobDataL(aMessage);
+		break;
+	case EPairingServerOobDataCancelReadLocal:
+		CancelReadLocalOobData(aMessage);
+		break;
+	case EPairingServerOobDataProvideRemoteParsed:
+		ProvideParsedRemoteOobDataL(aMessage);
+		break;
+	case EPairingServerOobDataProvideRemoteRaw:
+		ProvideRawRemoteOobDataL(aMessage);
+		break;
+	case EPairingServerOobDataClearRemote:
+		ClearRemoteOobDataL(aMessage);
+		break;
+	default:
+		CPairingSubSession::DispatchSubSessMessageL(aMessage);
+		break;
+		}
+	}
+
+void COobDataSession::ProvideParsedRemoteOobDataL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TPckgBuf<TBTDevAddr> addrBuf;
+	if(aMessage.GetDesLengthL(0) != sizeof(TBTDevAddr))
+		{
+		LEAVEL(KErrBadDescriptor);
+		}
+	aMessage.ReadL(0, addrBuf);
+
+	TBluetoothSimplePairingHash hash;
+	if(aMessage.GetDesLengthL(1) != KBluetoothSimplePairingHashSize)
+		{
+		LEAVEL(KErrBadDescriptor);
+		}
+	aMessage.ReadL(1, hash);
+
+	TBluetoothSimplePairingRandomizer randomizer;
+	TInt len = aMessage.GetDesLength(2);
+	if (len < KErrNone) // The randomizer wasn't available (which is fine...)
+		{
+		randomizer.FillZ(KBluetoothSimplePairingRandomizerSize);
+		}
+	else
+		{
+		if(len != KBluetoothSimplePairingRandomizerSize)
+			{
+			LEAVEL(KErrBadDescriptor);
+			}
+		aMessage.ReadL(2, randomizer);
+		}
+
+	TOobData oobData(addrBuf(), hash, randomizer);
+	OobDataManager().ProvideRemoteOobDataL(oobData);
+	aMessage.Complete(KErrNone);
+	}
+
+void COobDataSession::ProvideRawRemoteOobDataL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	//Do a quick check to ensure there is at least enough data to get the BT address out.
+	if(aMessage.GetDesLengthL(0) < KOOBOptionalDataOffset)
+		User::Leave(KErrUnderflow);
+
+	RBuf8 rawBuf;
+	rawBuf.CreateL(aMessage.GetDesMaxLengthL(0));
+	rawBuf.CleanupClosePushL();
+	//Read the optional oob data to rawbuf so it can be parsed to the data block parser
+	aMessage.ReadL(0, rawBuf, KOOBOptionalDataOffset);
+	rawBuf.SetMax();
+
+	//We need to get the address out manually, EIR can't parse the address an no EIR device
+	//address tag is defined. We are currently ignoring the length and anything other than
+	//the pairing hash & randomizer.
+	TBuf8<KBTDevAddrSize> addrBuf;
+	aMessage.ReadL(0, addrBuf, KOOBBtAddrOffset);
+	TBTDevAddr addr(addrBuf);
+
+	//Any remaining data is optional and will be in EIR format so we can use the
+	//EIR object to parse the data properly.
+	TExtendedInquiryResponseDataCodec dataBlockParser(rawBuf);
+
+	TPtrC8 hashBuf;
+	LEAVEIFERRORL(dataBlockParser.GetData(EEirOobSimplePairingHash, hashBuf));
+	if(hashBuf.Length() != KBluetoothSimplePairingHashSize)
+		{
+		LEAVEL(KErrCorrupt);
+		}
+	TBluetoothSimplePairingHash hash(hashBuf);
+
+	TPtrC8 randomizerBuf;
+	TBluetoothSimplePairingRandomizer randomizer;
+	TInt err = dataBlockParser.GetData(EEirOobSimplePairingRandomizerR, randomizerBuf);
+	if(err < KErrNone) // The randomizer wasn't available (which is fine...)
+		{
+		randomizer.FillZ(KBluetoothSimplePairingRandomizerSize);
+		}
+	else
+		{
+		if(randomizerBuf.Length() != KBluetoothSimplePairingRandomizerSize)
+			{
+			LEAVEL(KErrCorrupt);
+			}
+		randomizer.Copy(randomizerBuf);
+		}
+
+	// Mark this line as intentional as coverity raises a false positive error that hash
+	// has not been initalised even though it is set to hashBuf a few lines above.
+	// coverity[uninit_use_in_call]
+	TOobData oobData(addr, hash, randomizer);
+	OobDataManager().ProvideRemoteOobDataL(oobData);
+
+	CleanupStack::PopAndDestroy(&rawBuf); // finished with the backing buffer
+
+	aMessage.Complete(KErrNone);
+	}
+
+void COobDataSession::ClearRemoteOobDataL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	TPckgBuf<TBTDevAddr> addrBuf;
+	if(aMessage.GetDesLengthL(0) != sizeof(TBTDevAddr))
+		{
+		LEAVEL(KErrBadDescriptor);
+		}
+	aMessage.ReadL(0, addrBuf);
+
+	OobDataManager().ClearRemoteOobData(addrBuf());
+	aMessage.Complete(KErrNone);
+	}
+
+void COobDataSession::ReadLocalOobDataL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	if(iReadLocalOobDataMsg.Handle())
+		{
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerReadLocalOobDataOutstanding);
+		return;
+		}
+	iReadLocalOobDataMsg = aMessage; // Remember which request to complete.
+	OobDataManager().ReadLocalOobData(*this);
+	}
+
+void COobDataSession::CancelReadLocalOobData(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	TryCancelReadLocalOobData();
+	aMessage.Complete(KErrNone);
+	}
+
+void COobDataSession::TryCancelReadLocalOobData()
+	{
+	LOG_FUNC
+	if(iReadLocalOobDataMsg.Handle())
+		{
+		OobDataManager().CancelReadLocalOobData(*this);
+		}
+	}
+
+
+void COobDataSession::XoldoLocalOobDataRetrieved(TInt aResult, const TBluetoothSimplePairingHash& aHash, const TBluetoothSimplePairingRandomizer& aRandomizer)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iReadLocalOobDataMsg.Handle(),
+			PANIC(KPairingServerFaultCat, EPairingServerNoMessageForObserverCompletion));
+
+	TInt err = aResult;
+	if(err == KErrNone)
+		{
+		TRAP(err, LocalOobDataRetrievedL(aHash, aRandomizer));
+		}
+	if(err == KErrBadDescriptor)
+		{
+		iReadLocalOobDataMsg.Panic(KPairingServerPanicCat, EPairingServerBadDescriptor);
+		}
+	else
+		{
+		iReadLocalOobDataMsg.Complete(err);
+		}
+	}
+
+void COobDataSession::LocalOobDataRetrievedL(const TBluetoothSimplePairingHash& aHash, const TBluetoothSimplePairingRandomizer& aRandomizer)
+	{
+	LOG_FUNC
+	iReadLocalOobDataMsg.WriteL(0, aHash);
+	iReadLocalOobDataMsg.WriteL(1, aRandomizer);
+	}
+
+
+//
+// CDedicatedBondingSession
+//
+
+CDedicatedBondingSession* CDedicatedBondingSession::NewLC(CPairingSession& aSession, CPhysicalLinksManager& aPhysicalLinksManager)
+	{
+	LOG_STATIC_FUNC
+	CDedicatedBondingSession* self = new(ELeave) CDedicatedBondingSession(aSession, aPhysicalLinksManager);
+	//As its a CObject derived class so we should use CleanupClosePushL
+	CleanupClosePushL(*self);
+	self->ConstructL();
+	return self;
+	}
+
+CDedicatedBondingSession::CDedicatedBondingSession(CPairingSession& aSession, CPhysicalLinksManager& aPhysicalLinksManager)
+	: CPairingSubSession(aSession)
+	, iPhysicalLinksManager(aPhysicalLinksManager)
+	{
+	LOG_FUNC
+	}
+
+void CDedicatedBondingSession::ConstructL()
+	{
+	LOG_FUNC
+	CPairingSubSession::ConstructL();
+	TCallBack cb(CDedicatedBondingSession::StaticShutdown, this);
+	iAsyncShutdown = new(ELeave) CAsyncCallBack(cb, CActive::EPriorityStandard);
+	}
+
+CDedicatedBondingSession::~CDedicatedBondingSession()
+	{
+	LOG_FUNC
+	iPhysicalLinksManager.SecMan().CancelRequest(*this);
+	delete iProxySap;
+	if(iStartBondingMsg.Handle())
+		{
+		iStartBondingMsg.Complete(KErrCancel);
+		}
+	delete iAsyncShutdown;
+	}
+
+void CDedicatedBondingSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	switch(aMessage.Function())
+		{
+	case EPairingServerStartDedicatedBond:
+		StartBondingL(aMessage);
+		break;
+	default:
+		CPairingSubSession::DispatchSubSessMessageL(aMessage);
+		break;
+		}
+	}
+
+void CDedicatedBondingSession::Complete(TInt aError)
+	{
+	LOG_FUNC
+	iState = EShutdown;
+	iAsyncShutdown->CallBack();
+	iStartBondingMsg.Complete(aError);
+	}
+
+TInt CDedicatedBondingSession::StaticShutdown(TAny* aDedBond)
+	{
+	LOG_STATIC_FUNC
+	reinterpret_cast<CDedicatedBondingSession*>(aDedBond)->Shutdown();
+	return KErrNone;
+	}
+
+void CDedicatedBondingSession::Shutdown()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iState == EShutdown, PANIC(KPairingServerFaultCat, EPairingServerBadShutdownState));
+	iState = EInvalid;
+	iProxySap->Shutdown(CServProviderBase::ENormal);
+	}
+
+void CDedicatedBondingSession::StartBondingL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	if(!iStartBondingMsg.IsNull() || iState != EInvalid)
+		{
+		aMessage.Panic(KPairingServerPanicCat, EPairingServerDedicatedBondAlreadyInProgress);
+		return;
+		}
+
+	TPckgBuf<TBTDevAddr> addrBuf;
+	TInt addrLen = aMessage.GetDesLengthL(0);
+	if(addrLen != sizeof(TBTDevAddr))
+		{
+		// If the length is correct then the address has been packaged incorrect for the
+		// IPC operation.
+		LEAVEL(KErrBadDescriptor);
+		}
+	aMessage.ReadL(0, addrBuf);
+
+	iStartBondingMsg = aMessage;
+	CleanupStack::PushL(TCleanupItem(CleanupStartMessage, this));
+
+	TBTSockAddr addr;
+	addr.SetBTAddr(addrBuf());
+	iProxySap = CBTProxySAP::NewL(iPhysicalLinksManager, NULL);
+
+	CleanupStack::Pop(this); // the start message cleaner
+
+	iState = EInitialConnectionPending;
+	iProxySap->SetNotify(this);
+	iProxySap->SetRemName(addr);
+	iProxySap->ActiveOpen();
+	}
+
+void CDedicatedBondingSession::CleanupStartMessage(TAny* aPtr)
+	{
+	LOG_STATIC_FUNC
+	CDedicatedBondingSession* session = reinterpret_cast<CDedicatedBondingSession*>(aPtr);
+	session->iStartBondingMsg = RMessage2(); // blat the old one
+	}
+
+void CDedicatedBondingSession::DoAccessRequestL()
+	{
+	LOG_FUNC
+	TBTServiceSecurity security;
+	security.SetAuthentication(EMitmDesired);
+	security.SetUid(KBluetoothDedicatedBondingUid);
+
+	iPhysicalLinksManager.SecMan().AccessRequestL(security, NULL, iProxySap->RemoteAddress(), EDedicatedBonding, *this);
+	}
+
+void CDedicatedBondingSession::AccessRequestComplete(TInt aResult)
+	{
+	LOG_FUNC
+	TInt err = aResult;
+	TBool completed = EFalse;
+	TBTSockAddr addr;
+	switch (iState)
+		{
+	case EZombie:
+		// Ready for a retry.
+		if(aResult == EBTSecManAccessDeferred)
+			{
+			iState = EFinalConnectionPending;
+			addr.SetBTAddr(iProxySap->RemoteAddress());
+			iProxySap->SetRemName(addr); // triggers finding a link again.
+			iProxySap->ActiveOpen();
+			break;
+			}
+		// else not deferred so complete now....
+		// fall-through...
+	case EInitialConnection:
+		ASSERT_DEBUG(aResult != EBTSecManAccessDeferred); // Should have been disconnected if we receive
+													// this - I don't expect this to happen.
+		// fall-through...
+	case EFinalConnection:
+		completed = ETrue; // in the final connection any complete is errored.
+		if(aResult == EBTSecManAccessDenied)
+			{
+			err = KErrAccessDenied;
+			}
+		break;
+	default:
+		LOG1(_L("Unexpected Access Request Complete in state %d"), iState);
+		__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedAccessCallback));
+		break;
+		}
+
+	if (completed)
+		{
+		Complete(err);
+		}
+	}
+
+void CDedicatedBondingSession::NewData(TUint /*aCount*/)
+	{
+	LOG_FUNC
+	// We aren't using a raw conduit
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::CanSend()
+	{
+	LOG_FUNC
+	// We aren't using a raw conduit
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::ConnectCompleteL()
+	{
+	LOG_FUNC
+	switch(iState)
+		{
+	case EInitialConnectionPending:
+		iState = EInitialConnection;
+		DoAccessRequestL();
+		break;
+	case EFinalConnectionPending:
+		iState = EFinalConnection;
+		DoAccessRequestL();
+		break;
+	case EInitialConnection:
+	case EFinalConnection:
+		// Apparently multiple connect completes are allowed by CSocket
+		break;
+	default:
+		LOG1(_L("Unexpected Connect Complete in state %d"), iState);
+		__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+		break;
+		}
+	}
+
+void CDedicatedBondingSession::ConnectComplete()
+	{
+	LOG_FUNC
+	TRAPD(err, ConnectCompleteL());
+	if(err != KErrNone)
+		{
+		Error(err);
+		}
+	}
+
+void CDedicatedBondingSession::ConnectComplete(const TDesC8& /*aConnectData*/)
+	{
+	LOG_FUNC
+	ConnectComplete(); // Connection data isn't useful for us.
+	}
+
+void CDedicatedBondingSession::ConnectComplete(CServProviderBase& /*aSSP*/)
+	{
+	LOG_FUNC
+	// ProxySAPs aren't used for passive connections.
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::ConnectComplete(CServProviderBase& /*aSSP*/, const TDesC8& /*aConnectData*/)
+	{
+	LOG_FUNC
+	// ProxySAPs aren't used for passive connections.
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::CanClose(TDelete aDelete)
+	{
+	LOG_FUNC
+	if (aDelete == EDelete)
+		{
+		delete iProxySap; iProxySap = NULL;
+		}
+	}
+
+void CDedicatedBondingSession::CanClose(const TDesC8& /*aDisconnectData*/, TDelete aDelete)
+	{
+	LOG_FUNC
+	CanClose(aDelete);
+	}
+
+void CDedicatedBondingSession::Error(TInt aError, TUint /*anOperationMask*/)
+	{
+	LOG_FUNC
+	Complete(aError);
+	}
+
+void CDedicatedBondingSession::Disconnect()
+	{
+	LOG_FUNC
+	switch (iState)
+		{
+	case EInitialConnection:
+		// enter the zombie state and wait for the access requester to complete.
+		iState = EZombie;
+		break;
+	case EFinalConnection:
+		Error(KErrDisconnected);
+		break;
+	case EShutdown:
+		// Already closing down.
+		break;
+	default:
+		LOG1(_L("Unexpected Disconnect in state %d"), iState);
+		__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+		break;
+		}
+	}
+
+void CDedicatedBondingSession::Disconnect(TDesC8& /*aDisconnectData*/)
+	{
+	LOG_FUNC
+	Disconnect();
+	}
+
+void CDedicatedBondingSession::IoctlComplete(TDesC8* /*aBuf*/)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::NoBearer(const TDesC8& /*aConnectionParams*/)
+	{
+	LOG_FUNC
+	// No idea what this is for and proxy sap never calls it... so as far as I'm concerned it's
+	// unexpected.
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+void CDedicatedBondingSession::Bearer(const TDesC8& /*aConnectionInfo*/)
+	{
+	LOG_FUNC
+	// No idea what this is for and proxy sap never calls it... so as far as I'm concerned it's
+	// unexpected.
+	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
+	}
+
+
+//
+// CSimplePairingResultSession
+//
+
+CSimplePairingResultSession* CSimplePairingResultSession::NewLC(CPairingSession& aSession, CSimplePairingResultList& aResultList)
+	{
+	LOG_STATIC_FUNC
+	CSimplePairingResultSession* self = new(ELeave) CSimplePairingResultSession(aSession, aResultList);
+	//As its a CObject derived class so we should use CleanupClosePushL
+	CleanupClosePushL(*self);
+	self->ConstructL();
+	return self;
+	}
+
+CSimplePairingResultSession::CSimplePairingResultSession(CPairingSession& aSession, CSimplePairingResultList& aResultList)
+	: CPairingSubSession(aSession)
+	, iResultList(aResultList)
+	{
+	LOG_FUNC
+	}
+
+void CSimplePairingResultSession::ConstructL()
+	{
+	LOG_FUNC
+	CPairingSubSession::ConstructL();
+	iResultList.RegisterObserverL(*this);
+	}
+
+CSimplePairingResultSession::~CSimplePairingResultSession()
+	{
+	LOG_FUNC
+	iResultList.ReleaseObserver(*this);
+	if(!iResultMsg.IsNull())
+		{
+		iResultMsg.Complete(KErrCancel);
+		}
+	}
+
+void CSimplePairingResultSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	switch(aMessage.Function())
+		{
+	case EPairingServerSimplePairingResult:
+		SimplePairingResultL(aMessage);
+		break;
+	case EPairingServerCancelSimplePairingResult:
+		CancelSimplePairingResult(aMessage);
+		break;
+	default:
+		CPairingSubSession::DispatchSubSessMessageL(aMessage);
+		break;
+		}
+	}
+
+void CSimplePairingResultSession::SimplePairingResultL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TPckgBuf<TBTDevAddr> addrBuf;
+	if(aMessage.GetDesMaxLengthL(0) != sizeof(TBTDevAddr))
+		{
+		LEAVEL(KErrBadDescriptor);
+		}
+
+	if(!iResultMsg.IsNull())
+		{
+		LEAVEL(KErrInUse);
+		}
+
+	iResultMsg = aMessage;
+	iResultList.ReturnResult();
+	}
+
+void CSimplePairingResultSession::CancelSimplePairingResult(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	if(!iResultMsg.IsNull())
+		{
+		iResultList.CancelReturn();
+		iResultMsg.Complete(KErrCancel);
+		}
+	aMessage.Complete(KErrNone);
+	}
+
+TInt CSimplePairingResultSession::MbsroResult(const TBTDevAddr& aDevAddr, TInt aResult)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iResultMsg.Handle(),
+			PANIC(KPairingServerFaultCat, EPairingServerNoMessageForObserverCompletion));
+
+	TRAPD(err, ReturnResultL(aDevAddr));
+	if(err == KErrBadDescriptor)
+		{
+		iResultMsg.Panic(KPairingServerPanicCat, EPairingServerBadDescriptor);
+		}
+	else if(err != KErrNone)
+		{
+		iResultMsg.Complete(err);
+		}
+	else
+		{
+		iResultMsg.Complete(aResult);
+		}
+	return err;
+	}
+
+void CSimplePairingResultSession::ReturnResultL(const TBTDevAddr& aDevAddr)
+	{
+	LOG_FUNC
+	TPckg<TBTDevAddr> pckg(aDevAddr);
+	iResultMsg.WriteL(0, pckg);
+	}
+
+
+//
+// CAuthenticationResultSession
+//
+
+CAuthenticationResultSession* CAuthenticationResultSession::NewLC(CPairingSession& aSession, CAuthenticationResultList& aResultList)
+	{
+	LOG_STATIC_FUNC
+	CAuthenticationResultSession* self = new(ELeave) CAuthenticationResultSession(aSession, aResultList);
+	//As its a CObject derived class so we should use CleanupClosePushL
+	CleanupClosePushL(*self);
+	self->ConstructL();
+	return self;
+	}
+
+CAuthenticationResultSession::CAuthenticationResultSession(CPairingSession& aSession, CAuthenticationResultList& aResultList)
+	: CPairingSubSession(aSession)
+	, iResultList(aResultList)
+	{
+	LOG_FUNC
+	}
+
+void CAuthenticationResultSession::ConstructL()
+	{
+	LOG_FUNC
+	CPairingSubSession::ConstructL();
+	iResultList.RegisterObserverL(*this);
+	}
+
+CAuthenticationResultSession::~CAuthenticationResultSession()
+	{
+	LOG_FUNC
+	iResultList.ReleaseObserver(*this);
+	if(!iResultMsg.IsNull())
+		{
+		iResultMsg.Complete(KErrCancel);
+		}
+	}
+
+void CAuthenticationResultSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	switch(aMessage.Function())
+		{
+	case EPairingServerAuthenticationResult:
+		AuthenticationResultL(aMessage);
+		break;
+	case EPairingServerCancelAuthenticationResult:
+		CancelAuthenticationResult(aMessage);
+		break;
+	default:
+		CPairingSubSession::DispatchSubSessMessageL(aMessage);
+		break;
+		}
+	}
+
+void CAuthenticationResultSession::AuthenticationResultL(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+
+	TPckgBuf<TBTDevAddr> addrBuf;
+	if(aMessage.GetDesMaxLengthL(0) != sizeof(TBTDevAddr))
+		{
+		LEAVEL(KErrBadDescriptor);
+		}
+
+	if(!iResultMsg.IsNull())
+		{
+		LEAVEL(KErrInUse);
+		}
+
+	iResultMsg = aMessage;
+	iResultList.ReturnResult();
+	}
+
+void CAuthenticationResultSession::CancelAuthenticationResult(const RMessage2& aMessage)
+	{
+	LOG_FUNC
+	if(!iResultMsg.IsNull())
+		{
+		iResultList.CancelReturn();
+		iResultMsg.Complete(KErrCancel);
+		}
+	aMessage.Complete(KErrNone);
+	}
+
+TInt CAuthenticationResultSession::MbsroResult(const TBTDevAddr& aDevAddr, TInt aResult)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iResultMsg.Handle(),
+			PANIC(KPairingServerFaultCat, EPairingServerNoMessageForObserverCompletion));
+
+	TRAPD(err, ReturnResultL(aDevAddr));
+	if(err == KErrBadDescriptor)
+		{
+		iResultMsg.Panic(KPairingServerPanicCat, EPairingServerBadDescriptor);
+		}
+	else if(err != KErrNone)
+		{
+		iResultMsg.Complete(err);
+		}
+	else
+		{
+		iResultMsg.Complete(aResult);
+		}
+	return err;
+	}
+
+void CAuthenticationResultSession::ReturnResultL(const TBTDevAddr& aDevAddr)
+	{
+	LOG_FUNC
+	TPckg<TBTDevAddr> pckg(aDevAddr);
+	iResultMsg.WriteL(0, pckg);
+	}
+
+