|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <bluetooth/logger.h> |
|
17 #include <bt_sock.h> |
|
18 #include "rfcommstates.h" |
|
19 #include "rfcomm.h" |
|
20 #include "rfcommmuxer.h" |
|
21 #include "rfcommflow.h" |
|
22 #include "rfcommconsts.h" |
|
23 #include "AsyncErrorKicker.h" |
|
24 |
|
25 #ifdef __FLOG_ACTIVE |
|
26 _LIT8(KLogComponent, LOG_COMPONENT_RFCOMM); |
|
27 #endif |
|
28 |
|
29 // Together, these classes and the SAP implement the State pattern |
|
30 // (GOF). The states themselves are implemented using the Flyweight |
|
31 // pattern. Each state is a Flyweight object, and CRfcommStateFactory |
|
32 // is manager of these objects. As a result of being a flyweight, no |
|
33 // state object may have state that can't be shared between all |
|
34 // possible users of the state (ie no per-SAP state) |
|
35 |
|
36 |
|
37 CRfcommStateFactory* CRfcommStateFactory::NewL() |
|
38 /** |
|
39 Create all the state singletons. |
|
40 **/ |
|
41 { |
|
42 CRfcommStateFactory* factory= new (ELeave) CRfcommStateFactory(); |
|
43 CleanupStack::PushL(factory); |
|
44 // Create all the new states |
|
45 factory->ConstructL(); |
|
46 CleanupStack::Pop(); |
|
47 return factory; |
|
48 } |
|
49 |
|
50 void CRfcommStateFactory::ConstructL() |
|
51 { |
|
52 iStates[EError] = new (ELeave) TRfcommStateError(*this); |
|
53 iStates[EClosed] = new (ELeave) TRfcommStateClosed(*this); |
|
54 iStates[EWaitForMux]= new (ELeave) TRfcommStateWaitForMux(*this); |
|
55 iStates[EWaitForPNResp]= new (ELeave) TRfcommStateWaitForPNResp(*this); |
|
56 iStates[EWaitForUA]= new (ELeave) TRfcommStateWaitForUA(*this); |
|
57 iStates[EOpen] = new (ELeave) TRfcommStateOpen(*this); |
|
58 iStates[EDisconnect] = new (ELeave) TRfcommStateDisconnect(*this); |
|
59 iStates[EListening] = new (ELeave) TRfcommStateListening(*this); |
|
60 iStates[EWaitForSABM] = new (ELeave) TRfcommStateWaitForSABM(*this); |
|
61 iStates[EWaitForIncomingSecurityCheck] = new (ELeave) TRfcommStateIncomingSecurityCheck(*this); |
|
62 iStates[EWaitForOutgoingSecurityCheck] = new (ELeave) TRfcommStateOutgoingSecurityCheck(*this); |
|
63 iStates[EWaitForStart] = new (ELeave) TRfcommStateWaitForStart(*this); |
|
64 iStates[ECloseOnStart] = new (ELeave) TRfcommStateCloseOnStart(*this); |
|
65 iStates[EDisconnecting] = new (ELeave) TRfcommStateDisconnecting(*this); |
|
66 // etc... |
|
67 } |
|
68 |
|
69 TInt CRfcommStateFactory::StateIndex(const TRfcommState* aState) const |
|
70 { |
|
71 TInt state; |
|
72 for (state = 0; state < ERfcommMaxState; state++) |
|
73 { |
|
74 if (iStates[state] == aState) |
|
75 { |
|
76 return state; |
|
77 } |
|
78 } |
|
79 |
|
80 return KUnknownState; |
|
81 } |
|
82 |
|
83 /* |
|
84 |
|
85 TRfcommState base class implementation |
|
86 |
|
87 */ |
|
88 |
|
89 TInt TRfcommState::SignalError(CRfcommSAP& aSAP, TInt aErr, MSocketNotify::TOperationBitmasks aType) |
|
90 /** |
|
91 Signal an error, with appropriate types to tell socket what's |
|
92 been affected. |
|
93 **/ |
|
94 { |
|
95 if (aSAP.iSocket) |
|
96 { |
|
97 aSAP.iSocket->Error(aErr, aType); |
|
98 } |
|
99 |
|
100 if(aType & MSocketNotify::EErrorFatal) |
|
101 { |
|
102 aSAP.iProtocol.ControlPlane().ModifyPhysicalLink(EUndoOverridePark, aSAP.iRemoteDev); |
|
103 ChangeState(aSAP, CRfcommStateFactory::EError); |
|
104 } |
|
105 return aErr; |
|
106 } |
|
107 |
|
108 // State change utility function |
|
109 |
|
110 void TRfcommState::ChangeState(CRfcommSAP& aSAP, CRfcommStateFactory::TRfcommStates aNewState) const |
|
111 { |
|
112 aSAP.iState->Exit(aSAP); |
|
113 #ifdef __FLOG_ACTIVE |
|
114 TRfcommState* state= iFactory.GetState(aNewState); |
|
115 LOG3(_L("RFCOMM : Sap %08x : State %S -> %S"), |
|
116 &aSAP, &aSAP.iState->iName, &state->iName); |
|
117 #endif //__FLOG_ACTIVE |
|
118 aSAP.iState=iFactory.GetState(aNewState); |
|
119 aSAP.iState->Enter(aSAP); |
|
120 } |
|
121 |
|
122 void TRfcommState::PanicInState(TRFCOMMPanic aPanic) const |
|
123 { |
|
124 Panic(aPanic, iFactory.StateIndex(this)); |
|
125 } |
|
126 |
|
127 #ifdef _DEBUG |
|
128 void TRfcommState::DebugPanicInState(TRFCOMMPanic aPanic) const |
|
129 #else |
|
130 void TRfcommState::DebugPanicInState(TRFCOMMPanic /*aPanic*/) const |
|
131 #endif |
|
132 { |
|
133 #ifdef _DEBUG |
|
134 PanicInState(aPanic); |
|
135 #endif |
|
136 } |
|
137 |
|
138 TRfcommState::TRfcommState(CRfcommStateFactory& aFactory) |
|
139 : iFactory(aFactory) |
|
140 { |
|
141 } |
|
142 |
|
143 /************************************************************************/ |
|
144 /* |
|
145 The default state operations. |
|
146 */ |
|
147 |
|
148 TRfcommStateDefault::TRfcommStateDefault(CRfcommStateFactory& aFactory) |
|
149 : TRfcommState(aFactory) |
|
150 { |
|
151 } |
|
152 |
|
153 void TRfcommStateDefault::Enter(CRfcommSAP& /*aSAP*/) |
|
154 { |
|
155 // Do nothing |
|
156 } |
|
157 |
|
158 void TRfcommStateDefault::Exit(CRfcommSAP& /*aSAP*/) |
|
159 { |
|
160 // Do nothing |
|
161 } |
|
162 |
|
163 void TRfcommStateDefault::ActiveOpen(CRfcommSAP& /* aSAP */ ) |
|
164 { |
|
165 PanicInState(ERfcommUnexpectedEvent); |
|
166 } |
|
167 |
|
168 TInt TRfcommStateDefault::PassiveOpen(CRfcommSAP& /* aSAP */, |
|
169 TUint /*aQueSize*/) |
|
170 { |
|
171 PanicInState(ERfcommUnexpectedEvent); |
|
172 return KErrGeneral; |
|
173 } |
|
174 |
|
175 |
|
176 void TRfcommStateDefault::Shutdown(CRfcommSAP& aSAP) |
|
177 { |
|
178 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
179 } |
|
180 |
|
181 void TRfcommStateDefault::FastShutdown(CRfcommSAP& aSAP) |
|
182 { |
|
183 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
184 } |
|
185 |
|
186 |
|
187 TInt TRfcommStateDefault::Send(CRfcommSAP& /*aSAP*/, const TDesC8& /*aData*/ ) |
|
188 { |
|
189 PanicInState(ERfcommUnexpectedEvent); |
|
190 return 0; |
|
191 } |
|
192 |
|
193 void TRfcommStateDefault::Read(CRfcommSAP& /*aSAP*/, TDesC8& /*aData*/) |
|
194 { |
|
195 PanicInState(ERfcommUnexpectedEvent); |
|
196 } |
|
197 |
|
198 void TRfcommStateDefault::Ioctl(CRfcommSAP& aSAP, TUint /*aLevel*/, |
|
199 TUint /*aName*/, TDes8* /*aOption*/) |
|
200 { |
|
201 SignalError(aSAP, KErrNotSupported, MSocketNotify::EErrorIoctl); |
|
202 } |
|
203 |
|
204 void TRfcommStateDefault::CancelIoctl(CRfcommSAP& aSAP, TUint /*aLevel*/, TUint /*aName*/) |
|
205 /** |
|
206 A request to cancel an Ioctl. |
|
207 |
|
208 Since the user has already been completed, and ESOCK prevents |
|
209 the completion occuring twice, there's very little we need to |
|
210 do (in fact we could ignore this entirely). |
|
211 |
|
212 Instead we will simply reset out IoctlLevel and IoctlName, |
|
213 since this will now mean that we will not complete the ioctl |
|
214 when the complete signal comes in. If the ioctl is going on |
|
215 below us, we will ignore the ioctl complete from them as well. |
|
216 **/ |
|
217 { |
|
218 aSAP.iIoctlLevel=0; |
|
219 aSAP.iIoctlName=0; |
|
220 } |
|
221 |
|
222 void TRfcommStateDefault::Start(CRfcommSAP& /*aSAP*/) |
|
223 { |
|
224 PanicInState(ERfcommUnexpectedEvent); |
|
225 } |
|
226 |
|
227 TInt TRfcommStateDefault::SetOption(CRfcommSAP &aSAP, TUint aLevel, |
|
228 TUint aName, const TDesC8& aOption) |
|
229 /** |
|
230 Set Option from user - works the same for SAPs in all states. |
|
231 **/ |
|
232 { |
|
233 if(aLevel == KSolBtRFCOMM) |
|
234 { |
|
235 switch(aName) |
|
236 { |
|
237 case KRFCOMMLocalPortParameter: |
|
238 // Just do a straight copy into the local port params |
|
239 aSAP.iLocalPortParams = *(TRfcommRemotePortParams*)aOption.Ptr(); |
|
240 break; |
|
241 case KRFCOMMMaximumSupportedMTU: |
|
242 { |
|
243 if ( aOption.Length() != sizeof(TUint16) ) |
|
244 { |
|
245 return KErrArgument; |
|
246 } |
|
247 else |
|
248 { |
|
249 TPckgBuf<TUint16> maxMTU; |
|
250 maxMTU.Copy(aOption); |
|
251 aSAP.iUserDefinedMTU = maxMTU(); |
|
252 } |
|
253 }; |
|
254 break; |
|
255 |
|
256 case KRFCOMMFlowTypeCBFC: |
|
257 { |
|
258 if ( aOption.Length() != sizeof(TBool) ) |
|
259 { |
|
260 return KErrArgument; |
|
261 } |
|
262 else |
|
263 { |
|
264 TPckgBuf<TBool> aCBFC; |
|
265 aCBFC.Copy(aOption); |
|
266 if(!aCBFC()) |
|
267 { |
|
268 //Switch off CBFC facility by setting flow strategy to |
|
269 //non-CBFC and setting the flow negotiated flag to 'ETrue'. |
|
270 if(aSAP.iMux) |
|
271 { |
|
272 if(!aSAP.iMux->SetFlowType(CRfcommFlowStrategyFactory::EFlowNonCreditBased)) |
|
273 { |
|
274 return KErrNotSupported; |
|
275 } |
|
276 } |
|
277 else |
|
278 { |
|
279 aSAP.DisallowCBFC(); //will cause muxer to use muxwise CBFC when created |
|
280 } |
|
281 } |
|
282 else |
|
283 { |
|
284 //Switch on CBFC facility by setting flow strategy to |
|
285 //CBFC and setting the flow negotiated flag to 'ETrue'. |
|
286 if(aSAP.iMux) |
|
287 { |
|
288 if(!aSAP.iMux->SetFlowType(CRfcommFlowStrategyFactory::EFlowCreditBased)) |
|
289 { |
|
290 return KErrNotSupported; |
|
291 } |
|
292 } |
|
293 else |
|
294 { |
|
295 aSAP.AllowCBFC(); //will cause muxer to use muxwise CBFC when created |
|
296 } |
|
297 } |
|
298 } |
|
299 } |
|
300 break; |
|
301 case KRFCOMMErrOnMSC: |
|
302 { |
|
303 if ( aOption.Length() != sizeof(TUint8) ) |
|
304 { |
|
305 return KErrArgument; |
|
306 } |
|
307 else |
|
308 { |
|
309 TPckgBuf<TUint8> aSignal; |
|
310 aSignal.Copy(aOption); |
|
311 aSAP.iDisconnectMSCSignal = aSignal(); |
|
312 } |
|
313 } |
|
314 break; |
|
315 case KBTSecurityDeviceOverride: |
|
316 { |
|
317 // let the security object handle this |
|
318 return aSAP.SetDeviceOverride(aOption); // just pass the option |
|
319 } |
|
320 case KBTRegisterCodService: |
|
321 { |
|
322 TInt err = KErrNone; |
|
323 TUint16 newServiceBits = *reinterpret_cast<const TUint16*>(aOption.Ptr()); |
|
324 err = aSAP.SetCodServiceBits(newServiceBits); // The service bits are saved and then registered when SAP becomes live |
|
325 return err; |
|
326 } |
|
327 |
|
328 case KRFCOMMForgiveCBFCOverflow: |
|
329 { |
|
330 if ( aOption.Length() != sizeof(TBool) ) |
|
331 { |
|
332 return KErrArgument; |
|
333 } |
|
334 else |
|
335 { |
|
336 aSAP.iForgiveCBFCOverflow = *reinterpret_cast<const TBool*>(aOption.Ptr()); |
|
337 } |
|
338 }; |
|
339 break; |
|
340 |
|
341 default: |
|
342 return KErrNotSupported; |
|
343 } |
|
344 return KErrNone; |
|
345 } |
|
346 |
|
347 // Not a RFCOMM setopt so error. We don't support passdown (yet). |
|
348 return KErrNotSupported; |
|
349 } |
|
350 |
|
351 void TRfcommStateDefault::MuxUp(CRfcommSAP& aSAP) |
|
352 { |
|
353 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, |
|
354 MSocketNotify::EErrorAllOperations); |
|
355 } |
|
356 |
|
357 void TRfcommStateDefault::LinkDown(CRfcommSAP& aSAP) |
|
358 { |
|
359 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, |
|
360 MSocketNotify::EErrorAllOperations); |
|
361 } |
|
362 |
|
363 void TRfcommStateDefault::SABM(CRfcommSAP& /*aSAP*/, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
364 /** |
|
365 Send a DM, since we are not expecting this |
|
366 |
|
367 **/ |
|
368 { |
|
369 aMux.SendDM(aDLCI); |
|
370 } |
|
371 |
|
372 void TRfcommStateDefault::DISC(CRfcommSAP& aSAP) |
|
373 /** |
|
374 Send a DM as we were not expecting this |
|
375 **/ |
|
376 { |
|
377 aSAP.iMux->SendDM(aSAP.iDLCI); |
|
378 } |
|
379 |
|
380 void TRfcommStateDefault::UA(CRfcommSAP& /*aSAP*/) |
|
381 /** |
|
382 Do nothing - unexpected response |
|
383 **/ |
|
384 { |
|
385 } |
|
386 |
|
387 void TRfcommStateDefault::DM(CRfcommSAP& /*aSAP*/) |
|
388 /** |
|
389 Do nothing - unexpected response |
|
390 **/ |
|
391 { |
|
392 } |
|
393 |
|
394 void TRfcommStateDefault::RPN(CRfcommSAP& aSAP, const TRfcommRPNTransaction& /*aRPNTransaction*/, CRfcommMuxer& /*aMuxer*/, TUint8 /*aDLCI*/) |
|
395 /** |
|
396 Send a DM as we didn't expect this |
|
397 **/ |
|
398 { |
|
399 aSAP.iMux->SendDM(aSAP.iDLCI); |
|
400 } |
|
401 |
|
402 void TRfcommStateDefault::RPNRsp(CRfcommSAP& /*aSAP*/, |
|
403 const TRfcommRPNTransaction& |
|
404 /*aRPNTransaction*/) |
|
405 /** |
|
406 Do nothing - unwanted response |
|
407 **/ |
|
408 { |
|
409 } |
|
410 |
|
411 |
|
412 void TRfcommStateDefault::PN(CRfcommSAP& aSAP, TRfcommPortParams& /*aParams*/, CRfcommMuxer& /*aMux*/, TUint8 aDLCI) |
|
413 /** |
|
414 Send a DM as we aren't handling this. |
|
415 **/ |
|
416 { |
|
417 __ASSERT_DEBUG(aDLCI==aSAP.iDLCI, PanicInState(ERfcommPNMismatchedDLCI)); |
|
418 aSAP.iMux->SendDM(aDLCI); |
|
419 } |
|
420 |
|
421 void TRfcommStateDefault::PNResp(CRfcommSAP& /*aSAP*/, TRfcommPortParams& /*aParams*/) |
|
422 /** |
|
423 Do nothing - unwanted response |
|
424 **/ |
|
425 { |
|
426 } |
|
427 |
|
428 void TRfcommStateDefault::MSC(CRfcommSAP& /*aSAP*/, TUint8 /*aSignals*/) |
|
429 /** |
|
430 Do nothing - the response is autogenerated |
|
431 **/ |
|
432 { |
|
433 } |
|
434 |
|
435 void TRfcommStateDefault::RLS(CRfcommSAP& /*aSAP*/, TUint8 /*aStatus*/) |
|
436 /** |
|
437 Do nothing - the response is autogenerated |
|
438 **/ |
|
439 { |
|
440 } |
|
441 |
|
442 void TRfcommStateDefault::NewData(CRfcommSAP& /*aSAP*/, const TDesC8& /*aData*/) |
|
443 /** |
|
444 Do nothing - we're throwing this data away |
|
445 **/ |
|
446 { |
|
447 } |
|
448 |
|
449 void TRfcommStateDefault::NotifyNewDataCallback(CRfcommSAP& aSAP) |
|
450 { |
|
451 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
452 } |
|
453 |
|
454 void TRfcommStateDefault::CanSend(CRfcommSAP& aSAP) |
|
455 { |
|
456 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
457 } |
|
458 |
|
459 void TRfcommStateDefault::IoctlComplete(CRfcommSAP& /*aSAP*/, TInt /*aErr*/, TUint /*aLevel*/, TUint /*aName*/, TDesC8* /*aBuf*/) |
|
460 { |
|
461 // Do nothing, this isn't for us |
|
462 } |
|
463 |
|
464 void TRfcommStateDefault::AccessRequestComplete(CRfcommSAP& /*aSAP*/, TInt /*aResult*/) |
|
465 { |
|
466 PanicInState(ERfcommUnexpectedSecurityRequesterCallback); |
|
467 } |
|
468 |
|
469 void TRfcommStateDefault::Error(CRfcommSAP& aSAP, TInt aErr, |
|
470 CRfcommSAP::TErrorTypes /*aType*/) |
|
471 { |
|
472 SignalError(aSAP, aErr, |
|
473 MSocketNotify::EErrorAllOperations); |
|
474 } |
|
475 |
|
476 void TRfcommStateDefault::ParentClosed(CRfcommSAP& aSAP) |
|
477 /** |
|
478 Our parent SAP has been deleted - NULL our pointer to it. |
|
479 |
|
480 This function only really applies to cloned child SAPs, but we |
|
481 handle it here anyway. |
|
482 **/ |
|
483 { |
|
484 aSAP.iParentSAP=NULL; |
|
485 } |
|
486 |
|
487 TBool TRfcommStateDefault::HandleFrameResponseTimeout(CRfcommSAP& /*aSAP*/) |
|
488 { |
|
489 // By default, we refuse to handle the frame timeout, indicating this by |
|
490 // returning EFalse. |
|
491 return EFalse; |
|
492 } |
|
493 |
|
494 //TRY_CBFC |
|
495 TUint8 TRfcommStateDefault::FreeCredit(CRfcommSAP& /*aSAP*/) |
|
496 { |
|
497 // return the max initial credit |
|
498 return (TUint8)KInitialCredit; |
|
499 } |
|
500 |
|
501 TInt TRfcommStateDefault::ProxyForRemoteCredit(const CRfcommSAP& /*aSAP*/) const |
|
502 { |
|
503 // return the max initial credit |
|
504 return (TInt)KInitialCredit; |
|
505 } |
|
506 |
|
507 void TRfcommStateDefault::SetProxyForRemoteCredit(CRfcommSAP& aSAP, TInt aCredit) |
|
508 { |
|
509 aSAP.iProxyForRemoteCredit = aCredit; |
|
510 LOG1(_L("RFCOMM: Proxy for credits available on REMOTE (...NEW SETUP...) -> %d"), aSAP.iProxyForRemoteCredit); |
|
511 } |
|
512 |
|
513 void TRfcommStateDefault::ProxyForRemoteCreditDecrement(CRfcommSAP& aSAP) |
|
514 { |
|
515 __ASSERT_DEBUG(aSAP.iProxyForRemoteCredit > 0,PanicInState(ERfcommCBFCProxyForRemoteCreditGoingNegative)); |
|
516 |
|
517 aSAP.iProxyForRemoteCredit--; |
|
518 LOG(_L("RFCOMM: Proxies for CREDITS on REMOTE:-")); |
|
519 LOG2(_L("RFCOMM: Available for use (...DECREMENT...) %d -> %d: -1"), |
|
520 aSAP.iProxyForRemoteCredit+1, |
|
521 aSAP.iProxyForRemoteCredit); |
|
522 #ifdef _DEBUG |
|
523 aSAP.iProxyForRemoteCreditsUsed++; |
|
524 LOG1(_L("RFCOMM: Total USED so far during this session: %d"), |
|
525 aSAP.iProxyForRemoteCreditsUsed); |
|
526 #endif |
|
527 return; |
|
528 } |
|
529 |
|
530 void TRfcommStateDefault::ProxyForRemoteCreditAddCredit(CRfcommSAP& aSAP, TUint8 aCredit) |
|
531 { |
|
532 aSAP.iProxyForRemoteCredit += aCredit; |
|
533 LOG(_L("RFCOMM: Proxies for CREDITS on REMOTE:-")); |
|
534 LOG3(_L("RFCOMM: Available for use (...ADD...) %d -> %d: +%d"), |
|
535 aSAP.iProxyForRemoteCredit-aCredit, |
|
536 aSAP.iProxyForRemoteCredit, |
|
537 aCredit); |
|
538 #ifdef _DEBUG |
|
539 aSAP.iProxyForRemoteCreditsSupplied += aCredit; |
|
540 LOG1(_L("RFCOMM: Total SUPPLIED so far during this session: %d"), |
|
541 aSAP.iProxyForRemoteCreditsSupplied); |
|
542 #endif |
|
543 } |
|
544 |
|
545 |
|
546 TInt TRfcommStateDefault::LocalCredit(const CRfcommSAP& /*aSAP*/) const |
|
547 { |
|
548 // return a zero credit - so cannot send |
|
549 return (TInt)0; |
|
550 } |
|
551 |
|
552 void TRfcommStateDefault::SetInitialLocalCredit(CRfcommSAP& aSAP, TInt aCredit) |
|
553 { |
|
554 aSAP.iLocalCredit = aCredit; |
|
555 LOG1(_L("RFCOMM: LOCAL credits available (...NEW SETUP...) -> %d"), aSAP.iLocalCredit); |
|
556 } |
|
557 |
|
558 void TRfcommStateDefault::LocalCreditDecrement(CRfcommSAP& aSAP) |
|
559 { |
|
560 __ASSERT_DEBUG(aSAP.iLocalCredit > 0,PanicInState(ERfcommCBFCLocalCreditGoingNegative)); |
|
561 |
|
562 aSAP.iLocalCredit--; |
|
563 LOG(_L("RFCOMM: LOCAL CREDITS:-")); |
|
564 LOG2(_L("RFCOMM: Available for use (...DECREMENT...) %d -> %d: -1"), |
|
565 aSAP.iLocalCredit+1, |
|
566 aSAP.iLocalCredit); |
|
567 #ifdef _DEBUG |
|
568 aSAP.iLocalCreditsUsed++; |
|
569 LOG1(_L("RFCOMM: Total USED so far during this session: %d"), |
|
570 aSAP.iLocalCreditsUsed); |
|
571 #endif |
|
572 return; |
|
573 } |
|
574 |
|
575 void TRfcommStateDefault::LocalCreditAddCredit(CRfcommSAP& aSAP, TUint8 aCredit) |
|
576 { |
|
577 aSAP.iLocalCredit += aCredit; |
|
578 LOG(_L("RFCOMM: LOCAL CREDITS:-")); |
|
579 LOG3(_L("RFCOMM: Available for use (...ADD...) %d -> %d: +%d"), |
|
580 aSAP.iLocalCredit-aCredit, |
|
581 aSAP.iLocalCredit, |
|
582 aCredit); |
|
583 #ifdef _DEBUG |
|
584 aSAP.iLocalCreditsSupplied += aCredit; |
|
585 LOG1(_L("RFCOMM: Total SUPPLIED so far during this session: %d"), |
|
586 aSAP.iLocalCreditsSupplied); |
|
587 #endif |
|
588 } |
|
589 |
|
590 |
|
591 /*************************************************************************/ |
|
592 |
|
593 // TRfcommStateError |
|
594 |
|
595 /*************************************************************************/ |
|
596 |
|
597 TRfcommStateError::TRfcommStateError(CRfcommStateFactory& aFactory) |
|
598 : TRfcommStateDefault(aFactory) |
|
599 { |
|
600 STATENAME("Error"); |
|
601 } |
|
602 |
|
603 void TRfcommStateError::ActiveOpen(CRfcommSAP& aSAP) |
|
604 { |
|
605 SignalError(aSAP, KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
606 } |
|
607 |
|
608 TInt TRfcommStateError::PassiveOpen(CRfcommSAP& aSAP, TUint /*aQueSize*/) |
|
609 { |
|
610 return SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
611 } |
|
612 |
|
613 void TRfcommStateError::Shutdown(CRfcommSAP& aSAP) |
|
614 { |
|
615 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
616 } |
|
617 |
|
618 void TRfcommStateError::FastShutdown(CRfcommSAP& aSAP) |
|
619 { |
|
620 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
621 } |
|
622 |
|
623 TInt TRfcommStateError::Send(CRfcommSAP& aSAP, const TDesC8&) |
|
624 { |
|
625 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
626 return 0; |
|
627 } |
|
628 |
|
629 void TRfcommStateError::Read(CRfcommSAP& aSAP, TDesC8&) |
|
630 { |
|
631 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
632 } |
|
633 |
|
634 void TRfcommStateError::Ioctl(CRfcommSAP& aSAP, TUint, TUint, TDes8*) |
|
635 { |
|
636 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
637 } |
|
638 |
|
639 void TRfcommStateError::CancelIoctl(CRfcommSAP& /*aSAP*/, TUint, TUint) |
|
640 /** |
|
641 Ignore the cancel. |
|
642 |
|
643 This is because cancelling in the error state may even be |
|
644 valid, and it doesn't hurt to ignore cancels. |
|
645 **/ |
|
646 { |
|
647 } |
|
648 |
|
649 void TRfcommStateError::Start(CRfcommSAP& aSAP) |
|
650 { |
|
651 SignalError(aSAP,KErrGeneral, MSocketNotify::EErrorAllOperations); |
|
652 } |
|
653 |
|
654 void TRfcommStateError::Enter(CRfcommSAP& aSAP) |
|
655 /** |
|
656 Take this SAP off the mux, since once it's in error state we |
|
657 don't want to get any more notifications from the mux |
|
658 **/ |
|
659 { |
|
660 |
|
661 aSAP.DeregisterCodService(); // See if there is a Service to remove for CodMan |
|
662 |
|
663 if(aSAP.iMux) |
|
664 { |
|
665 aSAP.iMux->DetachSAP(aSAP); |
|
666 } |
|
667 } |
|
668 |
|
669 |
|
670 /*************************************************************************/ |
|
671 |
|
672 // Implementation of TRfcommStateClosed |
|
673 // |
|
674 // This is the intial state for a SAP and represents it before Connect() has |
|
675 // been called, and it is also the end state when closing down |
|
676 |
|
677 TRfcommStateClosed::TRfcommStateClosed(CRfcommStateFactory& aFactory) |
|
678 : TRfcommStateDefault(aFactory) |
|
679 { |
|
680 STATENAME("Closed"); |
|
681 } |
|
682 |
|
683 void TRfcommStateClosed::Enter(CRfcommSAP& aSAP) |
|
684 /** |
|
685 Entering the closed state. |
|
686 |
|
687 We need to remove ourselves from the muxer (if we have one) |
|
688 **/ |
|
689 { |
|
690 aSAP.iClosePending=EFalse; |
|
691 if(aSAP.iNotifyNewDataCallback->IsActive()) |
|
692 { |
|
693 aSAP.iNotifyNewDataCallback->Cancel(); |
|
694 } |
|
695 aSAP.iNewDataToNotify=0; |
|
696 aSAP.iDataBuffer.Reset(); |
|
697 aSAP.iProtocol.ControlPlane().ModifyPhysicalLink(EUndoOverridePark, aSAP.iRemoteDev); |
|
698 if(aSAP.iMux) |
|
699 { |
|
700 aSAP.iMux->DetachSAP(aSAP); |
|
701 } |
|
702 aSAP.DeregisterCodService(); // See if there is a Service to remove for CodMan |
|
703 |
|
704 } |
|
705 |
|
706 void TRfcommStateClosed::Error(CRfcommSAP& /*aSAP*/, TInt /*aErr*/, |
|
707 CRfcommSAP::TErrorTypes /*aType*/) |
|
708 /** |
|
709 Panic, we'd never get here since state closed never has a mux associated. |
|
710 **/ |
|
711 { |
|
712 DebugPanicInState(ERfcommUnexpectedEvent); |
|
713 } |
|
714 |
|
715 void TRfcommStateClosed::ActiveOpen(CRfcommSAP& aSAP) |
|
716 /** |
|
717 Called by Socket to cause a connection to be established. |
|
718 |
|
719 This causes a sequence of actions which ends with |
|
720 ConnectComplete() being called on the socket notifier. Since a |
|
721 SAP in the closed state may not be fully initialised, all the |
|
722 parameters must be checked before starting the connect. |
|
723 **/ |
|
724 { |
|
725 LOG1(_L("RFCOMM: ActiveOpen while state closed, sap %08x"), &aSAP); |
|
726 if(!aSAP.ServerChannelValid() ) |
|
727 { |
|
728 LOG(_L("SAP DLCI error")); |
|
729 SignalError(aSAP, KErrRfcommBadAddress, MSocketNotify::EErrorConnect); |
|
730 return; |
|
731 } |
|
732 |
|
733 aSAP.RegisterCodService(); // See if there is a Service set for CodMan |
|
734 |
|
735 // First get a Mux. |
|
736 ChangeState(aSAP, CRfcommStateFactory::EWaitForMux); |
|
737 } |
|
738 |
|
739 TInt TRfcommStateClosed::PassiveOpen(CRfcommSAP& aSAP, |
|
740 TUint aQueSize) |
|
741 /** |
|
742 We've just asked to turn into a listening SAP. |
|
743 |
|
744 NB. We need to check with the protocol that no other listening SAPs |
|
745 are currently listening on our specified server channel. |
|
746 We should also return an error if the protocol has no listener |
|
747 **/ |
|
748 { |
|
749 // First, check that the protocol is listening |
|
750 |
|
751 if(aSAP.iProtocol.IncrementListeners() != KErrNone) // get protocol to attempt to listen |
|
752 return KErrRfcommNotListening; |
|
753 |
|
754 // Second, the check for other listening SAPs on our specified local address. |
|
755 |
|
756 TBTSockAddr listeningName; |
|
757 aSAP.LocalName(listeningName); |
|
758 CRfcommSAP* listener=aSAP.iProtocol.FindIdleSAP(listeningName); |
|
759 |
|
760 __ASSERT_DEBUG((listener==NULL), PanicInState(ERfcommSAPAllocatedBetweenBindAndListen)); |
|
761 |
|
762 if(listener!=NULL) |
|
763 return KErrInUse; |
|
764 |
|
765 TBTSockAddr remoteAddr; |
|
766 remoteAddr.SetBTAddr(aSAP.iRemoteDev); |
|
767 remoteAddr.SetPort(aSAP.iServerChannel); |
|
768 if(aSAP.iProtocol.FindIdleSAP(remoteAddr)) |
|
769 return KErrAlreadyExists; // RFCOMM already has a listener which would field this address... |
|
770 |
|
771 aSAP.iMaxClonesWaitingForStart=aQueSize; |
|
772 aSAP.RegisterCodService(); // See if there is a Service set for CodMan |
|
773 ChangeState(aSAP, CRfcommStateFactory::EListening); |
|
774 return KErrNone; |
|
775 } |
|
776 |
|
777 void TRfcommStateClosed::Start(CRfcommSAP& /*aSAP*/) |
|
778 { |
|
779 // Do nothing - this is quite a valid thing to happen, but the base class panics! |
|
780 } |
|
781 |
|
782 void TRfcommStateClosed::Shutdown(CRfcommSAP& aSAP) |
|
783 /** |
|
784 The ESOCK would like us to close down. We can. |
|
785 **/ |
|
786 { |
|
787 aSAP.iSocket->CanClose(); |
|
788 } |
|
789 |
|
790 TInt TRfcommStateClosed::SetOption(CRfcommSAP &aSAP, TUint aLevel, |
|
791 TUint aName, const TDesC8& aOption) |
|
792 /** |
|
793 Allow modem status to be modified whilst we are closed. |
|
794 **/ |
|
795 { |
|
796 if(aLevel == KSolBtRFCOMM && aName == KRFCOMMLocalModemStatus) |
|
797 { |
|
798 if ( aOption.Length() != sizeof(TUint8) ) |
|
799 { |
|
800 return KErrArgument; |
|
801 } |
|
802 else |
|
803 { |
|
804 TPckgBuf<TUint8> signals; |
|
805 signals.Copy(aOption); |
|
806 aSAP.iSignals = signals(); |
|
807 return KErrNone; |
|
808 } |
|
809 } |
|
810 |
|
811 return TRfcommStateDefault::SetOption(aSAP, aLevel, aName, aOption); |
|
812 } |
|
813 |
|
814 /*************************************************************************/ |
|
815 |
|
816 // Implementation of TRfcommStateConnecting |
|
817 |
|
818 TRfcommStateConnecting::TRfcommStateConnecting(CRfcommStateFactory& aFactory) |
|
819 : TRfcommStateDefault(aFactory) |
|
820 { |
|
821 } |
|
822 |
|
823 |
|
824 void TRfcommStateConnecting::Shutdown(CRfcommSAP& aSAP) |
|
825 /** |
|
826 We've been asked to do a controlled shutdown during connection. |
|
827 Record the fact that we want to send a disconnect command upon |
|
828 reception of the UA command. |
|
829 **/ |
|
830 { |
|
831 aSAP.iClosePending=ETrue; |
|
832 } |
|
833 |
|
834 void TRfcommStateConnecting::FastShutdown(CRfcommSAP& aSAP) |
|
835 /** |
|
836 We've been asked to shutdown with extreme prejudice. |
|
837 Move back to the Closed state - there is nothing we can do |
|
838 to make this clean |
|
839 **/ |
|
840 { |
|
841 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
842 }; |
|
843 |
|
844 |
|
845 void TRfcommStateConnecting::DM(CRfcommSAP& aSAP) |
|
846 /** |
|
847 We've received a DM (Disconnect Mode) response. |
|
848 If we've been asked to close down anyway, tell the SAP that we can be closed. |
|
849 If we haven't, signal an error to the socket. |
|
850 **/ |
|
851 { |
|
852 FailureWhileConnecting(aSAP, KErrCouldNotConnect); |
|
853 } |
|
854 |
|
855 void TRfcommStateConnecting::FailureWhileConnecting(CRfcommSAP& aSAP, TInt aErrorCode) |
|
856 /** |
|
857 Send appropriate notification of failure back to SAP socket if failure occurs while connecting. |
|
858 **/ |
|
859 { |
|
860 if(!aSAP.iClosePending) |
|
861 { |
|
862 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
863 SignalError(aSAP, aErrorCode, MSocketNotify::EErrorConnect); |
|
864 } |
|
865 else |
|
866 { |
|
867 aSAP.iSocket->CanClose(); // Will delete us |
|
868 } |
|
869 } |
|
870 |
|
871 void TRfcommStateConnecting::LinkDown(CRfcommSAP& aSAP) |
|
872 /** |
|
873 The link has gone down before our connection came up. |
|
874 |
|
875 This can even (counter-intuitively) occur in WaitForMux because |
|
876 there is a lag between the l2cap link coming up and the mux |
|
877 channel itself coming up. In the interval, the l2cap link can |
|
878 drop again and thus we get a link down notification (the mux |
|
879 will not attempt to reconnect). |
|
880 |
|
881 Handle this by simply erroring the connection attempt. |
|
882 **/ |
|
883 { |
|
884 // tell secman not to bother |
|
885 aSAP.CancelAccessRequest(); |
|
886 |
|
887 FailureWhileConnecting(aSAP, KErrDisconnected); |
|
888 } |
|
889 |
|
890 |
|
891 /*******************************************************************/ |
|
892 /* |
|
893 Implementation of WaitForMux state. |
|
894 When a mux has been found for this SAP, then MuxUp is called. |
|
895 */ |
|
896 |
|
897 TRfcommStateWaitForMux::TRfcommStateWaitForMux(CRfcommStateFactory& aFactory) |
|
898 : TRfcommStateConnecting(aFactory) |
|
899 { |
|
900 STATENAME("WaitForMux"); |
|
901 } |
|
902 |
|
903 void TRfcommStateWaitForMux::Enter(CRfcommSAP& aSAP) |
|
904 /** |
|
905 Entry to the state. |
|
906 |
|
907 Ask the protocol to find a mux for us. We can then |
|
908 add our context to it. |
|
909 **/ |
|
910 { |
|
911 CRfcommMuxer* mux=NULL; |
|
912 TBTSockAddr remoteAddr; |
|
913 aSAP.RemName(remoteAddr); |
|
914 TInt error=aSAP.iProtocol.GetMux(remoteAddr,mux); |
|
915 if(error) |
|
916 Error(aSAP, error, CRfcommSAP::EErrorGeneral); |
|
917 else |
|
918 { |
|
919 // Calculate the DLCI that this SAP is trying to connect to |
|
920 aSAP.iDLCI=mux->MakeOutboundDLCI(TUint8(remoteAddr.Port())); |
|
921 // Ensure that we don't already have a connection for the DLCI |
|
922 // we're trying to connect to on this device... |
|
923 if(mux->FindSAP(aSAP.DLCI())!=NULL) |
|
924 { |
|
925 // Problems! We've already got a SAP attached to this DLCI |
|
926 // for this same device...we need to error this SAP. |
|
927 LOG1(_L("RFCOMM: Attempt to connect to connected SAP, DLCI %d"), aSAP.DLCI()); |
|
928 Error(aSAP, KErrAlreadyExists, CRfcommSAP::EErrorGeneral); |
|
929 } |
|
930 else |
|
931 { |
|
932 // Transfer the sap to the mux |
|
933 if(aSAP.iMux) |
|
934 aSAP.iLink.Deque(); |
|
935 aSAP.iMux=mux; |
|
936 |
|
937 // The next line will call back into MuxUp, either synchronously |
|
938 // (when mux channel is already up) or asynchronously (when the |
|
939 // mux channel needs to be opened). |
|
940 mux->AddSAP(aSAP); |
|
941 } |
|
942 } |
|
943 } |
|
944 |
|
945 void TRfcommStateWaitForMux::MuxUp(CRfcommSAP& aSAP) |
|
946 /** |
|
947 A muxer has been found for this SAP. |
|
948 On entry, the sap has had a muxer associated with it. |
|
949 Change state to connecting, so it can do any config and the SABM. |
|
950 **/ |
|
951 { |
|
952 ChangeState(aSAP, CRfcommStateFactory::EWaitForPNResp); // Enter the new state |
|
953 } |
|
954 |
|
955 void TRfcommStateWaitForMux::Shutdown(CRfcommSAP& aSAP) |
|
956 /** |
|
957 We've been asked to shutdown while connecting. |
|
958 |
|
959 Since the mux isn't up yet, we must detach from the mux and |
|
960 also signal that we can be deleted. |
|
961 **/ |
|
962 { |
|
963 ChangeState(aSAP, CRfcommStateFactory::EClosed);// Enter this state, which detaches us |
|
964 aSAP.iSocket->CanClose(); // This deletes us |
|
965 } |
|
966 |
|
967 void TRfcommStateWaitForMux::SABM(CRfcommSAP& aSAP, CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
968 { |
|
969 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
970 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
971 } |
|
972 |
|
973 void TRfcommStateWaitForMux::UA(CRfcommSAP& /*aSAP*/) |
|
974 { |
|
975 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
976 /*ignore and hope for the best*/ |
|
977 } |
|
978 |
|
979 void TRfcommStateWaitForMux::DISC(CRfcommSAP& aSAP) |
|
980 { |
|
981 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
982 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
983 } |
|
984 |
|
985 void TRfcommStateWaitForMux::DM(CRfcommSAP& /*aSAP*/) |
|
986 { |
|
987 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
988 /*ignore and hope for the best*/ |
|
989 } |
|
990 |
|
991 void TRfcommStateWaitForMux::RPN(CRfcommSAP& aSAP, const TRfcommRPNTransaction& /*aRPNTransaction*/, CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
992 { |
|
993 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
994 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
995 } |
|
996 |
|
997 void TRfcommStateWaitForMux::RPNRsp(CRfcommSAP& /*aSAP*/, const TRfcommRPNTransaction& /*aRPNTransaction*/) |
|
998 { |
|
999 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1000 /*ignore and hope for the best*/ |
|
1001 } |
|
1002 |
|
1003 // Parameter negotiation |
|
1004 void TRfcommStateWaitForMux::PN(CRfcommSAP& aSAP, TRfcommPortParams& /*aParams*/, CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
1005 { |
|
1006 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1007 SignalError(aSAP, KErrRfcommSAPUnexpectedEvent, MSocketNotify::EErrorAllOperations); |
|
1008 } |
|
1009 |
|
1010 void TRfcommStateWaitForMux::PNResp(CRfcommSAP& /*aSAP*/, TRfcommPortParams& /*aParams*/) |
|
1011 { |
|
1012 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1013 /*ignore and hope for the best*/ |
|
1014 } |
|
1015 |
|
1016 void TRfcommStateWaitForMux::MSC(CRfcommSAP& /*aSAP*/, TUint8 /*aSignals*/) |
|
1017 { |
|
1018 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1019 /*ignore and hope for the best*/ |
|
1020 } |
|
1021 |
|
1022 void TRfcommStateWaitForMux::RLS(CRfcommSAP& /*aSAP*/, TUint8 /*aStatus*/) |
|
1023 { |
|
1024 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1025 /*ignore and hope for the best*/ |
|
1026 } |
|
1027 |
|
1028 void TRfcommStateWaitForMux::NewData(CRfcommSAP& /*aSAP*/, const TDesC8& /*aData*/) |
|
1029 { |
|
1030 DebugPanicInState(ERfcommFrameBeforeMuxUp); |
|
1031 /*ignore and hope for the best*/ |
|
1032 } |
|
1033 |
|
1034 /***************************************************************** |
|
1035 |
|
1036 State Wait for PN Response |
|
1037 |
|
1038 ******************************************************************/ |
|
1039 |
|
1040 TRfcommStateWaitForPNResp::TRfcommStateWaitForPNResp(CRfcommStateFactory& aFactory) |
|
1041 : TRfcommStateConnecting(aFactory) |
|
1042 { |
|
1043 STATENAME("WaitForPNResp"); |
|
1044 } |
|
1045 |
|
1046 void TRfcommStateWaitForPNResp::Enter(CRfcommSAP& aSAP) |
|
1047 /** |
|
1048 The Mux is up - it's time to initiate Parameter Negotiations |
|
1049 |
|
1050 Send a PN packet with our preferred parameters. |
|
1051 **/ |
|
1052 { |
|
1053 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1054 TRfcommPortParams params; |
|
1055 params.iMaxFrameSize=aSAP.MaximumMTU(); |
|
1056 params.iInitialCredit = aSAP.iMux->FlowStrategy()->PNFinalOctet(); |
|
1057 |
|
1058 aSAP.SetProxyForRemoteCredit(params.iInitialCredit); // set up our proxy |
|
1059 #ifdef _DEBUG |
|
1060 aSAP.iProxyForRemoteCreditsSupplied = params.iInitialCredit; |
|
1061 #endif |
|
1062 aSAP.iMTU=params.iMaxFrameSize; // Remember the newly calculated MTU |
|
1063 LOG2(_L("RFCOMM: Sending PN (Calculated MTU %d from frame size %d)"), aSAP.iMTU, aSAP.iMux->GetMaxDataSize()); |
|
1064 |
|
1065 TInt error=aSAP.iMux->SendPN(aSAP, params); |
|
1066 |
|
1067 if(error!=KErrNone) |
|
1068 { |
|
1069 // Error occurred while sending parameter negotiation command |
|
1070 FailureWhileConnecting(aSAP, error); |
|
1071 } |
|
1072 } |
|
1073 |
|
1074 void TRfcommStateWaitForPNResp::PNResp(CRfcommSAP& aSAP, TRfcommPortParams& aParams) |
|
1075 /** |
|
1076 We've received a PN response, which may or may not mean our |
|
1077 datasize has been accepted |
|
1078 |
|
1079 If everything is OK (ie. the PN response accepts a MTU size |
|
1080 between 1 and our original maximum MTU), send a SABM and begin |
|
1081 waiting for a UA. If things are not OK, we either signal an error |
|
1082 or inform the socket that we CanClose (depending on whether we |
|
1083 were trying to disconnect anyway). |
|
1084 |
|
1085 **/ |
|
1086 { |
|
1087 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1088 if(aParams.iCreditIndicator == (KCBFCResponseFlag >> 4)) |
|
1089 { |
|
1090 aSAP.SetInitialLocalCredit(aParams.iInitialCredit); |
|
1091 #ifdef _DEBUG |
|
1092 aSAP.iLocalCreditsSupplied = aParams.iInitialCredit; |
|
1093 #endif |
|
1094 } |
|
1095 TInt error=KErrNone; |
|
1096 if(aParams.iMaxFrameSize<=aSAP.NegotiatedMTU() && aParams.iMaxFrameSize>0) |
|
1097 { |
|
1098 LOG1(_L("RFCOMM: Received acceptable PN Response with MTU %d"),aParams.iMaxFrameSize); |
|
1099 |
|
1100 // We have an MTU value so ask L2Cap to work out the optimal MTU value based on the one |
|
1101 // received from the remote. Note that the Max Frame Size is the max data size for Rfcomm |
|
1102 // so we need to add on the max Rfcomm header size to create the restriction on L2Cap |
|
1103 // MTU. |
|
1104 TPckgBuf<TInt> restrictedMtu(aParams.iMaxFrameSize + KMaxFrameOverhead); |
|
1105 error = aSAP.GetOption(KSolBtL2CAP, KL2CAPOutboundMTUForBestPerformanceWithRestriction, restrictedMtu); |
|
1106 |
|
1107 // If we get an error continue but with a possible non-optimal MTU value. iMTU is the max |
|
1108 // data size so remove the max Rfcomm header size as these will get added later. |
|
1109 aSAP.iMTU = (error == KErrNone) ? restrictedMtu() - KMaxFrameOverhead : aParams.iMaxFrameSize; |
|
1110 error = KErrNone; |
|
1111 |
|
1112 } |
|
1113 else |
|
1114 { |
|
1115 LOG1(_L("RFCOMM: Received unacceptable PN Response with MTU %d"),aParams.iMaxFrameSize); |
|
1116 error=KErrRfcommParameterNegotiationFailure; |
|
1117 }; |
|
1118 |
|
1119 if(error!=KErrNone) |
|
1120 { |
|
1121 FailureWhileConnecting(aSAP,error); |
|
1122 } |
|
1123 else |
|
1124 { |
|
1125 ChangeState(aSAP, CRfcommStateFactory::EWaitForOutgoingSecurityCheck); |
|
1126 } |
|
1127 } |
|
1128 |
|
1129 /*********************************************************************/ |
|
1130 /* |
|
1131 We've received a good PN configuration response and we're waiting for the connection to complete. |
|
1132 |
|
1133 */ |
|
1134 |
|
1135 TRfcommStateWaitForUA::TRfcommStateWaitForUA(CRfcommStateFactory& aFactory) |
|
1136 : TRfcommStateConnecting(aFactory) |
|
1137 { |
|
1138 STATENAME("WaitForUA"); |
|
1139 } |
|
1140 |
|
1141 void TRfcommStateWaitForUA::UA(CRfcommSAP& aSAP) |
|
1142 /** |
|
1143 The SABM command has succeeded. |
|
1144 |
|
1145 If there is no close pending we go to open, and |
|
1146 also construct the SAPs buffers. If we need to close, we go to |
|
1147 the disconnect state. |
|
1148 **/ |
|
1149 { |
|
1150 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1151 if(aSAP.iClosePending) |
|
1152 { |
|
1153 ChangeState(aSAP, CRfcommStateFactory::EDisconnect); |
|
1154 } |
|
1155 else |
|
1156 { |
|
1157 TRAPD(err, |
|
1158 aSAP.iDataBuffer.SetLengthL(aSAP.iMux->FlowStrategy()->DataBufferMultiple()* |
|
1159 aSAP.iMTU)); |
|
1160 if(err != KErrNone) |
|
1161 { |
|
1162 // Failed to alloc, so fail this connect and error |
|
1163 SignalError(aSAP, err, MSocketNotify::EErrorConnect); |
|
1164 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1165 return; |
|
1166 } |
|
1167 |
|
1168 aSAP.iHighTideMark=KRfcommSAPBufferHighMultiple*(aSAP.iMTU); |
|
1169 aSAP.iLowTideMark=KRfcommSAPBufferLowMultiple*(aSAP.iMTU); |
|
1170 |
|
1171 |
|
1172 ChangeState(aSAP, CRfcommStateFactory::EOpen); |
|
1173 } |
|
1174 } |
|
1175 |
|
1176 TBool TRfcommStateWaitForUA::HandleFrameResponseTimeout(CRfcommSAP& aSAP) |
|
1177 /** |
|
1178 We've waited too long for a UA to come back to us, so we start disconnecting. |
|
1179 |
|
1180 We also need to signal |
|
1181 **/ |
|
1182 { |
|
1183 if(!aSAP.iClosePending) |
|
1184 SignalError(aSAP, KErrTimedOut, MSocketNotify::EErrorConnect); |
|
1185 |
|
1186 ChangeState(aSAP, CRfcommStateFactory::EDisconnect); |
|
1187 return ETrue; |
|
1188 } |
|
1189 |
|
1190 /******************************************************************/ |
|
1191 /* |
|
1192 The Listening state. |
|
1193 |
|
1194 Deals with incoming connection requests |
|
1195 */ |
|
1196 |
|
1197 TRfcommStateListening::TRfcommStateListening(CRfcommStateFactory& aFactory) |
|
1198 : TRfcommStateDefault(aFactory) |
|
1199 { |
|
1200 STATENAME("Listening"); |
|
1201 } |
|
1202 |
|
1203 void TRfcommStateListening::Enter(CRfcommSAP& aSAP) |
|
1204 /** |
|
1205 The SAP is entering the listening state. The protocol needs to know. |
|
1206 **/ |
|
1207 { |
|
1208 aSAP.iProtocol.AddIdleSAP(aSAP); |
|
1209 aSAP.iProtocol.RemoveBoundSAP(aSAP); |
|
1210 } |
|
1211 |
|
1212 void TRfcommStateListening::Exit(CRfcommSAP& aSAP) |
|
1213 { |
|
1214 aSAP.DeregisterCodService(); // See if there is a Service to remove for CodMan |
|
1215 aSAP.StopListening(); |
|
1216 } |
|
1217 |
|
1218 void TRfcommStateListening::SABM(CRfcommSAP& aSAP, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
1219 /** |
|
1220 A SABM sent to a listening SAP means we need create a clone SAP |
|
1221 **/ |
|
1222 { |
|
1223 // NB. The criteria of the following assert will vary for the different states |
|
1224 // that this function gets called in. |
|
1225 __ASSERT_DEBUG(aDLCI!=0, PanicInState(ERfcommBadDLCIForClone)); |
|
1226 |
|
1227 CRfcommSAP* newSAP=AttemptToClone(aSAP, aMux, aDLCI); |
|
1228 if(newSAP) |
|
1229 newSAP->SABM(aMux, aDLCI); |
|
1230 } |
|
1231 |
|
1232 void TRfcommStateListening::PN(CRfcommSAP& aSAP, TRfcommPortParams& aParams, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
1233 /** |
|
1234 A PN sent to a listening SAP means we need create a clone SAP |
|
1235 **/ |
|
1236 { |
|
1237 // NB. The criteria of the following assert will vary for the different states |
|
1238 // that this function gets called in. |
|
1239 __ASSERT_DEBUG(aDLCI!=0, PanicInState(ERfcommBadDLCIForClone)); |
|
1240 |
|
1241 CRfcommSAP* newSAP=AttemptToClone(aSAP, aMux, aDLCI); |
|
1242 if(newSAP) |
|
1243 { |
|
1244 newSAP->PN(aParams, aMux, aDLCI); |
|
1245 } |
|
1246 else |
|
1247 { |
|
1248 // Uh Oh! Couldn't get a SAP, don't worry too much - a DM has been sent |
|
1249 LOG(_L("[rfcommstates.cpp]: Couldn't clone a SAP after receiving a PN\n")); |
|
1250 } |
|
1251 } |
|
1252 |
|
1253 void TRfcommStateListening::RPN(CRfcommSAP& aSAP, const TRfcommRPNTransaction& aRPNTransaction, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
1254 /** |
|
1255 A RPN sent to a listening SAP means we need create a clone SAP |
|
1256 **/ |
|
1257 { |
|
1258 __ASSERT_DEBUG(aDLCI!=0, PanicInState(ERfcommBadDLCIForClone)); |
|
1259 |
|
1260 CRfcommSAP* newSAP=AttemptToClone(aSAP, aMux, aDLCI); |
|
1261 if(newSAP) |
|
1262 { |
|
1263 newSAP->RPN(&aRPNTransaction, aMux, aDLCI); |
|
1264 } |
|
1265 else |
|
1266 { |
|
1267 // Uh Oh! Couldn't get a SAP, don't worry too much - a DM has been sent |
|
1268 LOG(_L("[rfcommstates.cpp]: Couldn't clone a SAP after receiving a RPN\n")); |
|
1269 } |
|
1270 } |
|
1271 |
|
1272 void TRfcommStateListening::Shutdown(CRfcommSAP& aSAP) |
|
1273 { |
|
1274 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1275 aSAP.iSocket->CanClose(); |
|
1276 } |
|
1277 |
|
1278 void TRfcommStateListening::FastShutdown(CRfcommSAP& aSAP) |
|
1279 { |
|
1280 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1281 } |
|
1282 |
|
1283 CRfcommSAP* TRfcommStateListening::AttemptToClone(CRfcommSAP& aSAP, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
1284 /** |
|
1285 Utility function private to TRfcommStateListening which attempts to create a cloned SAP |
|
1286 |
|
1287 @param aSAP The SAP to be cloned |
|
1288 @param aMux The Muxer to attach it to |
|
1289 @param aDLCI The DLCI of the cloned SAP |
|
1290 **/ |
|
1291 { |
|
1292 CRfcommSAP* newSAP=aSAP.CloneMe(); |
|
1293 |
|
1294 if(!newSAP) |
|
1295 { |
|
1296 // A new clone could not be created - send a DM, game over |
|
1297 aMux.SendDM(aDLCI); |
|
1298 } |
|
1299 else |
|
1300 { |
|
1301 // Set up details of the new identity of the clone |
|
1302 |
|
1303 // Put it in WaitForSABM state |
|
1304 newSAP->iState=iFactory.GetState(CRfcommStateFactory::EWaitForSABM); |
|
1305 newSAP->iState->Enter(*newSAP); |
|
1306 |
|
1307 newSAP->iSignals=aSAP.iSignals; |
|
1308 newSAP->iDLCI=aDLCI; |
|
1309 newSAP->iServerChannel=aMux.MakeServerChannel(aDLCI); |
|
1310 newSAP->iRemoteDev=aMux.RemoteBTAddr(); |
|
1311 // Must come after registering the remote address with the new SAP because we will need |
|
1312 // the remote address to find a link in LinkMgrProtocol to override LPM on |
|
1313 newSAP->iProtocol.ControlPlane().ModifyPhysicalLink(EOverrideLPMWithTimeout, newSAP->iRemoteDev); |
|
1314 newSAP->iUserDefinedMTU=aSAP.iUserDefinedMTU; // We take our cues as |
|
1315 // regards max MTU from |
|
1316 // the listening SAP. |
|
1317 |
|
1318 newSAP->iMux=&aMux; |
|
1319 // NB. The listening SAP retains ownership of the SAP until it sends a |
|
1320 // ConnectComplete up for it. |
|
1321 aMux.AddSAP(*newSAP); |
|
1322 } |
|
1323 |
|
1324 return newSAP; |
|
1325 } |
|
1326 |
|
1327 TInt TRfcommStateListening::SetOption(CRfcommSAP &aSAP, TUint aLevel, |
|
1328 TUint aName, const TDesC8& aOption) |
|
1329 /** |
|
1330 Allow modem status to be modified whilst we are listening. |
|
1331 **/ |
|
1332 { |
|
1333 if(aLevel == KSolBtRFCOMM && aName == KRFCOMMLocalModemStatus) |
|
1334 { |
|
1335 if ( aOption.Length() != sizeof(TUint8) ) |
|
1336 { |
|
1337 return KErrArgument; |
|
1338 } |
|
1339 else |
|
1340 { |
|
1341 TPckgBuf<TUint8> signals; |
|
1342 signals.Copy(aOption); |
|
1343 aSAP.iSignals = signals(); |
|
1344 return KErrNone; |
|
1345 } |
|
1346 } |
|
1347 |
|
1348 return TRfcommStateDefault::SetOption(aSAP, aLevel, aName, aOption); |
|
1349 } |
|
1350 |
|
1351 /*****************************************************************/ |
|
1352 /* |
|
1353 The cloned base state |
|
1354 */ |
|
1355 |
|
1356 TRfcommStateCloned::TRfcommStateCloned(CRfcommStateFactory& aFactory) |
|
1357 : TRfcommStateDefault(aFactory) |
|
1358 { |
|
1359 } |
|
1360 |
|
1361 void TRfcommStateCloned::LinkDown(CRfcommSAP& aSAP) |
|
1362 { |
|
1363 aSAP.iParentSAP->ChildConnectFailed(aSAP); |
|
1364 } |
|
1365 |
|
1366 void TRfcommStateCloned::Error(CRfcommSAP& aSAP, TInt /*aErr*/, |
|
1367 CRfcommSAP::TErrorTypes /*aType*/) |
|
1368 { |
|
1369 aSAP.iParentSAP->ChildConnectFailed(aSAP); // Will delete us... |
|
1370 } |
|
1371 |
|
1372 void TRfcommStateCloned::DISC(CRfcommSAP& aSAP) |
|
1373 /** |
|
1374 DISC, so the other end wants us to go away. |
|
1375 |
|
1376 Kill ourselves after acknowledging it. |
|
1377 **/ |
|
1378 { |
|
1379 aSAP.iMux->SendUA(aSAP.DLCI()); // Send a UA which will outlive this SAP |
|
1380 aSAP.iParentSAP->ChildConnectFailed(aSAP); |
|
1381 } |
|
1382 |
|
1383 void TRfcommStateCloned::DM(CRfcommSAP& aSAP) |
|
1384 /** |
|
1385 We've got a DM in, which means that something's wrong. |
|
1386 |
|
1387 We'll junk this connection, since we should not get a DM as we |
|
1388 haven't sent any commands. The other end is obviously very |
|
1389 confused. |
|
1390 **/ |
|
1391 { |
|
1392 aSAP.iParentSAP->ChildConnectFailed(aSAP); |
|
1393 } |
|
1394 |
|
1395 /******************************************************************/ |
|
1396 /* |
|
1397 The Wait For SABM state. |
|
1398 |
|
1399 (The intial state of a cloned SAP) |
|
1400 */ |
|
1401 |
|
1402 TRfcommStateWaitForSABM::TRfcommStateWaitForSABM(CRfcommStateFactory& aFactory) |
|
1403 : TRfcommStateCloned(aFactory) |
|
1404 { |
|
1405 STATENAME("WaitForSABM"); |
|
1406 } |
|
1407 |
|
1408 void TRfcommStateWaitForSABM::SABM(CRfcommSAP& aSAP, CRfcommMuxer& aMux, TUint8 aDLCI) |
|
1409 /** |
|
1410 We received a SABM - Tell our parent SAP that we're connected |
|
1411 **/ |
|
1412 { |
|
1413 if(aSAP.iMTU==0) // i.e. We've not entered into any negotiations... |
|
1414 aSAP.iMTU=KRfcommDefaultMTU; // ...so set to default. |
|
1415 |
|
1416 // We can set up the Data Buffer since MTU negotiations are now over. |
|
1417 //TRAPD(err, aSAP.iDataBuffer.SetLengthL(KRfcommSAPBufferMultiple*aSAP.iMTU)); |
|
1418 TRAPD(err, |
|
1419 aSAP.iDataBuffer.SetLengthL(aMux.FlowStrategy()->DataBufferMultiple()* |
|
1420 aSAP.iMTU)); |
|
1421 if(err != KErrNone) |
|
1422 { |
|
1423 // Failed to alloc, so fail this connect and error |
|
1424 aMux.SendDM(aDLCI); |
|
1425 aSAP.iParentSAP->ChildConnectFailed(aSAP); // Will delete us... |
|
1426 return; |
|
1427 } |
|
1428 |
|
1429 aSAP.iHighTideMark=KRfcommSAPBufferHighMultiple*(aSAP.iMTU); |
|
1430 aSAP.iLowTideMark=KRfcommSAPBufferLowMultiple*(aSAP.iMTU); |
|
1431 |
|
1432 ChangeState(aSAP,CRfcommStateFactory::EWaitForIncomingSecurityCheck); |
|
1433 } |
|
1434 |
|
1435 #ifndef _DEBUG |
|
1436 void TRfcommStateWaitForSABM::PN(CRfcommSAP& aSAP, TRfcommPortParams& aParams, |
|
1437 CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
1438 #else |
|
1439 void TRfcommStateWaitForSABM::PN(CRfcommSAP& aSAP, TRfcommPortParams& aParams, |
|
1440 CRfcommMuxer& aMux, TUint8 /*aDLCI*/) |
|
1441 #endif |
|
1442 { |
|
1443 __ASSERT_DEBUG(aSAP.iMux==&aMux,PanicInState(ERfcommInvalidMuxInSAP)); |
|
1444 if(aSAP.iMTU==0) |
|
1445 { |
|
1446 // We have no MTU set for the SAP at the moment. Try to determine |
|
1447 // the upper limit of what we can handle |
|
1448 aSAP.iMTU=aSAP.MaximumMTU(); |
|
1449 } |
|
1450 |
|
1451 if(aParams.iMaxFrameSize>aSAP.iMTU || aParams.iMaxFrameSize<=0) |
|
1452 { |
|
1453 // Either the remote device wants a larger MTU or has provided us |
|
1454 // with a nonsensical <=0 one. |
|
1455 // Either way, try to negotiate the MTU to our maximum |
|
1456 aParams.iMaxFrameSize=aSAP.iMTU; |
|
1457 } |
|
1458 else |
|
1459 { |
|
1460 |
|
1461 // We have an MTU value so ask L2Cap to work out the optimal MTU value based on the one |
|
1462 // received from the remote. Note that the Max Frame Size is the max data size for Rfcomm |
|
1463 // so we need to add on the max Rfcomm header size to create the restriction on L2Cap |
|
1464 // MTU. |
|
1465 TPckgBuf<TInt> restrictedMtu(aParams.iMaxFrameSize + KMaxFrameOverhead); |
|
1466 TInt err = aSAP.GetOption(KSolBtL2CAP, KL2CAPOutboundMTUForBestPerformanceWithRestriction, restrictedMtu); |
|
1467 |
|
1468 |
|
1469 // If we get an error continue but with a possible non-optimal MTU value. iMTU is the max |
|
1470 // data size so remove the max Rfcomm header size as these will get added later. |
|
1471 aSAP.iMTU = (err == KErrNone) ? restrictedMtu() - KMaxFrameOverhead : aParams.iMaxFrameSize; |
|
1472 } |
|
1473 |
|
1474 if(aParams.iCreditIndicator == (KCBFCCommandFlag >> 4)) |
|
1475 { |
|
1476 // Remote device is using CBFC. Set up the credit counts |
|
1477 aSAP.SetInitialLocalCredit(aParams.iInitialCredit); // Credits we've just been given |
|
1478 |
|
1479 // now set to the credits we will give them |
|
1480 aParams.iInitialCredit = aSAP.iMux->FlowStrategy()->PNFinalOctet(); |
|
1481 aSAP.SetProxyForRemoteCredit(aParams.iInitialCredit); // and record it |
|
1482 } |
|
1483 |
|
1484 aSAP.iMux->SendPNResponse(aSAP, aParams); |
|
1485 } |
|
1486 |
|
1487 void TRfcommStateWaitForSABM::RPN(CRfcommSAP& aSAP, const TRfcommRPNTransaction& aRPNTransaction, |
|
1488 CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
1489 { |
|
1490 // Write whatever's changed into our local port params. |
|
1491 aSAP.iLocalPortParams.UpdateFromRPNTransaction(aRPNTransaction); |
|
1492 |
|
1493 // Send L2CAP exactly what they sent us, except this is a response |
|
1494 aSAP.iMux->SendRPN(aSAP, EFalse, KRPNResponseLength, aRPNTransaction); |
|
1495 |
|
1496 // Don't bother telling the user. If they're interested they'll just have |
|
1497 // to keep doing getOpts whenever they feel like it! |
|
1498 } |
|
1499 |
|
1500 void TRfcommStateWaitForSABM::MuxUp(CRfcommSAP& /*aSAP*/) |
|
1501 { |
|
1502 // Do nothing - included because the default class will panic. |
|
1503 } |
|
1504 |
|
1505 |
|
1506 /******************************************************************/ |
|
1507 /* |
|
1508 The Incoming Security Check state. |
|
1509 |
|
1510 Handles making and responding to a security check on the security manager. |
|
1511 |
|
1512 */ |
|
1513 |
|
1514 TRfcommStateIncomingSecurityCheck::TRfcommStateIncomingSecurityCheck(CRfcommStateFactory& aFactory) |
|
1515 : TRfcommStateCloned(aFactory) |
|
1516 { |
|
1517 STATENAME("IncomingSecurityCheck"); |
|
1518 } |
|
1519 |
|
1520 void TRfcommStateIncomingSecurityCheck::Enter(CRfcommSAP& aSAP) |
|
1521 { |
|
1522 // INCOMING security |
|
1523 // The listening SAP has the security settings, and possible device overrides |
|
1524 aSAP.StartAccessRequest(aSAP.ListeningSAP()); |
|
1525 } |
|
1526 |
|
1527 void TRfcommStateIncomingSecurityCheck::AccessRequestComplete(CRfcommSAP& aSAP, TInt aResult) |
|
1528 { |
|
1529 if(aResult==KErrNone) |
|
1530 { |
|
1531 LOG1(_L("RFCOMM: Access Request Successful (DLCI %d)"), aSAP.DLCI()); |
|
1532 ChangeState(aSAP, CRfcommStateFactory::EWaitForStart); |
|
1533 } |
|
1534 else |
|
1535 {// Something is not well - inform our parent. |
|
1536 // This will result in us being deleted, so send DM for the DLCI |
|
1537 LOG2(_L("RFCOMM: Access Request Failed (DLCI %d, Error %d)"), aSAP.DLCI(),aResult); |
|
1538 aSAP.iMux->SendDM(aSAP.DLCI()); |
|
1539 aSAP.iParentSAP->ChildConnectFailed(aSAP); |
|
1540 } |
|
1541 } |
|
1542 |
|
1543 void TRfcommStateIncomingSecurityCheck::Exit(CRfcommSAP& aSAP) |
|
1544 { |
|
1545 aSAP.CancelAccessRequest(); |
|
1546 } |
|
1547 |
|
1548 /******************************************************************/ |
|
1549 /* |
|
1550 The Outgoing Security Check state. |
|
1551 |
|
1552 Handles making and responding to a security check on the security manager. |
|
1553 |
|
1554 */ |
|
1555 |
|
1556 TRfcommStateOutgoingSecurityCheck::TRfcommStateOutgoingSecurityCheck(CRfcommStateFactory& aFactory) |
|
1557 : TRfcommStateConnecting(aFactory) |
|
1558 { |
|
1559 STATENAME("OutgoingSecurityCheck"); |
|
1560 } |
|
1561 |
|
1562 void TRfcommStateOutgoingSecurityCheck::Enter(CRfcommSAP& aSAP) |
|
1563 { |
|
1564 // Outgoing security |
|
1565 // The listening SAP has the security settings, and possible device overrides |
|
1566 aSAP.StartAccessRequest(aSAP); |
|
1567 } |
|
1568 |
|
1569 void TRfcommStateOutgoingSecurityCheck::AccessRequestComplete(CRfcommSAP& aSAP, TInt aResult) |
|
1570 { |
|
1571 if(aResult==EBTSecManAccessGranted) |
|
1572 { |
|
1573 LOG1(_L("RFCOMM: Access Request Successful (DLCI %d)"), aSAP.DLCI()); |
|
1574 aResult = aSAP.iMux->SendSABM(aSAP); |
|
1575 } |
|
1576 |
|
1577 if (aResult < KErrNone || aResult == EBTSecManAccessDenied) |
|
1578 {// Something is not well - inform our parent. |
|
1579 // This will result in us being deleted, so send DM for the DLCI |
|
1580 LOG2(_L("RFCOMM: Outgoing security Failed (DLCI %d, Error %d)"), aSAP.DLCI(),aResult); |
|
1581 FailureWhileConnecting(aSAP, KErrCouldNotConnect); |
|
1582 } |
|
1583 else |
|
1584 { |
|
1585 ChangeState(aSAP, CRfcommStateFactory::EWaitForUA); |
|
1586 } |
|
1587 } |
|
1588 |
|
1589 void TRfcommStateOutgoingSecurityCheck::Exit(CRfcommSAP& aSAP) |
|
1590 { |
|
1591 aSAP.CancelAccessRequest(); |
|
1592 } |
|
1593 |
|
1594 |
|
1595 /******************************************************************/ |
|
1596 /* |
|
1597 The Wait For Start state. |
|
1598 |
|
1599 */ |
|
1600 |
|
1601 TRfcommStateWaitForStart::TRfcommStateWaitForStart(CRfcommStateFactory& aFactory) |
|
1602 : TRfcommStateDefault(aFactory) |
|
1603 { |
|
1604 STATENAME("WaitForStart"); |
|
1605 } |
|
1606 |
|
1607 void TRfcommStateWaitForStart::Enter(CRfcommSAP &aSAP) |
|
1608 { |
|
1609 // NB. The following line effectively passes ownership of aSAP away from |
|
1610 // the parent SAP to ESOCK |
|
1611 aSAP.iParentSAP->ChildConnected(aSAP); |
|
1612 } |
|
1613 |
|
1614 void TRfcommStateWaitForStart::Start(CRfcommSAP& aSAP) |
|
1615 /** |
|
1616 Start has been called on us. Move to the open state. |
|
1617 **/ |
|
1618 { |
|
1619 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1620 if(aSAP.iParentSAP!=NULL) |
|
1621 { |
|
1622 // We still have an extant parent listening SAP. |
|
1623 // Let them know that we have been started so that they can |
|
1624 // accept more cloned SAPs into the WaitForStart state. |
|
1625 aSAP.iParentSAP->ChildStarted(aSAP); |
|
1626 } |
|
1627 aSAP.iMux->SendUA(aSAP); |
|
1628 |
|
1629 ChangeState(aSAP, CRfcommStateFactory::EOpen); |
|
1630 } |
|
1631 |
|
1632 void TRfcommStateWaitForStart::DISC(CRfcommSAP& aSAP) |
|
1633 /** |
|
1634 We are waiting for a Start, but the remote device has decided to disconnect us. |
|
1635 |
|
1636 Send a UA, and enter the CloseOnStart state. |
|
1637 **/ |
|
1638 { |
|
1639 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1640 aSAP.iMux->SendUA(aSAP.DLCI()); |
|
1641 aSAP.iMux->DetachSAP(aSAP); // Because we're just waiting about for a Start |
|
1642 // from above - we're not interested in what is |
|
1643 // coming in from below (esp. LinkDown notification). |
|
1644 ChangeState(aSAP,CRfcommStateFactory::ECloseOnStart); |
|
1645 } |
|
1646 |
|
1647 void TRfcommStateWaitForStart::Error(CRfcommSAP& aSAP, TInt /*aErr*/, |
|
1648 CRfcommSAP::TErrorTypes /*aType*/) |
|
1649 { |
|
1650 // We can't really do anything at this point with an error, |
|
1651 // because ESOCK knows about us. Therefore, the best we can |
|
1652 // do is to move into CloseOnStart state. |
|
1653 ChangeState(aSAP,CRfcommStateFactory::ECloseOnStart); |
|
1654 } |
|
1655 |
|
1656 /******************************************************************/ |
|
1657 /* |
|
1658 The Close On Start state. |
|
1659 |
|
1660 For when a SAP triggers a ConnectComplete, but receives a remote DISC |
|
1661 before it receives a local Start. |
|
1662 */ |
|
1663 |
|
1664 TRfcommStateCloseOnStart::TRfcommStateCloseOnStart(CRfcommStateFactory& aFactory) |
|
1665 : TRfcommStateDefault(aFactory) |
|
1666 { |
|
1667 STATENAME("CloseOnStart"); |
|
1668 } |
|
1669 |
|
1670 void TRfcommStateCloseOnStart::Start(CRfcommSAP& aSAP) |
|
1671 { |
|
1672 // NB. The Disconnect() invalidates the cloned SAP on ESOCKs |
|
1673 // accept queue - however, a client side Accept() will still be |
|
1674 // completed with KErrNone. The first read or write will be |
|
1675 // completed with KErrDisconnected. |
|
1676 // |
|
1677 aSAP.iSocket->Disconnect(); |
|
1678 |
|
1679 if(aSAP.iParentSAP!=NULL) |
|
1680 { |
|
1681 // We still have an extant parent listening SAP. |
|
1682 // Let them know that we have been started so that they can |
|
1683 // accept more cloned SAPs into the WaitForStart state. |
|
1684 aSAP.iParentSAP->ChildStarted(aSAP); |
|
1685 } |
|
1686 |
|
1687 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1688 } |
|
1689 |
|
1690 void TRfcommStateCloseOnStart::Error(CRfcommSAP& /*aSAP*/, TInt /*aErr*/, |
|
1691 CRfcommSAP::TErrorTypes /*aType*/) |
|
1692 { |
|
1693 // Nothing we can really do with this error, since we're already |
|
1694 // going to close on start. |
|
1695 } |
|
1696 |
|
1697 |
|
1698 /******************************************************************/ |
|
1699 /* |
|
1700 The open state. |
|
1701 |
|
1702 Here all the data xfer and flow control is handled. |
|
1703 */ |
|
1704 |
|
1705 TRfcommStateOpen::TRfcommStateOpen(CRfcommStateFactory& aFactory) |
|
1706 : TRfcommStateDefault(aFactory) |
|
1707 { |
|
1708 STATENAME("Open"); |
|
1709 } |
|
1710 |
|
1711 void TRfcommStateOpen::Enter(CRfcommSAP& aSAP) |
|
1712 /** |
|
1713 We've entered the open state, so tell the SAP. |
|
1714 **/ |
|
1715 { |
|
1716 // If this fails what happens? |
|
1717 TInt err=aSAP.iMux->SendMSC(aSAP, aSAP.iSignals); |
|
1718 if(err != KErrNone) |
|
1719 { |
|
1720 // Failed to alloc, so fail this connect and error |
|
1721 SignalError(aSAP, err, MSocketNotify::EErrorConnect); |
|
1722 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1723 return; |
|
1724 } |
|
1725 |
|
1726 aSAP.iProtocol.ControlPlane().ModifyPhysicalLink(EUndoOverridePark, aSAP.iRemoteDev); |
|
1727 aSAP.iSocket->ConnectComplete(); |
|
1728 aSAP.CTS(EFalse); // So that we block should anyone try to write |
|
1729 // anything through this SAP before we get MSC |
|
1730 // from remote side. |
|
1731 aSAP.iReceivedMSC=EFalse; // Until we receive an MSC, we consider any |
|
1732 // user data we receive as being a bit naughty |
|
1733 // (other device is non 7.10 compliant) |
|
1734 } |
|
1735 |
|
1736 void TRfcommStateOpen::PerformDataAwareStateChange(CRfcommSAP& aSAP) |
|
1737 { |
|
1738 if(aSAP.iNewDataToNotify) |
|
1739 { |
|
1740 // We have outstanding data, so move to a half-closed state |
|
1741 // where stuff can be read out but not sent |
|
1742 ChangeState(aSAP, CRfcommStateFactory::EDisconnecting); |
|
1743 } |
|
1744 else |
|
1745 { |
|
1746 // Now call DisConnect(). Eventually this sap will be cleared up. |
|
1747 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1748 aSAP.iSocket->Disconnect(); |
|
1749 } |
|
1750 } |
|
1751 |
|
1752 |
|
1753 void TRfcommStateOpen::Exit(CRfcommSAP& aSAP) |
|
1754 /** |
|
1755 Exit the open channel |
|
1756 **/ |
|
1757 { |
|
1758 aSAP.DeregisterCodService(); // See if there is a Service to remove for CodMan |
|
1759 } |
|
1760 |
|
1761 |
|
1762 void TRfcommStateOpen::Shutdown(CRfcommSAP& aSAP) |
|
1763 /** |
|
1764 Shutdown the open channel gracefully |
|
1765 **/ |
|
1766 { |
|
1767 aSAP.iProtocol.ControlPlane().ModifyPhysicalLink(EOverridePark, aSAP.iRemoteDev); |
|
1768 aSAP.iClosePending=ETrue; |
|
1769 ChangeState(aSAP, CRfcommStateFactory::EDisconnect); |
|
1770 } |
|
1771 |
|
1772 void TRfcommStateOpen::FastShutdown(CRfcommSAP& aSAP) |
|
1773 /** |
|
1774 Terminate the session with extreme prejudice :-) |
|
1775 |
|
1776 Send a disconnect, but don't bother to wait around since we'll |
|
1777 be deleted by our owner when this call returns. |
|
1778 **/ |
|
1779 { |
|
1780 // Send a DISC using the DLCI based overload which ensures that |
|
1781 // the queued DISC frame does not get deleted when the SAP gets |
|
1782 // removed from the muxer |
|
1783 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1784 aSAP.iProtocol.ControlPlane().ModifyPhysicalLink(EOverridePark, aSAP.iRemoteDev); |
|
1785 aSAP.iMux->SendDISC(aSAP.DLCI()); // Disassociated from the SAP |
|
1786 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1787 } |
|
1788 |
|
1789 TInt TRfcommStateOpen::Send(CRfcommSAP& aSAP, const TDesC8& aData) |
|
1790 /** |
|
1791 Attempt to send some data. |
|
1792 |
|
1793 We fragment the data and issue writes to the mux. Keep going |
|
1794 until either the mux tells us to back off, or until all the |
|
1795 data has been sent. |
|
1796 |
|
1797 We also obey our flow control setting, so we only send if we |
|
1798 are clear to send |
|
1799 |
|
1800 Note that when we fail to send all the data, ESOCK will keep |
|
1801 calling us until we return zero before marking us as blocked. |
|
1802 Therefore we have to check if we're blocked before trying to |
|
1803 send anything. |
|
1804 |
|
1805 @return Length of data actually sent |
|
1806 **/ |
|
1807 { |
|
1808 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1809 |
|
1810 TInt len=0; // Current amount we've sent. |
|
1811 TInt fraglen; |
|
1812 TInt sentlen=0; |
|
1813 |
|
1814 if(!aSAP.SendBlocked()) |
|
1815 { |
|
1816 if(aSAP.CTS()) //FIXME???? make general to accommodate CBFC as well |
|
1817 { |
|
1818 while(len < aData.Length()) |
|
1819 { |
|
1820 //NB1 0 if !CBFC |
|
1821 //NB2 A successful 'Write' will update this value for next loop. |
|
1822 TUint8 credit = aSAP.Mux()->FlowStrategy()->WriteCredit(aSAP); |
|
1823 fraglen=Min(aData.Length()-len, STATIC_CAST(TInt, aSAP.UsableMTU(credit))); |
|
1824 if(aSAP.iMux->FlowStrategy()->AllowWrite(aSAP)) |
|
1825 sentlen=aSAP.iMux->Write(aSAP, credit, aData.Mid(len,fraglen)); |
|
1826 else |
|
1827 sentlen=0; |
|
1828 len+=sentlen; |
|
1829 if(sentlen != fraglen) |
|
1830 { |
|
1831 // We failed to send all the data we wanted to, so |
|
1832 // we're now blocked from sending, and must wait for a |
|
1833 // notification that we can send again. |
|
1834 aSAP.SendBlocked(aSAP.SendBlocked() | CRfcommSAP::EBlockedByMux); |
|
1835 break; |
|
1836 } |
|
1837 } |
|
1838 } |
|
1839 else |
|
1840 { |
|
1841 // We're not clear to send to the other end, so back off ESOCK |
|
1842 aSAP.SendBlocked(aSAP.SendBlocked() | CRfcommSAP::EBlockedByRemote); |
|
1843 } |
|
1844 } |
|
1845 return len; |
|
1846 } |
|
1847 |
|
1848 void TRfcommStateOpen::Read(CRfcommSAP& aSAP, TDesC8& aData) |
|
1849 /** |
|
1850 Read some data. |
|
1851 |
|
1852 This is filled from the circular buffer of incoming data. |
|
1853 **/ |
|
1854 { |
|
1855 __ASSERT_DEBUG(aSAP.DataBuffer().Count() >= aData.Length(), |
|
1856 PanicInState(ERfcommReadForTooMuchData)); |
|
1857 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1858 LOG1(_L("RFCOMM: Read of %d bytes"), aData.Length()); |
|
1859 |
|
1860 aSAP.DataBuffer().Remove(const_cast<TUint8*>(aData.Ptr()), aData.Length()); |
|
1861 //TRY_CBFC |
|
1862 aSAP.iMux->FlowStrategy()->UpdateRxFlowControlState(aSAP); |
|
1863 //FIXED_ME removed flow control code to flow strategy |
|
1864 } |
|
1865 |
|
1866 void TRfcommStateOpen::NewData(CRfcommSAP& aSAP, const TDesC8& aData) |
|
1867 /** |
|
1868 New data has come in. |
|
1869 |
|
1870 Store it in a buffer, and signal the socket to get it. |
|
1871 **/ |
|
1872 { |
|
1873 LOG1(_L("RFCOMM: New data length %d"), aData.Length()); |
|
1874 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
1875 __ASSERT_DEBUG(aData.Length() <= aSAP.iMux->GetMaxDataSize(), PanicInState(ERfcommDataPacketTooLong)); |
|
1876 |
|
1877 if(!aSAP.iReceivedMSC) |
|
1878 { |
|
1879 // We're dealing with a rather naughty non-7.10-compliant |
|
1880 // RFCOMM implementation which doesn't send an MSC before |
|
1881 // sending it's data. Note this fact and continue. |
|
1882 LOG(_L("RFCOMM: Warning received data before MSC on new connection!")); |
|
1883 } |
|
1884 //TRY_CBFC |
|
1885 if (!aSAP.iMux->FlowStrategy()->NewDataReviseCredits(aSAP, aData)) // ...the remote has overflowed us... |
|
1886 { |
|
1887 // remote is ignoring flow control decide whether to disconnect or drop packets (if using CBFC) |
|
1888 if (aSAP.iMux->FlowStrategy()->FlowType() == CRfcommFlowStrategyFactory::EFlowCreditBased && |
|
1889 aSAP.iForgiveCBFCOverflow) |
|
1890 { |
|
1891 //drop packet - l2cap frees the underlying packet storage |
|
1892 return; |
|
1893 } |
|
1894 else |
|
1895 { |
|
1896 aSAP.iSocket->Disconnect(); |
|
1897 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
1898 return; |
|
1899 } |
|
1900 } |
|
1901 |
|
1902 TInt storelen=aSAP.DataBuffer().Add(aData.Ptr(), aData.Length()); |
|
1903 if(storelen != aData.Length()) |
|
1904 { |
|
1905 // We've not got room for some of the data |
|
1906 LOG(_L("RFCOMM: Warning received data loss")); |
|
1907 } |
|
1908 |
|
1909 // Check to see if we need to quench the source |
|
1910 LOG1(_L("RFCOMM: Data buffer level %d"), aSAP.DataBuffer().Count()); |
|
1911 |
|
1912 aSAP.iMux->FlowStrategy()->NewData(aSAP); |
|
1913 //FIXED-ME flow code block removed to strategy object (applies non CBFC flow only). |
|
1914 |
|
1915 if(storelen) |
|
1916 { |
|
1917 aSAP.iNewDataToNotify += storelen; |
|
1918 aSAP.iNotifyNewDataCallback->CallBack(); |
|
1919 } |
|
1920 } |
|
1921 |
|
1922 void TRfcommStateOpen::NotifyNewDataCallback(CRfcommSAP& aSAP) |
|
1923 { |
|
1924 TInt newData = aSAP.iNewDataToNotify; |
|
1925 if (newData) |
|
1926 { |
|
1927 aSAP.iNewDataToNotify = 0; |
|
1928 LOG1(_L("RFCOMM: Actually telling Socket of newdata %d bytes"), newData); |
|
1929 aSAP.iSocket->NewData(newData); |
|
1930 } |
|
1931 aSAP.iMux->FlowStrategy()->UpdateRxFlowControlState(aSAP); |
|
1932 } |
|
1933 |
|
1934 void TRfcommStateOpen::CanSend(CRfcommSAP& aSAP) |
|
1935 /** |
|
1936 SAP is now clear to try to send data again (maybe) since these |
|
1937 can be sent any time. |
|
1938 |
|
1939 Notify the socket. |
|
1940 **/ |
|
1941 { |
|
1942 |
|
1943 __ASSERT_DEBUG(aSAP.SendBlocked() & CRfcommSAP::EBlockedByMux, PanicInState(ERfcommUnexpectedCanSend)); |
|
1944 |
|
1945 aSAP.SendBlocked(aSAP.SendBlocked() & ~CRfcommSAP::EBlockedByMux); |
|
1946 aSAP.iSocket->CanSend(); |
|
1947 } |
|
1948 |
|
1949 void TRfcommStateOpen::MSC(CRfcommSAP& aSAP, TUint8 aSignals) |
|
1950 /** |
|
1951 Modem signals received from the remote end. |
|
1952 The only bit we're really interested in is the FC bit but we store |
|
1953 the rest anyway in case anyone above wants to read it (see GetOpt) |
|
1954 **/ |
|
1955 { |
|
1956 aSAP.iRemoteModemStatus = aSignals; |
|
1957 |
|
1958 aSAP.iReceivedMSC=ETrue; |
|
1959 |
|
1960 //FC |
|
1961 if(aSAP.iMux->FlowStrategy()->MSC(aSAP, aSignals)) |
|
1962 { |
|
1963 aSAP.SendBlocked(aSAP.SendBlocked() & ~CRfcommSAP::EBlockedByRemote); |
|
1964 aSAP.iSocket->CanSend(); |
|
1965 } |
|
1966 // |
|
1967 |
|
1968 // Indication of config change |
|
1969 IoctlComplete(aSAP, KErrNone, KSolBtRFCOMM, KRFCOMMConfigChangeIndicationIoctl, NULL); |
|
1970 |
|
1971 // If there has been a signal status to watch for set, and this is it, then we send a disconnect error to the client reader |
|
1972 if(aSAP.iDisconnectMSCSignal && aSAP.iDisconnectMSCSignal == aSignals) |
|
1973 { |
|
1974 SignalError(aSAP, KErrDisconnected, MSocketNotify::EErrorRecv); |
|
1975 } |
|
1976 } |
|
1977 |
|
1978 void TRfcommStateOpen::RLS(CRfcommSAP& aSAP, TUint8 aStatus) |
|
1979 // Remote Line Status command received from remote end |
|
1980 // Just set the SAP's local copy |
|
1981 { |
|
1982 aSAP.iRLSstatus = aStatus; |
|
1983 // Indication of config change |
|
1984 IoctlComplete(aSAP, KErrNone, KSolBtRFCOMM, KRFCOMMConfigChangeIndicationIoctl, NULL); |
|
1985 } |
|
1986 |
|
1987 |
|
1988 void TRfcommStateOpen::DISC(CRfcommSAP& aSAP) |
|
1989 /** |
|
1990 The remote end has sent a DISC. We need to respond. |
|
1991 |
|
1992 Q: What do we do about any data in our buffers? |
|
1993 A: Q the UA in order, so that all data in our buffers is |
|
1994 flushed before the UA is sent. |
|
1995 **/ |
|
1996 { |
|
1997 // Use the DLCI based overload of SendUA, which ensures that the queued |
|
1998 // frame has no SAP set. |
|
1999 // This ensures that the frame does not get deleted when this SAP is detached |
|
2000 // from the muxer, when we enter the Closed state. |
|
2001 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
2002 aSAP.iMux->SendUA(aSAP.DLCI()); // If this fails there's not much we can do |
|
2003 PerformDataAwareStateChange(aSAP); |
|
2004 } |
|
2005 |
|
2006 |
|
2007 void TRfcommStateOpen::DM(CRfcommSAP& aSAP) |
|
2008 /** |
|
2009 A DM, which means the other end has gone away. |
|
2010 |
|
2011 Time to error everything. |
|
2012 **/ |
|
2013 { |
|
2014 SignalError(aSAP, KErrDisconnected, MSocketNotify::EErrorAllOperations); |
|
2015 } |
|
2016 |
|
2017 void TRfcommStateOpen::RPN(CRfcommSAP& aSAP, const TRfcommRPNTransaction& aRPNTransaction, CRfcommMuxer& /*aMuxer*/, TUint8 /*aDLCI*/) |
|
2018 // The remote end has sent us an RPN negotiate command |
|
2019 // Just accept whatever they suggested then tell them we've accepted |
|
2020 { |
|
2021 // Write whatever's changed into our local port params. |
|
2022 aSAP.iLocalPortParams.UpdateFromRPNTransaction(aRPNTransaction); |
|
2023 |
|
2024 // Send L2CAP exactly what they sent us, except this is a response |
|
2025 aSAP.iMux->SendRPN(aSAP, EFalse, KRPNResponseLength, aRPNTransaction); |
|
2026 |
|
2027 // Indication of config change |
|
2028 IoctlComplete(aSAP, KErrNone, KSolBtRFCOMM, KRFCOMMConfigChangeIndicationIoctl, NULL); |
|
2029 } |
|
2030 |
|
2031 void TRfcommStateOpen::RPNRsp(CRfcommSAP& aSAP, |
|
2032 const TRfcommRPNTransaction& aRPNTransaction) |
|
2033 // The remote end has sent us an RPN response |
|
2034 { |
|
2035 // Make sure this is the response we are waiting for |
|
2036 switch(aSAP.iIoctlName) |
|
2037 { |
|
2038 case KRFCOMMRemotePortNegCmdIoctl: |
|
2039 LOG1(_L("RFCOMM: Received Negotiation response for sap %08x"), &aSAP); |
|
2040 // Update the local port parameters with what was agreed by the remote end. |
|
2041 aSAP.iLocalPortParams.UpdateFromRPNTransaction(aRPNTransaction); |
|
2042 break; |
|
2043 case KRFCOMMRemotePortNegRequestIoctl: |
|
2044 LOG1(_L("RFCOMM: Received Query response for sap %08x"), &aSAP); |
|
2045 break; |
|
2046 default: |
|
2047 __DEBUGGER(); |
|
2048 LOG(_L("Unexpected RPN response\n")); |
|
2049 return; |
|
2050 } |
|
2051 |
|
2052 // Convert the RPN transaction structure into a descriptor |
|
2053 TPckgC<TRfcommRPNTransaction> RPNTransaction(aRPNTransaction); |
|
2054 |
|
2055 // Send the package up to the user |
|
2056 IoctlComplete(aSAP, KErrNone, KSolBtRFCOMM, aSAP.iIoctlName, &RPNTransaction); |
|
2057 } |
|
2058 |
|
2059 void TRfcommStateOpen::PN(CRfcommSAP& aSAP, TRfcommPortParams& /*aParams*/, CRfcommMuxer& /*aMux*/, TUint8 /*aDLCI*/) |
|
2060 /** |
|
2061 We received a PN in the open state - no problem, but for simplicity |
|
2062 we just respond with our current settings (i.e. MTU). |
|
2063 NB. Importantly, the initial credit field should be set to 0... |
|
2064 **/ |
|
2065 { |
|
2066 TRfcommPortParams params; |
|
2067 params.iMaxFrameSize=aSAP.NegotiatedMTU(); |
|
2068 params.iInitialCredit=0; // See F:1 5.5.3 Core spec 1.1 |
|
2069 aSAP.iMux->SendPNResponse(aSAP, params); |
|
2070 } |
|
2071 |
|
2072 void TRfcommStateOpen::LinkDown(CRfcommSAP& aSAP) |
|
2073 /** |
|
2074 The link has gone down, which means our Mux will be deleting itself. |
|
2075 |
|
2076 Go to closed state, which removes us from the mux |
|
2077 **/ |
|
2078 { |
|
2079 PerformDataAwareStateChange(aSAP); |
|
2080 } |
|
2081 |
|
2082 |
|
2083 void TRfcommStateOpen::Ioctl(CRfcommSAP& aSAP,TUint aLevel,TUint aName,TDes8* aOption) |
|
2084 /** |
|
2085 Perform an RFCOMM ioctl that applies to an RFCOMM connection. |
|
2086 |
|
2087 If it is not valid, an error occurs. |
|
2088 **/ |
|
2089 { |
|
2090 TInt ret = KErrNone; |
|
2091 |
|
2092 switch(aName) |
|
2093 { |
|
2094 case KRFCOMMModemStatusCmdIoctl: |
|
2095 { |
|
2096 // aOption stores modem status |
|
2097 if(!aOption) |
|
2098 { |
|
2099 ret=KErrArgument; |
|
2100 } |
|
2101 else |
|
2102 { |
|
2103 TUint8 flags = TUint8(*aOption->Ptr()); |
|
2104 // Make sure we send our real flow control status, |
|
2105 // not just whatever was in the data received from the user |
|
2106 if(aSAP.CTR()) |
|
2107 { |
|
2108 flags &= ~KModemSignalFC; |
|
2109 } |
|
2110 else |
|
2111 { |
|
2112 flags |= KModemSignalFC; |
|
2113 } |
|
2114 |
|
2115 aSAP.SetSignals(flags); |
|
2116 ret = aSAP.iMux->SendMSC(aSAP, flags); |
|
2117 } |
|
2118 } |
|
2119 // Complete Ioctl with what was sent to us |
|
2120 IoctlComplete(aSAP, ret, aLevel, aName, aOption); |
|
2121 break; |
|
2122 |
|
2123 case KRFCOMMRemoteLineStatusCmdIoctl: |
|
2124 // aOption stores status of remote line |
|
2125 ret = aOption ? aSAP.iMux->SendRLS(aSAP, TUint8(*aOption->Ptr())) : KErrArgument; |
|
2126 // Complete Ioctl with what was sent to us |
|
2127 IoctlComplete(aSAP, ret, aLevel, aName, aOption); |
|
2128 break; |
|
2129 |
|
2130 case KRFCOMMRemotePortNegCmdIoctl: |
|
2131 LOG1(_L("RFCOMM: Sending RPN negotiate for sap %08x"), |
|
2132 &aSAP); |
|
2133 // aOption is really an RPN transaction structure |
|
2134 ret = aOption ? aSAP.iMux->SendRPN(aSAP, ETrue, KRPNCommandLength, |
|
2135 *(TRfcommRPNTransaction*)aOption->Ptr()) : KErrArgument; |
|
2136 break; |
|
2137 |
|
2138 case KRFCOMMRemotePortNegRequestIoctl: |
|
2139 LOG1(_L("RFCOMM: Sending RPN query for sap %08x"), |
|
2140 &aSAP); |
|
2141 // aOption is really an RPN transaction structure |
|
2142 ret = aOption ? aSAP.iMux->SendRPN(aSAP, ETrue, KRPNRequestLength, |
|
2143 *(TRfcommRPNTransaction*)aOption->Ptr()) : KErrArgument; |
|
2144 break; |
|
2145 |
|
2146 case KRFCOMMFConIoctl: |
|
2147 LOG2(_L("RFCOMM: Sending FCon command for device 0x%04x%08x"), |
|
2148 TUint(TUint16((aSAP.iMux->RemoteBTAddr())[0])), |
|
2149 TUint((aSAP.iMux->RemoteBTAddr())[2])); |
|
2150 //FC |
|
2151 ret=aSAP.iMux->SendFCon(); |
|
2152 // |
|
2153 IoctlComplete(aSAP, ret, aLevel, aName, aOption); |
|
2154 break; |
|
2155 |
|
2156 case KRFCOMMFCoffIoctl: |
|
2157 LOG2(_L("RFCOMM: Sending FCoff command for device 0x%04x%08x"), |
|
2158 TUint(TUint16((aSAP.iMux->RemoteBTAddr())[0])), |
|
2159 TUint((aSAP.iMux->RemoteBTAddr())[2])); |
|
2160 //FC |
|
2161 ret=aSAP.iMux->SendFCoff(); |
|
2162 // |
|
2163 IoctlComplete(aSAP, ret, aLevel, aName, aOption); |
|
2164 break; |
|
2165 |
|
2166 case KRFCOMMConfigChangeIndicationIoctl: |
|
2167 LOG(_L("RFCOMM: Registering KRFCOMMConfigChangeIndicationIoctl")); |
|
2168 // Do nothing -- async completion on remote MSC, RPN, RLS |
|
2169 break; |
|
2170 |
|
2171 default: |
|
2172 ret = KErrNotSupported; |
|
2173 } |
|
2174 |
|
2175 if(ret != KErrNone) |
|
2176 { |
|
2177 aSAP.iIoctlName=0; |
|
2178 aSAP.iIoctlLevel=0; |
|
2179 SignalError(aSAP, ret, MSocketNotify::EErrorIoctl); |
|
2180 } |
|
2181 } |
|
2182 |
|
2183 void TRfcommStateOpen::IoctlComplete(CRfcommSAP& aSAP, TInt aErr, TUint aLevel,TUint aName, TDesC8* aBuf) |
|
2184 /** |
|
2185 An ioctl has completed. |
|
2186 |
|
2187 If it's for us, signal the socket |
|
2188 **/ |
|
2189 { |
|
2190 if (aSAP.iIoctlLevel==aLevel && |
|
2191 aSAP.iIoctlName ==aName) |
|
2192 { |
|
2193 if(aErr == KErrNone) |
|
2194 { |
|
2195 aSAP.iSocket->IoctlComplete(aBuf); |
|
2196 } |
|
2197 else |
|
2198 { |
|
2199 SignalError(aSAP, aErr, MSocketNotify::EErrorIoctl); |
|
2200 } |
|
2201 aSAP.iIoctlName=0; |
|
2202 aSAP.iIoctlLevel=0; |
|
2203 } |
|
2204 } |
|
2205 |
|
2206 TInt TRfcommStateOpen::SetOption(CRfcommSAP &aSAP, TUint aLevel, |
|
2207 TUint aName, const TDesC8& aOption) |
|
2208 /** |
|
2209 Allow modem status to be modified whilst open. |
|
2210 **/ |
|
2211 { |
|
2212 TInt ret; |
|
2213 if(aLevel == KSolBtRFCOMM && aName == KRFCOMMLocalModemStatus) |
|
2214 { |
|
2215 if ( aOption.Length() != sizeof(TUint8) ) |
|
2216 { |
|
2217 ret = KErrArgument; |
|
2218 } |
|
2219 else |
|
2220 { |
|
2221 TUint8 flags = TUint8(*aOption.Ptr()); |
|
2222 if(aSAP.CTR()) |
|
2223 { |
|
2224 flags &= ~KModemSignalFC; |
|
2225 } |
|
2226 else |
|
2227 { |
|
2228 flags |= KModemSignalFC; |
|
2229 } |
|
2230 |
|
2231 ret = aSAP.iMux->SendMSC(aSAP, flags); |
|
2232 if(ret==KErrNone) |
|
2233 { |
|
2234 // Oddly, ioctl KRFCOMMModemStatusCmdIoctl updates |
|
2235 // local signals regardless of an error sending them |
|
2236 aSAP.SetSignals(flags); |
|
2237 } |
|
2238 } |
|
2239 } |
|
2240 else |
|
2241 { |
|
2242 ret = TRfcommStateDefault::SetOption(aSAP, aLevel, aName, aOption); |
|
2243 } |
|
2244 |
|
2245 |
|
2246 return ret; |
|
2247 } |
|
2248 |
|
2249 |
|
2250 //TRY_CBFC |
|
2251 TUint8 TRfcommStateOpen::FreeCredit(CRfcommSAP& aSAP) |
|
2252 { |
|
2253 TUint8 creds = aSAP.FreeCreditCalculation(); |
|
2254 return creds; |
|
2255 } |
|
2256 |
|
2257 TInt TRfcommStateOpen::ProxyForRemoteCredit(const CRfcommSAP& aSAP) const |
|
2258 { |
|
2259 return aSAP.iProxyForRemoteCredit; |
|
2260 } |
|
2261 |
|
2262 TInt TRfcommStateOpen::LocalCredit(const CRfcommSAP& aSAP) const |
|
2263 { |
|
2264 return aSAP.iLocalCredit; |
|
2265 } |
|
2266 |
|
2267 |
|
2268 |
|
2269 /*********************************************************************/ |
|
2270 /* |
|
2271 Disconnect state |
|
2272 */ |
|
2273 |
|
2274 TRfcommStateDisconnect::TRfcommStateDisconnect(CRfcommStateFactory& aFactory) |
|
2275 : TRfcommStateDefault(aFactory) |
|
2276 { |
|
2277 STATENAME("Disconnect"); |
|
2278 } |
|
2279 |
|
2280 void TRfcommStateDisconnect::Enter(CRfcommSAP& aSAP) |
|
2281 /** |
|
2282 Send out a disconnect via the mux |
|
2283 **/ |
|
2284 { |
|
2285 __ASSERT_DEBUG(aSAP.iMux!=NULL,PanicInState(ERfcommNullMux)); |
|
2286 // Need to kill off any data callback since we don't want it |
|
2287 aSAP.iNotifyNewDataCallback->Cancel(); |
|
2288 aSAP.iNewDataToNotify = 0; |
|
2289 aSAP.iDataBuffer.Reset(); |
|
2290 aSAP.iMux->SendDISC(aSAP); |
|
2291 } |
|
2292 |
|
2293 void TRfcommStateDisconnect::DISC(CRfcommSAP& aSAP) |
|
2294 /** |
|
2295 We're attempting to DISC, and apparently so is our peer SAP. |
|
2296 |
|
2297 Send them a UA, and move to the closed state. |
|
2298 **/ |
|
2299 { |
|
2300 aSAP.iMux->SendUA(aSAP.DLCI()); // Send to DLCI, or we may lose this when the SAP gets deleted. |
|
2301 DisconnectComplete(aSAP); |
|
2302 } |
|
2303 |
|
2304 void TRfcommStateDisconnect::UA(CRfcommSAP& aSAP) |
|
2305 /** |
|
2306 An answer to our DISC. |
|
2307 |
|
2308 Disconnect from the Mux now, so it can go away if needs be. |
|
2309 **/ |
|
2310 { |
|
2311 DisconnectComplete(aSAP); |
|
2312 } |
|
2313 |
|
2314 void TRfcommStateDisconnect::DM(CRfcommSAP& aSAP) |
|
2315 /** |
|
2316 Strange, the remote end has sent an error for our disconnect. |
|
2317 Oh well, better close anyway. |
|
2318 **/ |
|
2319 { |
|
2320 DisconnectComplete(aSAP); |
|
2321 } |
|
2322 |
|
2323 void TRfcommStateDisconnect::DisconnectComplete(CRfcommSAP& aSAP) |
|
2324 { |
|
2325 // Record whether there is a CanClose pending - entering the closed |
|
2326 // state will overwrite this data. |
|
2327 TBool canCloseRequired=aSAP.iClosePending; |
|
2328 |
|
2329 ChangeState(aSAP, CRfcommStateFactory::EClosed); // Must enter before CanClose, since |
|
2330 // this may delete us |
|
2331 if(canCloseRequired) |
|
2332 aSAP.iSocket->CanClose(); |
|
2333 } |
|
2334 |
|
2335 void TRfcommStateDisconnect::LinkDown(CRfcommSAP& aSAP) |
|
2336 /** |
|
2337 The link has gone down during our close. |
|
2338 **/ |
|
2339 { |
|
2340 ChangeState(aSAP, CRfcommStateFactory::EClosed); // Enter before we get deleted... |
|
2341 aSAP.iSocket->CanClose(); |
|
2342 } |
|
2343 |
|
2344 /*************************************************************** |
|
2345 |
|
2346 The disconnecting state |
|
2347 |
|
2348 ***************************************************************/ |
|
2349 |
|
2350 |
|
2351 TRfcommStateDisconnecting::TRfcommStateDisconnecting(CRfcommStateFactory& aFactory) |
|
2352 : TRfcommStateDefault(aFactory) |
|
2353 { |
|
2354 STATENAME("Disconnecting"); |
|
2355 } |
|
2356 |
|
2357 |
|
2358 void TRfcommStateDisconnecting::Enter(CRfcommSAP& aSAP) |
|
2359 /** |
|
2360 Enter the disconnecting state. |
|
2361 |
|
2362 This state is entered if we have data for the client, but the |
|
2363 other end has disconnected. Thus we are in a half-disconnected |
|
2364 state, where the remote end thinks we're closed and the local |
|
2365 end thinks we're open. Since we have data to notify, we'll send |
|
2366 it to ESOCK immediately. |
|
2367 |
|
2368 We disconnect from the mux as we have no further need for |
|
2369 incoming events. |
|
2370 **/ |
|
2371 { |
|
2372 __ASSERT_DEBUG(aSAP.iNewDataToNotify, PanicInState(ERfcommStateDisconnectingWithNoData)); |
|
2373 __ASSERT_DEBUG(aSAP.iNotifyNewDataCallback->IsActive(), PanicInState(ERfcommStateDisconnectingWithNoData)); |
|
2374 // aSAP.iNotifyNewDataCallback->Cancel(); // Cancel the outstanding callback |
|
2375 aSAP.iMux->DetachSAP(aSAP); |
|
2376 TInt newData = aSAP.iNewDataToNotify; |
|
2377 if (newData) |
|
2378 { |
|
2379 aSAP.iNewDataToNotify = 0; |
|
2380 aSAP.iSocket->NewData(newData); |
|
2381 } |
|
2382 } |
|
2383 |
|
2384 TInt TRfcommStateDisconnecting::Send(CRfcommSAP& aSAP, const TDesC8& /*aData*/) |
|
2385 /** |
|
2386 Attempt to send data, but we can't. |
|
2387 |
|
2388 We will signal an error on the send. |
|
2389 **/ |
|
2390 { |
|
2391 aSAP.iErrorKicker->SetError(KErrDisconnected, CRfcommSAP::EErrorOperation); |
|
2392 aSAP.iErrorKicker->Call(); // FIXME: Note this currently errors everything |
|
2393 return 0; |
|
2394 } |
|
2395 |
|
2396 void TRfcommStateDisconnecting::Read(CRfcommSAP& aSAP, TDesC8& aData) |
|
2397 /** |
|
2398 Read out some of the data from the buffer. |
|
2399 |
|
2400 Note that there is no need to deal with flow control, as the |
|
2401 link is dead. Also, there is no need to deal with notifying |
|
2402 the mux for more data, since we assume that only data that is |
|
2403 notified to us before the DISC is valid. |
|
2404 **/ |
|
2405 { |
|
2406 __ASSERT_DEBUG(aSAP.DataBuffer().Count() >= aData.Length(), |
|
2407 PanicInState(ERfcommReadForTooMuchData)); |
|
2408 LOG1(_L("RFCOMM: Read of (disconnecting) %d bytes"), aData.Length()); |
|
2409 |
|
2410 aSAP.DataBuffer().Remove(const_cast<TUint8*>(aData.Ptr()), aData.Length()); |
|
2411 } |
|
2412 |
|
2413 void TRfcommStateDisconnecting::NotifyNewDataCallback(CRfcommSAP& aSAP) |
|
2414 /** |
|
2415 Method name is a bit dud in this state |
|
2416 We notify the socket that it is Disconnected |
|
2417 Provides better behaviour for the MSocketNotify - it doesn't end up |
|
2418 with a Disconnect upcall whilst calling Read |
|
2419 **/ |
|
2420 { |
|
2421 __ASSERT_DEBUG(aSAP.iNewDataToNotify == 0, PanicInState(ERfcommStateClosedWithData)); |
|
2422 |
|
2423 LOG(_L("SAP has no more data - socket now Disconnected")); |
|
2424 |
|
2425 aSAP.iSocket->Disconnect(); |
|
2426 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
2427 } |
|
2428 |
|
2429 void TRfcommStateDisconnecting::Ioctl(CRfcommSAP& aSAP,TUint /*aLevel*/,TUint /*aName*/,TDes8* /*aOption*/) |
|
2430 /** |
|
2431 An ioctl has been requested while we are in state disconnected. |
|
2432 |
|
2433 We fail all ioctls in this state. |
|
2434 **/ |
|
2435 { |
|
2436 __ASSERT_DEBUG(aSAP.iIoctlLevel == 0, PanicInState(ERfcommSAPTwoIoctls)); |
|
2437 __ASSERT_DEBUG(aSAP.iIoctlName == 0, PanicInState(ERfcommSAPTwoIoctls)); |
|
2438 |
|
2439 SignalError(aSAP, KErrDisconnected, MSocketNotify::EErrorIoctl); |
|
2440 } |
|
2441 |
|
2442 void TRfcommStateDisconnecting::Shutdown(CRfcommSAP& aSAP) |
|
2443 /** |
|
2444 We've been asked to close this side. |
|
2445 |
|
2446 Since the other end has already gone away, there's no need to |
|
2447 send anything, we can go straight to closed. |
|
2448 **/ |
|
2449 { |
|
2450 ChangeState(aSAP, CRfcommStateFactory::EClosed); // Must enter before CanClose, since |
|
2451 // this may delete us |
|
2452 aSAP.iSocket->CanClose(); |
|
2453 } |
|
2454 |
|
2455 void TRfcommStateDisconnecting::FastShutdown(CRfcommSAP& aSAP) |
|
2456 /** |
|
2457 We've been asked to close this side with extreme prejudice. |
|
2458 |
|
2459 Since the other end has already gone away, there's no need to |
|
2460 send anything, we can go straight to closed. Note we will be |
|
2461 deleted when this returns. |
|
2462 **/ |
|
2463 { |
|
2464 ChangeState(aSAP, CRfcommStateFactory::EClosed); |
|
2465 } |