// 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:
//
#include <bluetooth/logger.h>
#include "secman.h"
#include "linkutil.h"
#include <bluetooth/hcicommandqueue.h>
#include <bluetooth/hci/event.h>
#include <bluetooth/hci/writesimplepairingmodecommand.h>
#include <bluetooth/hci/writesimplepairingdebugmodecommand.h>
#include <bluetooth/hci/iocapabilityrequestreplycommand.h>
#include <bluetooth/hci/iocapabilityrequestnegativereplycommand.h>
#include <bluetooth/hci/iocapabilityrequestnegativereplycommand.h>
#include <bluetooth/hci/userconfirmationrequestreplycommand.h>
#include <bluetooth/hci/userconfirmationrequestnegativereplycommand.h>
#include <bluetooth/hci/remoteoobdatarequestreplycommand.h>
#include <bluetooth/hci/remoteoobdatarequestnegativereplycommand.h>
#include <bluetooth/hci/readlocaloobdatacommand.h>
#include <bluetooth/hci/commandcompleteevent.h>
#include <bluetooth/hci/commandstatusevent.h>
#include <bluetooth/hci/iocapabilityrequestevent.h>
#include <bluetooth/hci/iocapabilityresponseevent.h>
#include <bluetooth/hci/userconfirmationrequestevent.h>
#include <bluetooth/hci/userpasskeynotificationevent.h>
#include <bluetooth/hci/remoteoobdatarequestevent.h>
#include <bluetooth/hci/simplepairingcompleteevent.h>
#include <bluetooth/hci/keypressnotificationevent.h>
#include <bluetooth/hci/remotehostsupportedfeaturesnotificationevent.h>
#include <bluetooth/hci/writesimplepairingdebugmodecompleteevent.h>
#include <bluetooth/hci/readlocaloobdatacompleteevent.h>
#include <bluetooth/hci/remoteoobdatarequestreplycompleteevent.h>
#include <bluetooth/hci/remoteoobdatarequestnegativereplycompleteevent.h>
#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_SECMAN);
#endif
// ------------------------------------------------------------------------
// class CSecManCommandController
// ------------------------------------------------------------------------
CSecManCommandController::CSecManCommandController(CBTSecMan& aSecMan)
: iSecMan(aSecMan)
{
LOG_FUNC
}
CSecManCommandController* CSecManCommandController::NewL(CBTSecMan& aSecMan)
{
LOG_STATIC_FUNC
CSecManCommandController* self = CSecManCommandController::NewLC(aSecMan);
CleanupStack::Pop(self);
return self;
}
CSecManCommandController* CSecManCommandController::NewLC(CBTSecMan& aSecMan)
{
LOG_STATIC_FUNC
CSecManCommandController* self = new(ELeave) CSecManCommandController(aSecMan);
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
void CSecManCommandController::ConstructL()
{
LOG_FUNC
}
CSecManCommandController::~CSecManCommandController()
{
LOG_FUNC
ClearHCICommandQueue();
}
void CSecManCommandController::SetHCICommandQueue(MHCICommandQueue& aCommandQueue)
{
LOG_FUNC
__ASSERT_DEBUG(!iCommandQueue, PANIC(KBTSecPanic, EBTSecCommandQueueAlreadyProvided));
iCommandQueue = &aCommandQueue;
}
void CSecManCommandController::ClearHCICommandQueue()
{
LOG_FUNC
if(iCommandQueue)
{
iCommandQueue->MhcqRemoveAllCommands(*this);
}
iCommandQueue = NULL;
}
MHCICommandQueue& CSecManCommandController::CommandQueue() const
{
LOG_FUNC
__ASSERT_DEBUG(iCommandQueue, PANIC(KBTSecPanic, EBTSecCommandQueueNotAvailable));
return *iCommandQueue;
}
void CSecManCommandController::WriteSimplePairingModeL(TUint8 aSimplePairingMode)
{
LOG_FUNC
// Ownership of cmd transfered
CWriteSimplePairingModeCommand* cmd = CWriteSimplePairingModeCommand::NewL(aSimplePairingMode);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::WriteSimplePairingDebugModeL(TUint8 aSimplePairingDebugMode)
{
LOG_FUNC
// Ownership of cmd transfered
CWriteSimplePairingDebugModeCommand* cmd = CWriteSimplePairingDebugModeCommand::NewL(aSimplePairingDebugMode);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::IOCapabilityRequestReplyL(const TBTDevAddr& aBDADDR,
THCIIoCapability aIOCapability,
THCIOobDataPresence aOOBDataPresent,
THCIAuthenticationRequirement aAuthenticationRequirements)
{
LOG_FUNC
// Ownership of cmd transfered
CIOCapabilityRequestReplyCommand* cmd = CIOCapabilityRequestReplyCommand::NewL(aBDADDR, aIOCapability, aOOBDataPresent, aAuthenticationRequirements);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::IOCapabilityRequestNegativeReplyL(const TBTDevAddr& aBDADDR, TUint8 aReason)
{
// Ownership of cmd transfered
CIOCapabilityRequestNegativeReplyCommand* cmd = CIOCapabilityRequestNegativeReplyCommand::NewL(aBDADDR, aReason);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::UserConfirmationRequestReplyL(const TBTDevAddr& aBDADDR)
{
LOG_FUNC
// Ownership of cmd transfered
CUserConfirmationRequestReplyCommand* cmd = CUserConfirmationRequestReplyCommand::NewL(aBDADDR);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::UserConfirmationRequestNegativeReplyL(const TBTDevAddr& aBDADDR)
{
LOG_FUNC
// Ownership of cmd transfered
CUserConfirmationRequestNegativeReplyCommand* cmd = CUserConfirmationRequestNegativeReplyCommand::NewL(aBDADDR);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::RemoteOOBDataRequestReplyL(const TBTDevAddr& aBDADDR,
const TBluetoothSimplePairingHash& aC,
const TBluetoothSimplePairingRandomizer& aR)
{
LOG_FUNC
// Ownership of cmd transfered
CRemoteOOBDataRequestReplyCommand* cmd = CRemoteOOBDataRequestReplyCommand::NewL(aBDADDR, aC, aR);
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::RemoteOOBDataRequestNegativeReplyL(const TBTDevAddr& aBDADDR)
{
LOG_FUNC
CRemoteOOBDataRequestNegativeReplyCommand* cmd = CRemoteOOBDataRequestNegativeReplyCommand::NewL(aBDADDR);
// Ownership of cmd transfered
CommandQueue().MhcqAddCommandL(cmd, *this);
}
void CSecManCommandController::MhcqcCommandErrored(TInt IF_FLOGGING(aErrorCode), const CHCICommandBase* __DEBUG_ONLY(aCommand))
{
LOG_FUNC
__ASSERT_DEBUG(aCommand, PANIC(KBTSecPanic, EBTSecNoCommandAssociatedWithErrorEvent)); // this should never happen
#ifdef _DEBUG
LOG2(_L("error code:%d opcode:0x%04x"), aErrorCode, aCommand->Opcode());
#else
LOG1(_L("error code:%d"), aErrorCode);
#endif
}
// -----------------------------------------------------------------------------------------
// From MHCICommandQueueClient
void CSecManCommandController::MhcqcCommandEventReceived(const THCIEventBase& aEvent, const CHCICommandBase* /*aRelatedCommand*/)
{
LOG_FUNC
switch(aEvent.EventCode())
{
case ECommandCompleteEvent:
{
CommandCompleteEvent(aEvent);
break;
}
case ECommandStatusEvent:
CommandStatusEvent(aEvent);
break;
case EIOCapabilityRequestEvent:
IOCapabilityRequestEvent(aEvent);
break;
case EIOCapabilityResponseEvent:
IOCapabilityResponseEvent(aEvent);
break;
case EUserConfirmationRequestEvent:
UserConfirmationRequestEvent(aEvent);
break;
case EUserPasskeyRequestEvent:
// Symbian devices are assumed to be DisplayYesNo statically.
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecBadUserPasskeyRequest));
break;
case EUserPasskeyNotificationEvent:
UserPasskeyNotificationEvent(aEvent);
break;
case ERemoteOOBDataRequestEvent:
RemoteOOBDataRequestEvent(aEvent);
break;
case EKeypressNotificationEvent:
KeypressNotificationEvent(aEvent);
break;
case ESimplePairingCompleteEvent:
SimplePairingCompleteEvent(aEvent);
break;
default:
LOG1(_L("Warning!! Unknown Command Event Received (event code: %d)"), aEvent.EventCode());
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecUnknownHCIEvent));
break;
}
}
void CSecManCommandController::IOCapabilityRequestEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TIOCapabilityRequestEvent& event = TIOCapabilityRequestEvent::Cast(aEvent);
iSecMan.IOCapabilityRequestFromRemote(event.BDADDR());
}
void CSecManCommandController::IOCapabilityResponseEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TIOCapabilityResponseEvent& event = TIOCapabilityResponseEvent::Cast(aEvent);
iSecMan.IOCapabilityAskForResponse(event.BDADDR(), CastToIoCapability(event.IOCapability()), CastToOobDataPresence(event.OOBDataPresent()), CastToAuthenticationRequirements(event.AuthenticationRequirements()));
}
void CSecManCommandController::UserConfirmationRequestEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TUserConfirmationRequestEvent& event = TUserConfirmationRequestEvent::Cast(aEvent);
iSecMan.UserConfirmationRequest(event.BDADDR(), event.NumericValue());
}
void CSecManCommandController::UserPasskeyNotificationEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TUserPasskeyNotificationEvent& event = TUserPasskeyNotificationEvent::Cast(aEvent);
iSecMan.PasskeyNotification(event.BDADDR(), event.Passkey());
}
void CSecManCommandController::RemoteOOBDataRequestEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TRemoteOOBDataRequestEvent& event = TRemoteOOBDataRequestEvent::Cast(aEvent);
iSecMan.RemoteOOBDataRequest(event.BDADDR());
}
void CSecManCommandController::SimplePairingCompleteEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TSimplePairingCompleteEvent& spevent = TSimplePairingCompleteEvent::Cast(aEvent);
iSecMan.SimplePairingComplete(spevent.BDADDR(), aEvent.ErrorCode());
}
void CSecManCommandController::KeypressNotificationEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TKeypressNotificationEvent& event = TKeypressNotificationEvent::Cast(aEvent);
iSecMan.KeypressNotification(event.BDADDR(), event.NotificationType());
}
void CSecManCommandController::CommandCompleteEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent);
THCIOpcode opcode = completeEvent.CommandOpcode();
THCIErrorCode hciErr = aEvent.ErrorCode();
switch (opcode)
{
case KWriteSimplePairingModeOpcode:
WriteSimplePairingModeOpcode(completeEvent);
break;
case KRemoteOOBDataRequestReplyOpcode:
RemoteOOBDataRequestReplyOpcode(completeEvent);
break;
case KRemoteOOBDataRequestNegativeReplyOpcode:
RemoteOOBDataRequestNegativeReplyOpcode(completeEvent);
break;
case KIOCapabilityRequestReplyOpcode:
// Check bdaddr
break;
case KWriteSimplePairingDebugModeOpcode:
WriteSimplePairingDebugModeOpcode(completeEvent);
break;
// Need to handle link key request reply...
// Need to complete link key request negative reply
// Pin code request reply
case KIOCapabilityRequestNegativeReplyOpcode:
case KUserConfirmationRequestReplyOpcode:
// check bdaddr.
case KUserConfirmationRequestNegativeReplyOpcode:
// check bdadrr
case KUserPasskeyRequestReplyOpcode:
case KUserPasskeyRequestNegativeReplyOpcode:
// Catch all the events we do not handle
LOG1(_L("Warning!! Unhandled Command Complete Event (opcode: %d)"), opcode);
break;
default:
LOG2(_L("Link [HCIFacade_Events.cpp]: Warning: Unknown Command complete event! Opcode %d error code %d"), opcode, hciErr);
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecUnknownHCICommandCompleteOpcode));
break;
}
}
void CSecManCommandController::CommandStatusEvent(const THCIEventBase& aEvent)
{
LOG_FUNC
const TCommandStatusEvent& commandStatusEvent = TCommandStatusEvent::Cast(aEvent);
THCIOpcode opcode = commandStatusEvent.CommandOpcode();
THCIErrorCode hciErr = commandStatusEvent.ErrorCode();
}
void CSecManCommandController::WriteSimplePairingModeOpcode(const THCICommandCompleteEvent& aCompleteEvent)
{
LOG_FUNC
if(aCompleteEvent.ErrorCode() == EOK)
{
iSecMan.SetLocalSimplePairingMode(ETrue);
}
// if we got an error then we make the reasonable assumption that the local controller is not
// capable of secure simple pairing.
}
void CSecManCommandController::RemoteOOBDataRequestReplyOpcode(const THCICommandCompleteEvent& aCompleteEvent)
{
LOG_FUNC
const TRemoteOOBDataRequestReplyCompleteEvent& event = TRemoteOOBDataRequestReplyCompleteEvent::Cast(aCompleteEvent);
iSecMan.RemoteOOBDataRequestComplete(event.BDADDR());
}
void CSecManCommandController::RemoteOOBDataRequestNegativeReplyOpcode(const THCICommandCompleteEvent& aCompleteEvent)
{
LOG_FUNC
const TRemoteOOBDataRequestNegativeReplyCompleteEvent& event = TRemoteOOBDataRequestNegativeReplyCompleteEvent::Cast(aCompleteEvent);
iSecMan.RemoteOOBDataRequestComplete(event.BDADDR());
}
void CSecManCommandController::WriteSimplePairingDebugModeOpcode(const THCICommandCompleteEvent& aCompleteEvent)
{
LOG_FUNC
const TWriteSimplePairingDebugModeCompleteEvent& event = TWriteSimplePairingDebugModeCompleteEvent::Cast(aCompleteEvent);
if(event.ErrorCode() == EOK)
{
iSecMan.DebugModeChanged(ETrue);
}
// ignore errors - debug mode remains the same
}
THCIIoCapability CSecManCommandController::CastToIoCapability(TUint8 aIOCapability)
{
LOG_STATIC_FUNC
switch(aIOCapability)
{
case EIOCapsDisplayOnly:
case EIOCapsDisplayYesNo:
case EIOCapsKeyboardOnly:
case EIOCapsNoInputNoOutput:
// All valid understood values.
break;
default:
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecUnexpectedIoCapability));
break;
}
return static_cast<THCIIoCapability>(aIOCapability);
}
THCIOobDataPresence CSecManCommandController::CastToOobDataPresence(TUint8 aOOBDataPresent)
{
LOG_STATIC_FUNC
switch(aOOBDataPresent)
{
case EOOBDataNotPresent:
case EOOBDataPresent:
// All valid understood values.
break;
default:
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecUnexpectedOobDataPresence));
break;
}
return static_cast<THCIOobDataPresence>(aOOBDataPresent);
}
THCIAuthenticationRequirement CSecManCommandController::CastToAuthenticationRequirements(TUint8 aAuthenticationRequirements)
{
LOG_STATIC_FUNC
switch(aAuthenticationRequirements)
{
case EMitmNotReqNoBonding:
case EMitmReqNoBonding:
case EMitmNotReqDedicatedBonding:
case EMitmReqDedicatedBonding:
case EMitmNotReqGeneralBonding:
case EMitmReqGeneralBonding:
// All valid understood values.
break;
default:
__ASSERT_DEBUG(EFalse, PANIC(KBTSecPanic, EBTSecUnexpectedAuthenticationRequirements));
break;
}
return static_cast<THCIAuthenticationRequirement>(aAuthenticationRequirements);
}