diff -r df7a93ede42e -r a0ea99b6fa53 bluetoothengine/btnotif/btnotifsrv/src/btnotifoutgoingpairinghandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifoutgoingpairinghandler.cpp Mon May 17 11:06:23 2010 +0300 @@ -0,0 +1,381 @@ +/* +* Copyright (c) 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: Pairing handler for local device initiated pairing +* +*/ + +#include "btnotifoutgoingpairinghandler.h" +#include +#include +#include "btnotifpairingmanager.h" + +/** Length of the default PIN. */ +const TInt KDefaultHeadsetPinLength = 4; + +enum TPairingStageId + { + /** + * no pairing operation ongoing + */ + ENoBonding = 0, + + /** + * pair with dedicated bonding method + */ + EDedicatedBonding = 200, + + /** + * pair with general bonding by establishing L2CAP connection. + */ + EGeneralBonding, + + /** + * delaying next pairing request for a while + */ + EGeneralBondingRetryTimer, + + /** + * The last pairing retry + */ + EGeneralBondingRetry, + + /** + * disconnecting physical link after pairing operation. + * + * todo: not used yet. + */ + EDisconnectLinkAfterBonding, + }; + +/** SDP PSM (used for pairing) */ +const TInt KSDPPSM = 0x0001; + +// Delay time to void Repeated Attempts on pairing +const TInt KGeneralBondingRetryDelayMicroSeconds = 5000000; // 5.0s + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// C++ default constructor +// --------------------------------------------------------------------------- +// +CBTNotifOutgoingPairingHandler::CBTNotifOutgoingPairingHandler( CBTNotifPairingManager& aParent, const TBTDevAddr& aAddr) + : CBTNotifBasePairingHandler( aParent, aAddr ) + { + } + +// --------------------------------------------------------------------------- +// Symbian 2nd-phase constructor +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::ConstructL() + { + BaseConstructL(); + User::LeaveIfError( iTimer.CreateLocal() ); + } + +// --------------------------------------------------------------------------- +// NewL +// --------------------------------------------------------------------------- +// +CBTNotifBasePairingHandler* CBTNotifOutgoingPairingHandler::NewL( CBTNotifPairingManager& aParent, + const TBTDevAddr& aAddr ) + { + CBTNotifOutgoingPairingHandler* self = new( ELeave ) CBTNotifOutgoingPairingHandler( aParent, aAddr ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CBTNotifOutgoingPairingHandler::~CBTNotifOutgoingPairingHandler() + { + if ( iActive ) + { + iActive->Cancel(); + } + iBondingSession.Close(); + iSocket.Close(); + iTimer.Close(); + } + +// --------------------------------------------------------------------------- +// Simply deny the request as this is handing outgoing pairing +// --------------------------------------------------------------------------- +// +TInt CBTNotifOutgoingPairingHandler::ObserveIncomingPair( const TBTDevAddr& /*aAddr*/ ) + { + return KErrServerBusy; + } + +// --------------------------------------------------------------------------- +// Accept the request only this device is not busy with another pairing request. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::HandleOutgoingPairL( const TBTDevAddr& aAddr, TUint aCod ) + { + // TRACE_FUNC_ARG( ( _L(" cod 0x%08x"), aCod ) ) + if ( iActive->IsActive() || aAddr != iAddr ) + { + // we don't allow another pairing request. + User::Leave( KErrServerBusy ); + } + + iAddr = aAddr; + iCod = TBTDeviceClass( aCod ); + UnSetPairResult(); + iParent.UnpairDevice( iAddr ); + if ( CBtDevExtension::IsHeadset( iCod ) ) + { + // If the devie is a headset, set to 0000 pin auto pairing + iPairMode = EBTOutgoingHeadsetAutoPairing; + } + else + { + iPairMode = EBTOutgoingNoneHeadsetPairing; + } + // SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode ); + DoPairingL(); + } + +// --------------------------------------------------------------------------- +// Cancels an outstanding pair request by self-destruct +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::CancelOutgoingPair() + { + iParent.RenewPairingHandler( NULL ); + } + + +// --------------------------------------------------------------------------- +// when phone initiated a pairing request towards a headset, +// Pin code 0000 is first tried. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::GetPinCode( + TBTPinCode& aPin, const TBTDevAddr& aAddr, TInt aMinPinLength ) + { + aPin().iLength = 0; + if ( aMinPinLength <= KDefaultHeadsetPinLength + && aAddr == iAddr + && iPairMode == EBTOutgoingHeadsetAutoPairing) + { + // if the pairing requires a stronger security level (indicated + // by aMinPinLength), + // 0000 will not be supplied as it does not mmet the security + // requirements + const TUint8 KZeroPinValue = '0'; + for (TInt i = 0; i < KDefaultHeadsetPinLength; ++i) + { + aPin().iPIN[i] = KZeroPinValue; + } + aPin().iLength = KDefaultHeadsetPinLength; + } + } + +// --------------------------------------------------------------------------- +// Abort pairing handling, request the owner to destroy this. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::StopPairHandling( const TBTDevAddr& aAddr ) + { + if ( aAddr == iAddr ) + { + iParent.OutgoingPairCompleted( KErrCancel ); + iParent.RenewPairingHandler( NULL ); + } + } + +// --------------------------------------------------------------------------- +// Pairing result will be received when pairing operation completes. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::DoHandlePairServerResult( TInt aResult ) + { + if (aResult == (KHCIErrorBase-EPairingNotAllowed)) + { + // if EPairingNotAllowed is recieved then any further pairing attempts will fail + // so don't attampt to pair + iPairMode = EBTOutgoingPairNone; + } + } + +// --------------------------------------------------------------------------- +// Cancels possible outstanding pairing and notify user pair success. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::DoHandleRegistryNewPairedEvent( + const TBTNamelessDevice& aDev ) + { + TInt err( KErrNone ); + // If pairing was performed using Just Works mode, we set a + // UICookie to indicate that the device is successfully + // bonded so that this device will be listed in paired device view of + // bluetooth application: + if ( aDev.LinkKeyType() == ELinkKeyUnauthenticatedNonUpgradable ) + { + // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair, Just Works pairing" ) ) ); + err = iParent.AddUiCookieJustWorksPaired( aDev ); + } + iActive->Cancel(); + SetPairResult( err ? err : KErrNone ); + iParent.OutgoingPairCompleted( err ); + iParent.RenewPairingHandler( NULL ); + } + +// --------------------------------------------------------------------------- +// From class MBTNotifPairingAOObserver. +// Based on the result code, decides the next operation, either try pairing +// with another mode, or complete pair request. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::RequestCompletedL( + CBtSimpleActive* aActive, TInt aStatus ) + { + // TRACE_FUNC_ARG( ( _L( "reqid %d, status: %d, pair mode %d " ), aId, aStatus, iPairMode ) ) + if( aActive->RequestId() == EDedicatedBonding && + ( aStatus == KErrRemoteDeviceIndicatedNoBonding || + ( aStatus && iPairMode != EBTOutgoingNoneHeadsetPairing && iPairMode != EBTOutgoingPairNone ) ) ) + { + // try general pairing if the remote doesn't have dedicated bonding, or + // pairing fails with a headset. + DoPairingL(); + } + else if ( aStatus && iPairMode == EBTOutgoingHeadsetAutoPairing ) + { + iPairMode = EBTOutgoingHeadsetManualPairing; + // auto pairing with headset failed, try to pair again with manual pin: + // ( void ) SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode ); + // TRACE_INFO( _L( " auto pairing failed, switch to manual pairing") ); + DoPairingL(); + } + else if ( aStatus && aActive->RequestId() == EGeneralBonding && + iPairMode == EBTOutgoingHeadsetManualPairing ) + { + // pairing headset with manual pin failed, wait for a while and try again: + iActive->SetRequestId( EGeneralBondingRetryTimer ); + iTimer.After( iActive->iStatus, KGeneralBondingRetryDelayMicroSeconds ); + iActive->GoActive(); + } + else if( aActive->RequestId() == EGeneralBondingRetryTimer ) + { + // try to pair headset again with manual pin again: + DoPairingL(); + } + else if ( aStatus ) + { + // we only starts showing note if pairing failed. + // For a successful pair, we must wait until registry has been updated. + if ( !IsPairResultSet() ) + { + SetPairResult( aStatus ); + } + if ( aStatus ) + { + // todo: show error note? + iParent.OutgoingPairCompleted( aStatus ); + } + } + } + +// --------------------------------------------------------------------------- +// From class MBTEngActiveObserver. +// cancels an outstanding request according to the given id. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::CancelRequest( TInt aRequestId ) + { + switch ( aRequestId ) + { + case EDedicatedBonding: + { + iBondingSession.Close(); + } + case EGeneralBonding: + case EGeneralBondingRetry: + { + iSocket.CancelConnect(); + iSocket.Close(); + } + case EGeneralBondingRetryTimer: + { + iTimer.Cancel(); + } + } + } + +// --------------------------------------------------------------------------- +// From class MBTEngActiveObserver. +// Handles a leave in RequestCompleted by self-destructing. +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::HandleError( + CBtSimpleActive* aActive, TInt aError ) + { + // TRACE_FUNC_ARG( ( _L( "error: %d" ), aError ) ) + // Our RunL can actually not leave, so we should never reach here. + (void) aActive; + iParent.OutgoingPairCompleted( aError ); + iParent.RenewPairingHandler( NULL ); + } + +// --------------------------------------------------------------------------- +// decide the next state and issue pair request +// --------------------------------------------------------------------------- +// +void CBTNotifOutgoingPairingHandler::DoPairingL() + { + // TRACE_FUNC_ENTRY + TPairingStageId currentMode = ( TPairingStageId ) iActive->RequestId(); + ASSERT( !iActive->IsActive() ); + TPairingStageId nextMode( EGeneralBonding ); + + // if running BTv2.0 stack, dedicated bonding method + // is not available. + if ( currentMode == ENoBonding && iParent.PairingServer() != NULL ) + { + nextMode = EDedicatedBonding; + } + else if(currentMode == EGeneralBondingRetryTimer) + { + nextMode = EGeneralBondingRetry; + } + + // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair::DoPairingL: bonding mode: pre %d, next %d"), currentMode, nextMode ) ); + + iActive->SetRequestId( nextMode ); + if ( nextMode == EDedicatedBonding ) + { + iBondingSession.Start( *iParent.PairingServer(), iAddr, iActive->RequestStatus() ); + } + else + { + TBTServiceSecurity sec; + sec.SetAuthentication( ETrue ); + iSockAddr.SetBTAddr( iAddr ); + iSockAddr.SetPort(KSDPPSM); + iSockAddr.SetSecurity( sec ); + iSocket.Close(); + User::LeaveIfError( iSocket.Open( iParent.SocketServ(), KL2CAPDesC ) ); + iSocket.Connect( iSockAddr, iActive->RequestStatus() ); + } + iActive->GoActive(); + // TRACE_FUNC_EXIT + } +