|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Pairing handler for local device initiated pairing |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "btnotifoutgoingpairinghandler.h" |
|
19 #include <btengconstants.h> |
|
20 #include <btservices/btdevextension.h> |
|
21 #include "btnotifpairingmanager.h" |
|
22 |
|
23 /** Length of the default PIN. */ |
|
24 const TInt KDefaultHeadsetPinLength = 4; |
|
25 |
|
26 enum TPairingStageId |
|
27 { |
|
28 /** |
|
29 * no pairing operation ongoing |
|
30 */ |
|
31 ENoBonding = 0, |
|
32 |
|
33 /** |
|
34 * pair with dedicated bonding method |
|
35 */ |
|
36 EDedicatedBonding = 200, |
|
37 |
|
38 /** |
|
39 * pair with general bonding by establishing L2CAP connection. |
|
40 */ |
|
41 EGeneralBonding, |
|
42 |
|
43 /** |
|
44 * delaying next pairing request for a while |
|
45 */ |
|
46 EGeneralBondingRetryTimer, |
|
47 |
|
48 /** |
|
49 * The last pairing retry |
|
50 */ |
|
51 EGeneralBondingRetry, |
|
52 |
|
53 /** |
|
54 * disconnecting physical link after pairing operation. |
|
55 * |
|
56 * todo: not used yet. |
|
57 */ |
|
58 EDisconnectLinkAfterBonding, |
|
59 }; |
|
60 |
|
61 /** SDP PSM (used for pairing) */ |
|
62 const TInt KSDPPSM = 0x0001; |
|
63 |
|
64 // Delay time to void Repeated Attempts on pairing |
|
65 const TInt KGeneralBondingRetryDelayMicroSeconds = 5000000; // 5.0s |
|
66 |
|
67 // ======== MEMBER FUNCTIONS ======== |
|
68 |
|
69 // --------------------------------------------------------------------------- |
|
70 // C++ default constructor |
|
71 // --------------------------------------------------------------------------- |
|
72 // |
|
73 CBTNotifOutgoingPairingHandler::CBTNotifOutgoingPairingHandler( CBTNotifPairingManager& aParent, const TBTDevAddr& aAddr) |
|
74 : CBTNotifBasePairingHandler( aParent, aAddr ) |
|
75 { |
|
76 } |
|
77 |
|
78 // --------------------------------------------------------------------------- |
|
79 // Symbian 2nd-phase constructor |
|
80 // --------------------------------------------------------------------------- |
|
81 // |
|
82 void CBTNotifOutgoingPairingHandler::ConstructL() |
|
83 { |
|
84 BaseConstructL(); |
|
85 User::LeaveIfError( iTimer.CreateLocal() ); |
|
86 } |
|
87 |
|
88 // --------------------------------------------------------------------------- |
|
89 // NewL |
|
90 // --------------------------------------------------------------------------- |
|
91 // |
|
92 CBTNotifBasePairingHandler* CBTNotifOutgoingPairingHandler::NewL( CBTNotifPairingManager& aParent, |
|
93 const TBTDevAddr& aAddr ) |
|
94 { |
|
95 CBTNotifOutgoingPairingHandler* self = new( ELeave ) CBTNotifOutgoingPairingHandler( aParent, aAddr ); |
|
96 CleanupStack::PushL( self ); |
|
97 self->ConstructL(); |
|
98 CleanupStack::Pop( self ); |
|
99 return self; |
|
100 } |
|
101 |
|
102 // --------------------------------------------------------------------------- |
|
103 // Destructor |
|
104 // --------------------------------------------------------------------------- |
|
105 // |
|
106 CBTNotifOutgoingPairingHandler::~CBTNotifOutgoingPairingHandler() |
|
107 { |
|
108 if ( iActive ) |
|
109 { |
|
110 iActive->Cancel(); |
|
111 } |
|
112 iBondingSession.Close(); |
|
113 iSocket.Close(); |
|
114 iTimer.Close(); |
|
115 } |
|
116 |
|
117 // --------------------------------------------------------------------------- |
|
118 // Simply deny the request as this is handing outgoing pairing |
|
119 // --------------------------------------------------------------------------- |
|
120 // |
|
121 TInt CBTNotifOutgoingPairingHandler::ObserveIncomingPair( const TBTDevAddr& /*aAddr*/ ) |
|
122 { |
|
123 return KErrServerBusy; |
|
124 } |
|
125 |
|
126 // --------------------------------------------------------------------------- |
|
127 // Accept the request only this device is not busy with another pairing request. |
|
128 // --------------------------------------------------------------------------- |
|
129 // |
|
130 void CBTNotifOutgoingPairingHandler::HandleOutgoingPairL( const TBTDevAddr& aAddr, TUint aCod ) |
|
131 { |
|
132 // TRACE_FUNC_ARG( ( _L(" cod 0x%08x"), aCod ) ) |
|
133 if ( iActive->IsActive() || aAddr != iAddr ) |
|
134 { |
|
135 // we don't allow another pairing request. |
|
136 User::Leave( KErrServerBusy ); |
|
137 } |
|
138 |
|
139 iAddr = aAddr; |
|
140 iCod = TBTDeviceClass( aCod ); |
|
141 UnSetPairResult(); |
|
142 iParent.UnpairDevice( iAddr ); |
|
143 if ( CBtDevExtension::IsHeadset( iCod ) ) |
|
144 { |
|
145 // If the devie is a headset, set to 0000 pin auto pairing |
|
146 iPairMode = EBTOutgoingHeadsetAutoPairing; |
|
147 } |
|
148 else |
|
149 { |
|
150 iPairMode = EBTOutgoingNoneHeadsetPairing; |
|
151 } |
|
152 // SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode ); |
|
153 DoPairingL(); |
|
154 } |
|
155 |
|
156 // --------------------------------------------------------------------------- |
|
157 // Cancels an outstanding pair request by self-destruct |
|
158 // --------------------------------------------------------------------------- |
|
159 // |
|
160 void CBTNotifOutgoingPairingHandler::CancelOutgoingPair() |
|
161 { |
|
162 iParent.RenewPairingHandler( NULL ); |
|
163 } |
|
164 |
|
165 |
|
166 // --------------------------------------------------------------------------- |
|
167 // when phone initiated a pairing request towards a headset, |
|
168 // Pin code 0000 is first tried. |
|
169 // --------------------------------------------------------------------------- |
|
170 // |
|
171 void CBTNotifOutgoingPairingHandler::GetPinCode( |
|
172 TBTPinCode& aPin, const TBTDevAddr& aAddr, TInt aMinPinLength ) |
|
173 { |
|
174 aPin().iLength = 0; |
|
175 if ( aMinPinLength <= KDefaultHeadsetPinLength |
|
176 && aAddr == iAddr |
|
177 && iPairMode == EBTOutgoingHeadsetAutoPairing) |
|
178 { |
|
179 // if the pairing requires a stronger security level (indicated |
|
180 // by aMinPinLength), |
|
181 // 0000 will not be supplied as it does not mmet the security |
|
182 // requirements |
|
183 const TUint8 KZeroPinValue = '0'; |
|
184 for (TInt i = 0; i < KDefaultHeadsetPinLength; ++i) |
|
185 { |
|
186 aPin().iPIN[i] = KZeroPinValue; |
|
187 } |
|
188 aPin().iLength = KDefaultHeadsetPinLength; |
|
189 } |
|
190 } |
|
191 |
|
192 // --------------------------------------------------------------------------- |
|
193 // Abort pairing handling, request the owner to destroy this. |
|
194 // --------------------------------------------------------------------------- |
|
195 // |
|
196 void CBTNotifOutgoingPairingHandler::StopPairHandling( const TBTDevAddr& aAddr ) |
|
197 { |
|
198 if ( aAddr == iAddr ) |
|
199 { |
|
200 iParent.OutgoingPairCompleted( KErrCancel ); |
|
201 iParent.RenewPairingHandler( NULL ); |
|
202 } |
|
203 } |
|
204 |
|
205 // --------------------------------------------------------------------------- |
|
206 // Pairing result will be received when pairing operation completes. |
|
207 // --------------------------------------------------------------------------- |
|
208 // |
|
209 void CBTNotifOutgoingPairingHandler::DoHandlePairServerResult( TInt aResult ) |
|
210 { |
|
211 if (aResult == (KHCIErrorBase-EPairingNotAllowed)) |
|
212 { |
|
213 // if EPairingNotAllowed is recieved then any further pairing attempts will fail |
|
214 // so don't attampt to pair |
|
215 iPairMode = EBTOutgoingPairNone; |
|
216 } |
|
217 } |
|
218 |
|
219 // --------------------------------------------------------------------------- |
|
220 // Cancels possible outstanding pairing and notify user pair success. |
|
221 // --------------------------------------------------------------------------- |
|
222 // |
|
223 void CBTNotifOutgoingPairingHandler::DoHandleRegistryNewPairedEvent( |
|
224 const TBTNamelessDevice& aDev ) |
|
225 { |
|
226 TInt err( KErrNone ); |
|
227 // If pairing was performed using Just Works mode, we set a |
|
228 // UICookie to indicate that the device is successfully |
|
229 // bonded so that this device will be listed in paired device view of |
|
230 // bluetooth application: |
|
231 if ( aDev.LinkKeyType() == ELinkKeyUnauthenticatedNonUpgradable ) |
|
232 { |
|
233 // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair, Just Works pairing" ) ) ); |
|
234 err = iParent.AddUiCookieJustWorksPaired( aDev ); |
|
235 } |
|
236 iActive->Cancel(); |
|
237 SetPairResult( err ? err : KErrNone ); |
|
238 iParent.OutgoingPairCompleted( err ); |
|
239 iParent.RenewPairingHandler( NULL ); |
|
240 } |
|
241 |
|
242 // --------------------------------------------------------------------------- |
|
243 // From class MBTNotifPairingAOObserver. |
|
244 // Based on the result code, decides the next operation, either try pairing |
|
245 // with another mode, or complete pair request. |
|
246 // --------------------------------------------------------------------------- |
|
247 // |
|
248 void CBTNotifOutgoingPairingHandler::RequestCompletedL( |
|
249 CBtSimpleActive* aActive, TInt aStatus ) |
|
250 { |
|
251 // TRACE_FUNC_ARG( ( _L( "reqid %d, status: %d, pair mode %d " ), aId, aStatus, iPairMode ) ) |
|
252 if( aActive->RequestId() == EDedicatedBonding && |
|
253 ( aStatus == KErrRemoteDeviceIndicatedNoBonding || |
|
254 ( aStatus && iPairMode != EBTOutgoingNoneHeadsetPairing && iPairMode != EBTOutgoingPairNone ) ) ) |
|
255 { |
|
256 // try general pairing if the remote doesn't have dedicated bonding, or |
|
257 // pairing fails with a headset. |
|
258 DoPairingL(); |
|
259 } |
|
260 else if ( aStatus && iPairMode == EBTOutgoingHeadsetAutoPairing ) |
|
261 { |
|
262 iPairMode = EBTOutgoingHeadsetManualPairing; |
|
263 // auto pairing with headset failed, try to pair again with manual pin: |
|
264 // ( void ) SetOutgoPairProperty( iOutgoProperty, iAddr, iPairMode ); |
|
265 // TRACE_INFO( _L( " auto pairing failed, switch to manual pairing") ); |
|
266 DoPairingL(); |
|
267 } |
|
268 else if ( aStatus && aActive->RequestId() == EGeneralBonding && |
|
269 iPairMode == EBTOutgoingHeadsetManualPairing ) |
|
270 { |
|
271 // pairing headset with manual pin failed, wait for a while and try again: |
|
272 iActive->SetRequestId( EGeneralBondingRetryTimer ); |
|
273 iTimer.After( iActive->iStatus, KGeneralBondingRetryDelayMicroSeconds ); |
|
274 iActive->GoActive(); |
|
275 } |
|
276 else if( aActive->RequestId() == EGeneralBondingRetryTimer ) |
|
277 { |
|
278 // try to pair headset again with manual pin again: |
|
279 DoPairingL(); |
|
280 } |
|
281 else if ( aStatus ) |
|
282 { |
|
283 // we only starts showing note if pairing failed. |
|
284 // For a successful pair, we must wait until registry has been updated. |
|
285 if ( !IsPairResultSet() ) |
|
286 { |
|
287 SetPairResult( aStatus ); |
|
288 } |
|
289 if ( aStatus ) |
|
290 { |
|
291 // todo: show error note? |
|
292 iParent.OutgoingPairCompleted( aStatus ); |
|
293 } |
|
294 } |
|
295 } |
|
296 |
|
297 // --------------------------------------------------------------------------- |
|
298 // From class MBTEngActiveObserver. |
|
299 // cancels an outstanding request according to the given id. |
|
300 // --------------------------------------------------------------------------- |
|
301 // |
|
302 void CBTNotifOutgoingPairingHandler::CancelRequest( TInt aRequestId ) |
|
303 { |
|
304 switch ( aRequestId ) |
|
305 { |
|
306 case EDedicatedBonding: |
|
307 { |
|
308 iBondingSession.Close(); |
|
309 } |
|
310 case EGeneralBonding: |
|
311 case EGeneralBondingRetry: |
|
312 { |
|
313 iSocket.CancelConnect(); |
|
314 iSocket.Close(); |
|
315 } |
|
316 case EGeneralBondingRetryTimer: |
|
317 { |
|
318 iTimer.Cancel(); |
|
319 } |
|
320 } |
|
321 } |
|
322 |
|
323 // --------------------------------------------------------------------------- |
|
324 // From class MBTEngActiveObserver. |
|
325 // Handles a leave in RequestCompleted by self-destructing. |
|
326 // --------------------------------------------------------------------------- |
|
327 // |
|
328 void CBTNotifOutgoingPairingHandler::HandleError( |
|
329 CBtSimpleActive* aActive, TInt aError ) |
|
330 { |
|
331 // TRACE_FUNC_ARG( ( _L( "error: %d" ), aError ) ) |
|
332 // Our RunL can actually not leave, so we should never reach here. |
|
333 (void) aActive; |
|
334 iParent.OutgoingPairCompleted( aError ); |
|
335 iParent.RenewPairingHandler( NULL ); |
|
336 } |
|
337 |
|
338 // --------------------------------------------------------------------------- |
|
339 // decide the next state and issue pair request |
|
340 // --------------------------------------------------------------------------- |
|
341 // |
|
342 void CBTNotifOutgoingPairingHandler::DoPairingL() |
|
343 { |
|
344 // TRACE_FUNC_ENTRY |
|
345 TPairingStageId currentMode = ( TPairingStageId ) iActive->RequestId(); |
|
346 ASSERT( !iActive->IsActive() ); |
|
347 TPairingStageId nextMode( EGeneralBonding ); |
|
348 |
|
349 // if running BTv2.0 stack, dedicated bonding method |
|
350 // is not available. |
|
351 if ( currentMode == ENoBonding && iParent.PairingServer() != NULL ) |
|
352 { |
|
353 nextMode = EDedicatedBonding; |
|
354 } |
|
355 else if(currentMode == EGeneralBondingRetryTimer) |
|
356 { |
|
357 nextMode = EGeneralBondingRetry; |
|
358 } |
|
359 |
|
360 // TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair::DoPairingL: bonding mode: pre %d, next %d"), currentMode, nextMode ) ); |
|
361 |
|
362 iActive->SetRequestId( nextMode ); |
|
363 if ( nextMode == EDedicatedBonding ) |
|
364 { |
|
365 iBondingSession.Start( *iParent.PairingServer(), iAddr, iActive->RequestStatus() ); |
|
366 } |
|
367 else |
|
368 { |
|
369 TBTServiceSecurity sec; |
|
370 sec.SetAuthentication( ETrue ); |
|
371 iSockAddr.SetBTAddr( iAddr ); |
|
372 iSockAddr.SetPort(KSDPPSM); |
|
373 iSockAddr.SetSecurity( sec ); |
|
374 iSocket.Close(); |
|
375 User::LeaveIfError( iSocket.Open( iParent.SocketServ(), KL2CAPDesC ) ); |
|
376 iSocket.Connect( iSockAddr, iActive->RequestStatus() ); |
|
377 } |
|
378 iActive->GoActive(); |
|
379 // TRACE_FUNC_EXIT |
|
380 } |
|
381 |