// Copyright (c) 2008-2010 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; // cannot do an immediate shutdown as the semantics for that kill the phy
if(!iStartBondingMsg.IsNull())
{
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
if(!iStartBondingMsg.IsNull())
{
__ASSERT_DEBUG(!ShuttingDown(), PANIC(KPairingServerFaultCat, EPairingServerBadShutdownState));
iState = EShutdownRequested;
iAsyncShutdown->CallBack();
iPhysicalLinksManager.SecMan().CancelRequest(*this); // we don't want the result anymore (if it's still pending).
iStartBondingMsg.Complete(aError);
}
else
{
__ASSERT_DEBUG(ShuttingDown(), PANIC(KPairingServerFaultCat, EPairingServerBadShutdownState));
}
}
TInt CDedicatedBondingSession::StaticShutdown(TAny* aDedBond)
{
LOG_STATIC_FUNC
reinterpret_cast<CDedicatedBondingSession*>(aDedBond)->Shutdown();
return KErrNone;
}
void CDedicatedBondingSession::Shutdown()
{
LOG_FUNC
__ASSERT_DEBUG(iState == EShutdownRequested, PANIC(KPairingServerFaultCat, EPairingServerBadShutdownState));
__ASSERT_DEBUG(iStartBondingMsg.IsNull(), PANIC(KPairingServerFaultCat, EPairingServerMessageShouldBeNull));
iState = EShutdownPending;
iProxySap->Shutdown(CServProviderBase::ENormal);
}
TBool CDedicatedBondingSession::ShuttingDown() const
{
return iState == EShutdownRequested || iState == EShutdownPending;
}
void CDedicatedBondingSession::StartBondingL(const RMessage2& aMessage)
{
LOG_FUNC
if(iState != EMintCondition)
{
aMessage.Panic(KPairingServerPanicCat, EPairingServerDedicatedBondAlreadyInProgress);
return;
}
__ASSERT_DEBUG(iStartBondingMsg.IsNull(), PANIC(KPairingServerFaultCat, EPairingServerMessageShouldBeNull));
// Now we've been initiated, no turning back for this object.
iState = EInitiated;
TPckgBuf<TBTDevAddr> addrBuf;
TInt addrLen = aMessage.GetDesLengthL(0);
if(addrLen != sizeof(TBTDevAddr))
{
// If the length is incorrect then the address has been packaged incorrectly for the
// IPC operation.
LEAVEL(KErrBadDescriptor);
}
aMessage.ReadL(0, addrBuf);
TBTSockAddr addr;
addr.SetBTAddr(addrBuf());
__ASSERT_DEBUG(!iProxySap, PANIC(KPairingServerFaultCat, EPairingServerObjectAlreadyExists));
iProxySap = CBTProxySAP::NewL(iPhysicalLinksManager, NULL);
iStartBondingMsg = aMessage;
// Now we've entered the realm of not leaving with an error, since the connection
// process has started. Errors from now on must be via the Error() function call.
iState = EInitialConnectionPending;
iProxySap->SetNotify(this);
iProxySap->SetRemName(addr);
iProxySap->ActiveOpen();
TRAPD(err, DoAccessRequestL());
if(err != KErrNone)
{
Error(err);
}
}
void CDedicatedBondingSession::DoAccessRequestL()
{
LOG_FUNC
TBTServiceSecurity security;
security.SetAuthentication(EMitmDesired);
security.SetUid(KBluetoothDedicatedBondingUid);
iPhysicalLinksManager.SecMan().AccessRequestL(security, NULL, iProxySap->RemoteAddress(), EDedicatedBonding, EFalse, *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();
TRAPD(err, DoAccessRequestL());
if(err != KErrNone)
{
Error(err);
}
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;
case EInitialConnectionPending:
// fall-through deliberate
case EFinalConnectionPending:
// Access request shouldn't successfully complete if the connection is still pending
__ASSERT_DEBUG(aResult != EBTSecManAccessGranted, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedAccessCallback));
// We should get the MSocketNotify::Error callback, so don't do anything else
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::ConnectComplete()
{
LOG_FUNC
switch(iState)
{
case EInitialConnectionPending:
iState = EInitialConnection;
break;
case EFinalConnectionPending:
iState = EFinalConnection;
break;
case EInitialConnection:
// fall-through deliberate
case EFinalConnection:
// Apparently multiple connect completes are allowed by CSocket
break;
case EShutdownRequested:
// fall-through deliberate
case EShutdownPending:
// If an error occurred just after the connection request then we
// might receive a connection complete before the async shutdown request
// has been executed or completed.
break;
default:
LOG1(_L("Unexpected Connect Complete in state %d"), iState);
__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
break;
}
}
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
__ASSERT_DEBUG(iState == EShutdownPending, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
__ASSERT_DEBUG(iStartBondingMsg.IsNull(), PANIC(KPairingServerFaultCat, EPairingServerMessageShouldBeNull));
iState = EShutdown;
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 EShutdownRequested:
// fall-through deliberate
case EShutdownPending:
// 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);
}