|
1 // Copyright (c) 1999-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 // Runs the mux control channel for the Rfcomm muxer |
|
15 // |
|
16 // |
|
17 |
|
18 #include <bluetooth/logger.h> |
|
19 #include "rfcommmuxchannel.h" |
|
20 #include "rfcommconsts.h" |
|
21 #include "rfcommutil.h" |
|
22 |
|
23 #ifdef __FLOG_ACTIVE |
|
24 _LIT8(KLogComponent, LOG_COMPONENT_RFCOMM); |
|
25 #endif |
|
26 |
|
27 CRfcommMuxChannel::CRfcommMuxChannel(CMuxChannelStateFactory& aFact, CRfcommMuxer& aMux, |
|
28 CServProviderBase& aSAP, CMuxChannelStateFactory::TChannelState aInitialState) |
|
29 : iSAP(aSAP), |
|
30 iMux(aMux) |
|
31 { |
|
32 iState=aFact.GetState(aInitialState); |
|
33 iState->Enter(*this, EFalse); |
|
34 TCallBack cb(IdleTimerCallback, this); |
|
35 iIdleTimer.Set(cb); |
|
36 } |
|
37 |
|
38 CRfcommMuxChannel::~CRfcommMuxChannel() |
|
39 { |
|
40 DequeIdleTimer(); |
|
41 } |
|
42 |
|
43 void CRfcommMuxChannel::SetAddress(TBTDevAddr& aAddr) |
|
44 { |
|
45 TL2CAPSockAddr remote; |
|
46 iSAP.AutoBind(); |
|
47 remote.SetBTAddr(aAddr); |
|
48 remote.SetPort(KRFCOMMPSM); // 0x03 normally... |
|
49 if(iSAP.SetRemName(remote)!=KErrNone) |
|
50 { |
|
51 Panic(ERfcommErrorSettingAddress); |
|
52 } |
|
53 } |
|
54 |
|
55 void CRfcommMuxChannel::QueIdleTimer(TInt aDelay) |
|
56 { |
|
57 if(!iIdleTimerQueued) |
|
58 { |
|
59 BTSocketTimer::Queue(aDelay, iIdleTimer); |
|
60 iIdleTimerQueued=ETrue; |
|
61 } |
|
62 } |
|
63 |
|
64 void CRfcommMuxChannel::DequeIdleTimer() |
|
65 { |
|
66 if(iIdleTimerQueued) |
|
67 { |
|
68 BTSocketTimer::Remove(iIdleTimer); |
|
69 iIdleTimerQueued=EFalse; |
|
70 } |
|
71 } |
|
72 |
|
73 TInt CRfcommMuxChannel::IdleTimerCallback(TAny* aChannel) |
|
74 { |
|
75 CRfcommMuxChannel* channel=static_cast<CRfcommMuxChannel*>(aChannel); |
|
76 channel->iIdleTimerQueued=EFalse; |
|
77 LOG(_L("RFCOMM: Mux channel idle timer callback")); |
|
78 channel->iState->IdleTimeout(*channel); |
|
79 return EFalse; |
|
80 } |
|
81 |
|
82 /** |
|
83 This lets the protocol know whether this mux is able to be attached to. |
|
84 Sometimes it will be irrevocably committed to going down and so is not |
|
85 valid to be attached to. |
|
86 @return TBool Whether it's ok to attach a SAP |
|
87 */ |
|
88 TBool CRfcommMuxChannel::CanAttachSAP() |
|
89 { |
|
90 // Let the state use its context to work out if we're going down |
|
91 return iState->CanAttachSAP(); |
|
92 } |
|
93 |
|
94 /* |
|
95 State factory |
|
96 */ |
|
97 |
|
98 CMuxChannelStateFactory* CMuxChannelStateFactory::NewL() |
|
99 { |
|
100 CMuxChannelStateFactory* ret=new (ELeave) CMuxChannelStateFactory(); |
|
101 CleanupStack::PushL(ret); |
|
102 ret->ConstructL(); |
|
103 CleanupStack::Pop(); |
|
104 return ret; |
|
105 } |
|
106 |
|
107 void CMuxChannelStateFactory::ConstructL() |
|
108 { |
|
109 iStates[EClosed]=new (ELeave) TMuxChannelStateClosed(*this); |
|
110 iStates[EWaitForLink]=new (ELeave) TMuxChannelStateWaitForLink(*this); |
|
111 iStates[EError]= new (ELeave) TMuxChannelStateError(*this); |
|
112 iStates[ELinkUp]=new (ELeave) TMuxChannelStateLinkUp(*this); |
|
113 iStates[EWaitForSABMResp]=new (ELeave) TMuxChannelStateWaitForSABMResp(*this); |
|
114 iStates[EOpen]=new (ELeave) TMuxChannelStateOpen(*this); |
|
115 iStates[EClosing]=new (ELeave) TMuxChannelStateClosing(*this); |
|
116 } |
|
117 |
|
118 CMuxChannelStateFactory::~CMuxChannelStateFactory() |
|
119 { |
|
120 iStates.DeleteAll(); |
|
121 } |
|
122 |
|
123 TMuxChannelState* CMuxChannelStateFactory::GetState(TChannelState aState) |
|
124 { |
|
125 __ASSERT_DEBUG(aState != ERfcommChannelMaxState, Panic(ERfCommMuxerStateOutOfBounds)); |
|
126 return iStates[aState]; |
|
127 } |
|
128 |
|
129 TInt CMuxChannelStateFactory::StateIndex(const TMuxChannelState* aState) const |
|
130 { |
|
131 TInt state; |
|
132 for (state = 0; state < ERfcommChannelMaxState; state++) |
|
133 { |
|
134 if (iStates[state] == aState) |
|
135 { |
|
136 return state; |
|
137 } |
|
138 } |
|
139 |
|
140 return KUnknownState; |
|
141 } |
|
142 |
|
143 |
|
144 /* |
|
145 The base state class |
|
146 */ |
|
147 |
|
148 void TMuxChannelState::SetState(CRfcommMuxChannel& aContext, CMuxChannelStateFactory::TChannelState aState) |
|
149 { |
|
150 #ifdef __FLOG_ACTIVE |
|
151 TMuxChannelState* state=iFactory.GetState(aState); |
|
152 LOG2(_L("RFCOMM: MuxChannel : State %S -> %S"), |
|
153 &aContext.iState->iName, &state->iName); |
|
154 #endif //__FLOG_ACTIVE |
|
155 #ifdef _DEBUG |
|
156 TMuxChannelState* st=iFactory.GetState(aState); |
|
157 __ASSERT_DEBUG(st!=aContext.iState, PanicInState(ERfcommMuxChannelStateChangeToSelf)); |
|
158 #endif |
|
159 aContext.iState=iFactory.GetState(aState); |
|
160 } |
|
161 |
|
162 TMuxChannelState::TMuxChannelState(CMuxChannelStateFactory& aFactory) |
|
163 : iFactory(aFactory) |
|
164 { |
|
165 } |
|
166 |
|
167 void TMuxChannelState::PanicInState(TRFCOMMPanic aPanic) const |
|
168 { |
|
169 Panic(aPanic, iFactory.StateIndex(this)); |
|
170 } |
|
171 |
|
172 #ifdef _DEBUG |
|
173 void TMuxChannelState::DebugPanicInState(TRFCOMMPanic aPanic) const |
|
174 #else |
|
175 void TMuxChannelState::DebugPanicInState(TRFCOMMPanic /*aPanic*/) const |
|
176 #endif |
|
177 { |
|
178 #ifdef _DEBUG |
|
179 PanicInState(aPanic); |
|
180 #endif |
|
181 } |
|
182 |
|
183 void TMuxChannelState::Enter(CRfcommMuxChannel& aContext, TBool /*aDisconnectingIdleTimer*/) |
|
184 /** |
|
185 Called when entering a state |
|
186 **/ |
|
187 { |
|
188 aContext.DequeIdleTimer(); //ENTERED NEW STATE => NOT IDLE |
|
189 } |
|
190 |
|
191 void TMuxChannelState::Open(CRfcommMuxChannel& aContext) |
|
192 /** |
|
193 A request to bring up the mux channel |
|
194 **/ |
|
195 { |
|
196 aContext.iOpenPending=ETrue; |
|
197 aContext.iClosePending=EFalse; |
|
198 } |
|
199 |
|
200 void TMuxChannelState::Close(CRfcommMuxChannel& aContext) |
|
201 /** |
|
202 Close the mux channel down |
|
203 **/ |
|
204 { |
|
205 aContext.iClosePending=ETrue; |
|
206 aContext.iOpenPending=EFalse; |
|
207 } |
|
208 |
|
209 TBool TMuxChannelState::IsOpen(CRfcommMuxChannel& /*aContext*/) |
|
210 { |
|
211 return EFalse; |
|
212 } |
|
213 |
|
214 void TMuxChannelState::UA(CRfcommMuxChannel& /*aContext*/) |
|
215 /** |
|
216 A UA frame for DLCI zero has been received |
|
217 **/ |
|
218 { |
|
219 // Do nothing |
|
220 } |
|
221 |
|
222 void TMuxChannelState::DISC(CRfcommMuxChannel& /*aContext*/) |
|
223 /** |
|
224 A DISC frame for DLCI zero has been received |
|
225 **/ |
|
226 { |
|
227 // Do nothing |
|
228 } |
|
229 |
|
230 void TMuxChannelState::DM(CRfcommMuxChannel& /*aContext*/) |
|
231 /** |
|
232 A DM frame for DLCI zero has been received |
|
233 **/ |
|
234 { |
|
235 // Do nothing |
|
236 } |
|
237 |
|
238 void TMuxChannelState::PN(CRfcommMuxChannel& aContext, |
|
239 TBool aCommand, TRfcommPortParams& /*aParams*/) |
|
240 /** |
|
241 A PN command or response for DLCI zero has been received |
|
242 **/ |
|
243 { |
|
244 if(aCommand) |
|
245 { |
|
246 // We're at liberty to ignore this, since PNs are not allowed |
|
247 // on DLCI 0. However, we can send back a PN response with a |
|
248 // MTU of 127 (the default, which we can guarantee). |
|
249 // |
|
250 // NB. Default TRfcommPortParams constructor sets default MTU (127) |
|
251 // |
|
252 TRfcommPortParams muxParams; |
|
253 muxParams.iInitialCredit=0; //DS improved by making 0 default? |
|
254 aContext.TransmitPN(EFalse, muxParams); |
|
255 } |
|
256 else |
|
257 { |
|
258 // Should never happen |
|
259 LOG(_L("RFCOMM: Received a PN response on Mux channel!")); |
|
260 } |
|
261 |
|
262 } |
|
263 |
|
264 void TMuxChannelState::SABM(CRfcommMuxChannel& /*aContext*/) |
|
265 /** |
|
266 A SABM has been received for DLCI 0 |
|
267 **/ |
|
268 { |
|
269 //do nothing |
|
270 } |
|
271 |
|
272 void TMuxChannelState::FrameTimeout(CRfcommMuxChannel& /*aContext*/, |
|
273 CRfcommFrame* /*aFrm*/) |
|
274 /** |
|
275 A ctrl or mux frame has timed out before a response was received. |
|
276 |
|
277 Generally this is not a good thing. |
|
278 **/ |
|
279 { |
|
280 DebugPanicInState(ERfcommChannelIdleTimeout); |
|
281 } |
|
282 |
|
283 void TMuxChannelState::Disconnect(CRfcommMuxChannel& /*aContext*/) |
|
284 /** |
|
285 A disconnect indication has come in from L2CAP |
|
286 **/ |
|
287 { |
|
288 // Do nothing |
|
289 } |
|
290 |
|
291 void TMuxChannelState::CanClose(CRfcommMuxChannel& /*aContext*/) |
|
292 /** |
|
293 L2CAP is happy for us to delete the sap |
|
294 **/ |
|
295 { |
|
296 // Do nothing |
|
297 } |
|
298 |
|
299 void TMuxChannelState::ConnectComplete(CRfcommMuxChannel& /*aContext*/) |
|
300 /** |
|
301 The L2CAP connect has completed |
|
302 **/ |
|
303 { |
|
304 // Do nothing |
|
305 } |
|
306 |
|
307 void TMuxChannelState::Error(CRfcommMuxChannel& /*aContext*/, TInt /*aError*/, |
|
308 TUint /*anOperationMask*/) |
|
309 /** |
|
310 An error on the L2CAP sap has occurred |
|
311 **/ |
|
312 { |
|
313 // Do nothing |
|
314 } |
|
315 |
|
316 void TMuxChannelState::IdleTimeout(CRfcommMuxChannel& /*aContext*/) |
|
317 /** |
|
318 The idle timer has gone off. |
|
319 **/ |
|
320 { |
|
321 DebugPanicInState(ERfcommChannelIdleTimeout); |
|
322 } |
|
323 |
|
324 TBool TMuxChannelState::CanAttachSAP() |
|
325 { |
|
326 return ETrue; |
|
327 } |
|
328 |
|
329 /* |
|
330 Closed |
|
331 */ |
|
332 |
|
333 TMuxChannelStateClosed::TMuxChannelStateClosed(CMuxChannelStateFactory& aFactory) |
|
334 : TMuxChannelState(aFactory) |
|
335 { |
|
336 STATENAME("Closed"); |
|
337 } |
|
338 |
|
339 void TMuxChannelStateClosed::Enter(CRfcommMuxChannel& aContext, TBool /*aDisconnectingIdleTimer*/) |
|
340 /** |
|
341 Reset everything |
|
342 **/ |
|
343 { |
|
344 aContext.iOpenPending=EFalse; |
|
345 aContext.iClosePending=EFalse; |
|
346 aContext.DequeIdleTimer(); |
|
347 } |
|
348 |
|
349 void TMuxChannelStateClosed::Open(CRfcommMuxChannel& aContext) |
|
350 /** |
|
351 Open up the L2CAP link |
|
352 **/ |
|
353 { |
|
354 // Set opening\closing flags |
|
355 TMuxChannelState::Open(aContext); |
|
356 // Make sure the PSM is in place, rather than an old CID |
|
357 TL2CAPSockAddr remote; |
|
358 aContext.iSAP.RemName(remote); |
|
359 remote.SetPort(KRFCOMMPSM); |
|
360 |
|
361 TBTServiceSecurity ssec; |
|
362 ssec.SetAuthentication(EMitmNotRequired); |
|
363 ssec.SetAuthorisation(EFalse); |
|
364 ssec.SetEncryption(EFalse); |
|
365 ssec.SetDenied(EFalse); |
|
366 |
|
367 remote.SetSecurity(ssec); |
|
368 |
|
369 aContext.iSAP.SetRemName(remote); |
|
370 SetState(aContext,CMuxChannelStateFactory::EWaitForLink); |
|
371 aContext.iSAP.ActiveOpen(); |
|
372 aContext.iState->Enter(aContext); |
|
373 } |
|
374 |
|
375 void TMuxChannelStateClosed::Close(CRfcommMuxChannel& aContext) |
|
376 { |
|
377 // No need to do anything - call back synchronously |
|
378 aContext.iMux.MuxChannelClosed(); |
|
379 } |
|
380 |
|
381 /* |
|
382 WaitForLink - waiting for the link to come up |
|
383 */ |
|
384 |
|
385 TMuxChannelStateWaitForLink::TMuxChannelStateWaitForLink(CMuxChannelStateFactory& aFactory) |
|
386 : TMuxChannelState(aFactory) |
|
387 { |
|
388 STATENAME("WaitForLink"); |
|
389 } |
|
390 |
|
391 void TMuxChannelStateWaitForLink::ConnectComplete(CRfcommMuxChannel& aContext) |
|
392 /** |
|
393 The link has come up |
|
394 |
|
395 Move to the start state in the connected superstate (LinkUp) |
|
396 **/ |
|
397 { |
|
398 SetState(aContext,CMuxChannelStateFactory::ELinkUp); |
|
399 aContext.iState->Enter(aContext); |
|
400 } |
|
401 |
|
402 void TMuxChannelStateWaitForLink::Close(CRfcommMuxChannel& aContext) |
|
403 /** |
|
404 The mux is no longer wanted. |
|
405 |
|
406 Cancel the pending opening so we'll just timeout and die in |
|
407 state LinkUp, or the link won't come up so we'll drop to |
|
408 closed. |
|
409 **/ |
|
410 { |
|
411 aContext.iOpenPending=EFalse; |
|
412 } |
|
413 |
|
414 void TMuxChannelStateWaitForLink::Error(CRfcommMuxChannel& aContext, TInt aError, |
|
415 TUint aOperationMask) |
|
416 /** |
|
417 The connection failed to come up |
|
418 **/ |
|
419 { |
|
420 if(aOperationMask | MSocketNotify::EErrorFatal) |
|
421 { |
|
422 // Things are very bad, so drop to the error state |
|
423 SetState(aContext,CMuxChannelStateFactory::EError); |
|
424 aContext.iMux.MuxChannelError(ETrue, aError); |
|
425 } |
|
426 else if(aOperationMask | MSocketNotify::EErrorConnect) |
|
427 { |
|
428 // This connect failed, so we'd better go to the Closed state |
|
429 SetState(aContext,CMuxChannelStateFactory::EClosed); |
|
430 aContext.iMux.MuxChannelError(EFalse, aError); |
|
431 } |
|
432 else |
|
433 { |
|
434 // We have an error that probably should be ignored |
|
435 LOG(_L("RFCOMM: **** Muxchannel wait for link, ignoring error ****")); |
|
436 } |
|
437 aContext.iState->Enter(aContext); |
|
438 } |
|
439 |
|
440 /* |
|
441 Error |
|
442 */ |
|
443 |
|
444 TMuxChannelStateError::TMuxChannelStateError(CMuxChannelStateFactory& aFactory) |
|
445 : TMuxChannelState(aFactory) |
|
446 { |
|
447 STATENAME("Error"); |
|
448 } |
|
449 |
|
450 void TMuxChannelStateError::Open(CRfcommMuxChannel& /*aContext*/) |
|
451 { |
|
452 PanicInState(ERfcommChannelError); |
|
453 } |
|
454 |
|
455 void TMuxChannelStateError::Close(CRfcommMuxChannel& aContext) |
|
456 { |
|
457 // tell the muxer now since there'll be no transition from this state |
|
458 aContext.iMux.MuxChannelClosed(); |
|
459 } |
|
460 |
|
461 TBool TMuxChannelStateError::CanAttachSAP() |
|
462 { |
|
463 return EFalse; |
|
464 } |
|
465 |
|
466 /* |
|
467 Connected. Super state for several states |
|
468 */ |
|
469 |
|
470 |
|
471 TMuxChannelStateConnected::TMuxChannelStateConnected(CMuxChannelStateFactory& aFactory) |
|
472 : TMuxChannelState(aFactory) |
|
473 { |
|
474 STATENAME("Connected"); |
|
475 } |
|
476 |
|
477 void TMuxChannelStateConnected::SABM(CRfcommMuxChannel& aContext) |
|
478 /** |
|
479 A SABM has been received for DLCI 0 |
|
480 We are not in one of the connected states that expects a SABM |
|
481 Attempt to tell the other side that we are not in a fit state. |
|
482 **/ |
|
483 { |
|
484 LOG(_L("RFCOMM: sending NACK on unexpected SABM")); |
|
485 aContext.TransmitDM(); |
|
486 } |
|
487 |
|
488 void TMuxChannelStateConnected::FrameTimeout(CRfcommMuxChannel& aContext, CRfcommFrame* /*aFrm*/) |
|
489 /** |
|
490 A frame has failed to elicit a response |
|
491 |
|
492 This is bad for the mux channel, so we go to LinkUp. The muxer |
|
493 will take care of the frame.. |
|
494 **/ |
|
495 { |
|
496 // Do the basics... |
|
497 FrameTimeoutHelper(aContext); |
|
498 |
|
499 //... and then go to ELinkUp |
|
500 SetState(aContext,CMuxChannelStateFactory::ELinkUp); |
|
501 aContext.iState->Enter(aContext); |
|
502 } |
|
503 |
|
504 void TMuxChannelStateConnected::FrameTimeoutHelper(CRfcommMuxChannel& aContext) |
|
505 /** |
|
506 Helper function for code re-use in FrameTimeout methods |
|
507 **/ |
|
508 { |
|
509 aContext.iOpenPending=EFalse; |
|
510 aContext.iClosePending=EFalse; |
|
511 aContext.iMux.MuxChannelError(EFalse, KErrRfcommFrameResponseTimeout); |
|
512 } |
|
513 |
|
514 void TMuxChannelStateConnected::Disconnect(CRfcommMuxChannel& aContext) |
|
515 /** |
|
516 The other end has disconnected the L2CAP link |
|
517 **/ |
|
518 { |
|
519 aContext.DequeIdleTimer(); |
|
520 SetState(aContext,CMuxChannelStateFactory::EClosed); |
|
521 aContext.iState->Enter(aContext); |
|
522 aContext.iMux.MuxChannelDown(); |
|
523 aContext.iMux.MuxChannelClosed(); |
|
524 } |
|
525 |
|
526 void TMuxChannelStateConnected::Error(CRfcommMuxChannel& aContext, TInt aError, |
|
527 TUint aOperationMask) |
|
528 /** |
|
529 Summ'ts up at t'mill! |
|
530 |
|
531 Check the op mask - if it's only Ioctl then we ignore it, else |
|
532 something bad is wrong. |
|
533 |
|
534 Clear the link timer as well in case we are in LinkUp. |
|
535 **/ |
|
536 { |
|
537 if(aOperationMask != MSocketNotify::EErrorIoctl) |
|
538 { |
|
539 aContext.DequeIdleTimer(); |
|
540 SetState(aContext,CMuxChannelStateFactory::EError); |
|
541 aContext.iMux.MuxChannelError(ETrue, aError); |
|
542 aContext.iState->Enter(aContext); |
|
543 } |
|
544 } |
|
545 |
|
546 /* |
|
547 Now the meaty ones... |
|
548 |
|
549 LinkUp - the l2cap link is up, and maybe we need to bring up the mux channel... |
|
550 */ |
|
551 |
|
552 TMuxChannelStateLinkUp::TMuxChannelStateLinkUp(CMuxChannelStateFactory& aFactory) |
|
553 : TMuxChannelStateConnected(aFactory) |
|
554 { |
|
555 STATENAME("LinkUp"); |
|
556 } |
|
557 |
|
558 void TMuxChannelStateLinkUp::Enter(CRfcommMuxChannel& aContext, TBool aDisconnectingIdleTimer) |
|
559 /** |
|
560 Entered the state |
|
561 |
|
562 Start to bring up the link if a Open is pending, or bring it |
|
563 down if a Close is pending, or just remain link up and kick |
|
564 off a timer if neither is true. |
|
565 |
|
566 Find out the L2CAP MTU as this is now important. |
|
567 **/ |
|
568 { |
|
569 __ASSERT_DEBUG(!(aContext.iOpenPending && aContext.iClosePending), |
|
570 PanicInState(ERfcommMuxChannelOpeningAndClosing)); |
|
571 |
|
572 aContext.DequeIdleTimer(); //ENTERED NEW STATE => NOT IDLE |
|
573 |
|
574 TPckgBuf<TInt> buf; |
|
575 |
|
576 // Find out what the max data size is. |
|
577 aContext.iSAP.GetOption(KSolBtL2CAP, KL2CAPInboundMTU, buf); |
|
578 TInt t = buf(); |
|
579 aContext.iSAP.GetOption(KSolBtL2CAP, KL2CAPOutboundMTUForBestPerformance, buf); |
|
580 // Max size is the lower of incoming and outgoing |
|
581 // L2CAP MTUs since it's symmetrical |
|
582 aContext.iMaxDataSize=Min(buf(), t); |
|
583 |
|
584 if(aContext.iOpenPending) |
|
585 { |
|
586 aContext.iOpenPending=EFalse; |
|
587 TInt err=aContext.TransmitSABM(); |
|
588 if(err != KErrNone) |
|
589 { |
|
590 SetState(aContext,CMuxChannelStateFactory::EError); |
|
591 aContext.iMux.MuxChannelError(ETrue, err); |
|
592 } |
|
593 else |
|
594 { |
|
595 aContext.iState= |
|
596 iFactory.GetState(CMuxChannelStateFactory::EWaitForSABMResp); |
|
597 } |
|
598 aContext.iState->Enter(aContext); |
|
599 } |
|
600 else if(aContext.iClosePending) |
|
601 { |
|
602 SetState(aContext,CMuxChannelStateFactory::EClosing); |
|
603 aContext.iSAP.Shutdown(CServProviderBase::ENormal); |
|
604 aContext.iState->Enter(aContext); |
|
605 } |
|
606 else |
|
607 { |
|
608 if(aDisconnectingIdleTimer) |
|
609 { |
|
610 // Timeout (nominally 1 sec) to prevent a DoS attack from an out-of-sequence PN |
|
611 aContext.QueIdleTimer(KRfcommMuxDisconnectingChannelTimeout); |
|
612 } |
|
613 else |
|
614 { |
|
615 // We start the idle timer (nominally 10 secs). This is a countdown |
|
616 // which will be cancelled when we receive a SABM from the remote. |
|
617 // Otherwise the connection is closed to avoid sapping our battery. |
|
618 aContext.QueIdleTimer(KRfcommMuxConnectingChannelTimeout); |
|
619 } |
|
620 } |
|
621 } |
|
622 |
|
623 void TMuxChannelStateLinkUp::Close(CRfcommMuxChannel& aContext) |
|
624 /** |
|
625 We've been explicitly asked to close down. |
|
626 |
|
627 We should now bring down the link. We can signal that the mux |
|
628 channel is closed immediately. |
|
629 **/ |
|
630 { |
|
631 aContext.iMux.MuxChannelDown(); |
|
632 SetState(aContext,CMuxChannelStateFactory::EClosing); |
|
633 aContext.iSAP.Shutdown(CServProviderBase::ENormal); |
|
634 aContext.iState->Enter(aContext); |
|
635 } |
|
636 |
|
637 void TMuxChannelStateLinkUp::Open(CRfcommMuxChannel& aContext) |
|
638 /** |
|
639 Time to bring up that channel |
|
640 **/ |
|
641 { |
|
642 aContext.DequeIdleTimer(); |
|
643 aContext.iOpenPending=EFalse; |
|
644 TInt err=aContext.TransmitSABM(); |
|
645 if(err != KErrNone) |
|
646 { |
|
647 SetState(aContext,CMuxChannelStateFactory::EError); |
|
648 aContext.iMux.MuxChannelError(ETrue, err); |
|
649 } |
|
650 else |
|
651 { |
|
652 SetState(aContext,CMuxChannelStateFactory::EWaitForSABMResp); |
|
653 } |
|
654 aContext.iState->Enter(aContext); |
|
655 } |
|
656 |
|
657 void TMuxChannelStateLinkUp::SABM(CRfcommMuxChannel& aContext) |
|
658 /** |
|
659 We've received a SABM on DLCI 0. |
|
660 |
|
661 Respond with a UA, and move to the Open state. |
|
662 **/ |
|
663 { |
|
664 TInt err=aContext.TransmitUA(); |
|
665 if(err!=KErrNone) |
|
666 { |
|
667 // We're unable to respond, so we need to error stuff |
|
668 SetState(aContext,CMuxChannelStateFactory::EError); |
|
669 aContext.iMux.MuxChannelError(ETrue, err); |
|
670 } |
|
671 else |
|
672 { |
|
673 aContext.DequeIdleTimer(); |
|
674 SetState(aContext,CMuxChannelStateFactory::EOpen); |
|
675 } |
|
676 aContext.iState->Enter(aContext); |
|
677 } |
|
678 |
|
679 void TMuxChannelStateLinkUp::DISC(CRfcommMuxChannel& /*aContext*/) |
|
680 /** |
|
681 We've received a DISC on DLCI 0. |
|
682 **/ |
|
683 { |
|
684 // Do nothing |
|
685 } |
|
686 |
|
687 void TMuxChannelStateLinkUp::IdleTimeout(CRfcommMuxChannel& aContext) |
|
688 /** |
|
689 We've been idle long enough. Bring it down... |
|
690 **/ |
|
691 { |
|
692 LOG(_L("RFCOMM: Shutting down mux channel link")); |
|
693 SetState(aContext,CMuxChannelStateFactory::EClosing); |
|
694 aContext.iSAP.Shutdown(CServProviderBase::ENormal); |
|
695 aContext.iState->Enter(aContext); |
|
696 } |
|
697 |
|
698 void TMuxChannelStateLinkUp::FrameTimeout(CRfcommMuxChannel& aContext, CRfcommFrame* /*aFrm*/) |
|
699 /** |
|
700 Needs to be over-ridden as parent 'Connected' state does too much! |
|
701 |
|
702 FIXME - Yeah, I know it's horrible but short of re-writing most of the |
|
703 mux channel states, what else can we do? |
|
704 **/ |
|
705 { |
|
706 // Do the basics... |
|
707 FrameTimeoutHelper(aContext); |
|
708 |
|
709 //... and don't go to ELinkUp 'cos we're already there. |
|
710 } |
|
711 |
|
712 /* |
|
713 Wait for UA to the SABM |
|
714 */ |
|
715 |
|
716 TMuxChannelStateWaitForSABMResp::TMuxChannelStateWaitForSABMResp(CMuxChannelStateFactory& aFactory) |
|
717 : TMuxChannelStateConnected(aFactory) |
|
718 { |
|
719 STATENAME("WaitForSABMResp"); |
|
720 } |
|
721 |
|
722 void TMuxChannelStateWaitForSABMResp::UA(CRfcommMuxChannel& aContext) |
|
723 /** |
|
724 The mux channel is up, we're done |
|
725 **/ |
|
726 { |
|
727 SetState(aContext,CMuxChannelStateFactory::EOpen); |
|
728 aContext.iState->Enter(aContext); |
|
729 } |
|
730 |
|
731 void TMuxChannelStateWaitForSABMResp::DM(CRfcommMuxChannel& aContext) |
|
732 /** |
|
733 Our SABM has failed. |
|
734 |
|
735 It would be a good idea to rip up this muxer now, since the other end |
|
736 is very unhappy. |
|
737 **/ |
|
738 { |
|
739 SetState(aContext,CMuxChannelStateFactory::EError); |
|
740 aContext.iMux.MuxChannelError(ETrue, KErrCouldNotConnect); |
|
741 aContext.iState->Enter(aContext); |
|
742 } |
|
743 |
|
744 void TMuxChannelStateWaitForSABMResp::SABM(CRfcommMuxChannel& aContext) |
|
745 /** |
|
746 Our SABMs have passed in the post. |
|
747 |
|
748 It's not clear whether the sender of the SABM gets to be |
|
749 initiator or not, we assume that it's the creator of the L2CAP |
|
750 channel which gets that honour. Since others may assume |
|
751 otherwise, the safest thing to do here is to rip up this mux |
|
752 and wait for it to go round again. |
|
753 **/ |
|
754 { |
|
755 SetState(aContext,CMuxChannelStateFactory::EError); |
|
756 aContext.iMux.MuxChannelError(ETrue, KErrCouldNotConnect); |
|
757 aContext.iState->Enter(aContext); |
|
758 } |
|
759 |
|
760 void TMuxChannelStateWaitForSABMResp::Close(CRfcommMuxChannel& aContext) |
|
761 { |
|
762 // We need to give up...pretend we never sent the SABM |
|
763 aContext.iClosePending = ETrue; |
|
764 aContext.iOpenPending = EFalse; |
|
765 SetState(aContext,CMuxChannelStateFactory::ELinkUp); |
|
766 aContext.iState->Enter(aContext); |
|
767 } |
|
768 |
|
769 void TMuxChannelStateWaitForSABMResp::DISC(CRfcommMuxChannel& aContext) |
|
770 /** |
|
771 DISC received. |
|
772 **/ |
|
773 { |
|
774 SetState(aContext,CMuxChannelStateFactory::EError); |
|
775 aContext.iMux.MuxChannelError(ETrue, KErrCouldNotConnect); |
|
776 aContext.iState->Enter(aContext); |
|
777 } |
|
778 |
|
779 /* |
|
780 Open - all systems are go. |
|
781 */ |
|
782 |
|
783 TMuxChannelStateOpen::TMuxChannelStateOpen(CMuxChannelStateFactory& aFactory) |
|
784 : TMuxChannelStateConnected(aFactory) |
|
785 { |
|
786 STATENAME("Open"); |
|
787 } |
|
788 |
|
789 void TMuxChannelStateOpen::Enter(CRfcommMuxChannel& aContext, TBool /*aDisconnectingIdleTimer*/) |
|
790 /** |
|
791 Entering the Open state. |
|
792 |
|
793 Let the mux know, unless we're supposed to be closing. |
|
794 **/ |
|
795 { |
|
796 aContext.iOpenPending=EFalse; // Since we're open now! |
|
797 if(!aContext.iClosePending) |
|
798 { |
|
799 aContext.iMux.MuxChannelUp(); |
|
800 } |
|
801 else |
|
802 { |
|
803 // We're going down again! |
|
804 Close(aContext); |
|
805 } |
|
806 } |
|
807 |
|
808 void TMuxChannelStateOpen::Close(CRfcommMuxChannel& aContext) |
|
809 /** |
|
810 Time's up. Go on down. |
|
811 **/ |
|
812 { |
|
813 aContext.iClosePending=ETrue; |
|
814 SetState(aContext,CMuxChannelStateFactory::ELinkUp); |
|
815 aContext.iState->Enter(aContext); |
|
816 } |
|
817 |
|
818 /** |
|
819 A SABM has been received for DLCI 0. |
|
820 We're already in Open state- the remote may have sent another SABM because we |
|
821 replied to the first SABM later than they expected. |
|
822 All we can reasonably do is reply with a UA. Just dropping the SABM might |
|
823 result in a timeout on the other end. |
|
824 We need to override the SABM method to avoid the base class implementation's |
|
825 panic. |
|
826 */ |
|
827 void TMuxChannelStateOpen::SABM(CRfcommMuxChannel& aContext) |
|
828 { |
|
829 static_cast<void>(aContext.TransmitUA()); |
|
830 // We don't care about the error here. |
|
831 // If the UA succeeded, we're already in the right state so no further |
|
832 // action is required. |
|
833 // If the UA failed, it doesn't matter as we're already in the right state |
|
834 // and the connection already exists from the original SABM. If the remote |
|
835 // times out the SABM it sent and consequently wants to pull down the |
|
836 // connection, that's their business. Anyway, there's nothing we can do |
|
837 // about it. |
|
838 } |
|
839 |
|
840 void TMuxChannelStateOpen::DISC(CRfcommMuxChannel& aContext) |
|
841 /** |
|
842 Remote end wants us to shut down |
|
843 **/ |
|
844 { |
|
845 aContext.TransmitUA(); // May fail |
|
846 SetState(aContext,CMuxChannelStateFactory::ELinkUp); |
|
847 aContext.iMux.CloseSAPs(); |
|
848 aContext.iState->Enter(aContext); |
|
849 } |
|
850 |
|
851 TBool TMuxChannelStateOpen::IsOpen(CRfcommMuxChannel& /*aContext*/) |
|
852 { |
|
853 return ETrue; |
|
854 } |
|
855 |
|
856 |
|
857 |
|
858 |
|
859 /* |
|
860 Closing down the channel |
|
861 */ |
|
862 |
|
863 TMuxChannelStateClosing::TMuxChannelStateClosing(CMuxChannelStateFactory& aFactory) |
|
864 : TMuxChannelStateConnected(aFactory) |
|
865 { |
|
866 STATENAME("Closing"); |
|
867 } |
|
868 |
|
869 void TMuxChannelStateClosing::FrameTimeout(CRfcommMuxChannel& aContext, CRfcommFrame* /*aFrm*/) |
|
870 /** |
|
871 Needs to be over-ridden as parent 'Connected' state does too much! |
|
872 |
|
873 FIXME - Yeah, I know it's horrible but short of re-writing most of the mux channel |
|
874 states, what else can we do? |
|
875 **/ |
|
876 { |
|
877 // Do the basics... |
|
878 FrameTimeoutHelper(aContext); |
|
879 |
|
880 //... and don't go to ELinkUp ('cos we're taking the link down!) |
|
881 } |
|
882 |
|
883 void TMuxChannelStateClosing::CanClose(CRfcommMuxChannel& aContext) |
|
884 /** |
|
885 The socket is closed down now - we can move back to closed. |
|
886 |
|
887 We tear up the muxer at this point, since the creator of the l2cap |
|
888 link is the one who acts as initiator for RFCOMM dlci assignment. |
|
889 This is configured on mux creation, so we can't go back from here to |
|
890 link up without changing it. |
|
891 **/ |
|
892 { |
|
893 SetState(aContext,CMuxChannelStateFactory::EClosed); |
|
894 aContext.iState->Enter(aContext); |
|
895 aContext.iMux.MuxChannelClosed(); |
|
896 } |
|
897 |
|
898 TBool TMuxChannelStateClosing::CanAttachSAP() |
|
899 { |
|
900 return EFalse; |
|
901 } |
|
902 |