bluetooth/btstack/rfcomm/rfcommmuxchannel.cpp
changeset 0 29b1cd4cb562
child 23 32ba20339036
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     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