bluetooth/btstack/l2cap/l2signalmgr.cpp
changeset 0 29b1cd4cb562
child 22 786b94c6f0a4
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 // Implements the l2cap Muxer.
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <bluetooth/logger.h>
       
    19 
       
    20 #include <math.h>
       
    21 
       
    22 #include <bluetooth/hci/aclpacketconsts.h>
       
    23 #include <bluetooth/aclsockaddr.h>
       
    24 
       
    25 #include "l2signalmgr.h"
       
    26 #include "L2CapPDU.h"
       
    27 #include "l2capLinkSignalHandler.h"
       
    28 #include "l2capSAPSignalHandler.h"
       
    29 #include "L2CapDataController.h"
       
    30 #include "l2capMuxController.h"
       
    31 #include "l2capEntityConfig.h"
       
    32 #include "l2cap.h"
       
    33 #include "l2util.h"
       
    34 #include "btconsts.h"
       
    35 #include "L2CapDebugControlInterface.h"
       
    36 
       
    37 #ifdef __FLOG_ACTIVE
       
    38 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
       
    39 #endif
       
    40 
       
    41 #ifdef _DEBUG
       
    42 PANICCATEGORY("l2cap");
       
    43 #endif
       
    44 
       
    45 CL2CAPMux* CL2CAPMux::NewL(CL2CAPMuxController& aMuxController, const TBTDevAddr& aAddr)
       
    46 	{
       
    47 	LOG_STATIC_FUNC
       
    48 	CL2CAPMux* sig=new (ELeave) CL2CAPMux(aMuxController, aAddr);
       
    49 	CleanupStack::PushL(sig);
       
    50 	sig->ConstructL();
       
    51 	CleanupStack::Pop();
       
    52 	return sig;
       
    53 	}
       
    54 
       
    55 CL2CAPMux::CL2CAPMux(CL2CAPMuxController& aMuxController, const TBTDevAddr& aAddr)
       
    56  : iMuxController(aMuxController),
       
    57    iLinkState(ELinkNone),
       
    58    iRemote(aAddr),
       
    59    iIdleTimerActive(EFalse),
       
    60    iDataHandlers(_FOFF(CL2CapBasicDataController, iLink)),
       
    61    iSapSignalHandlers(_FOFF(CL2CapSAPSignalHandler, iLink)),
       
    62    iPDUsWaitingResendQ(_FOFF(HL2CapPDU, iLink)),
       
    63    iPDUsWaitingSend(_FOFF(HL2CapPDU, iLink)),
       
    64    iTryToSendPriority(CActive::EPriorityHigh),
       
    65    iUpdateTryToSendPriority(EFalse),
       
    66    iNextCID(KL2CapDynamicCIDStart),
       
    67    iQlink(this)
       
    68 	{
       
    69 	LOG_FUNC
       
    70 	TCallBack cb(IdleTimerExpired, this);
       
    71 	iIdleTimerEntry.Set(cb);
       
    72 	
       
    73 #ifdef _DEBUG
       
    74 	// Set up the next CID to be one off of the wrap point to
       
    75 	// check that functionality
       
    76 	iNextCID = 0xfffe;
       
    77 	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EMuxes,
       
    78 	                             L2capDebugInfo::EAllocated));
       
    79 #endif	                             
       
    80 	}
       
    81 
       
    82 
       
    83 void CL2CAPMux::ConstructL()
       
    84 	{
       
    85 	LOG_FUNC
       
    86 	iBoundLinkSignalHandler = CL2CapLinkSignalHandler::NewL(this);
       
    87 	iFragmentSender = new (ELeave) HFragmentedPDUSender(*this);
       
    88 	TCallBack canSendCallBack(AsyncCallBackForTryToSend, this);
       
    89 	iAsyncCallBackForTryToSend = new (ELeave)CAsyncCallBack(canSendCallBack, iTryToSendPriority);
       
    90 	TCallBack idleMuxCallBack(AsyncCallBackForIdleMux, this);
       
    91 	iAsyncCallBackForIdleMux = new (ELeave)CAsyncCallBack(idleMuxCallBack, CActive::EPriorityHigh);	
       
    92 	}
       
    93 
       
    94 
       
    95 //Passive connections call this with a valid SAP 
       
    96 //Active connections pass NULL into this and one gets created.
       
    97 void CL2CAPMux::CompleteACLConnect(CServProviderBase* aSAP)
       
    98 	{
       
    99 	LOG_FUNC
       
   100 	__ASSERT_DEBUG(!iBoundSAP, Panic(EL2CAPLinkUpWhenNoLinkRequested));
       
   101 
       
   102 	if (!aSAP)
       
   103 		{
       
   104 		TRAPD(err, iBoundSAP = MuxController().Protocol().LowerProtocol()->NewSAPL(KSockBluetoothTypeACL));
       
   105 		if (err == KErrNone)
       
   106 			{
       
   107 			iBoundSAP->SetNotify(this);
       
   108 			
       
   109 			const TBTDevAddr& addr = iRemote;
       
   110 			TBTSockAddr sockAddr;
       
   111 			sockAddr.SetBTAddr(addr);
       
   112 			
       
   113 			TInt err = iBoundSAP->SetRemName(sockAddr);
       
   114 			__ASSERT_ALWAYS(!err, Panic(EL2CAPCouldNotSetBasebandAddress));
       
   115 
       
   116 			// tell the SAP what data we can handle
       
   117 			TACLSockAddr aclSock;
       
   118 			aclSock.SetPort(EACLPortL2CAP);
       
   119 			err = iBoundSAP->SetLocalName(aclSock);
       
   120 			iLinkState = ELinkPending;
       
   121 			iBoundSAP->ActiveOpen();
       
   122 			}
       
   123 		}
       
   124 	else
       
   125 		{
       
   126 		iBoundSAP = aSAP;	// we take ownership of this connected SAP
       
   127 		iBoundSAP->SetNotify(this);
       
   128 		iBoundSAP->Start();	// and open the passive connection
       
   129 		ConnectComplete();	// gets BB MTU and configures this Mux
       
   130 		}
       
   131 	
       
   132 	//Now the Link is up Subscribe for Physical Link Notifications
       
   133 	MuxController().Protocol().ControlPlane().SubscribePhysicalLink(*this, iRemote);	
       
   134 	}
       
   135 	
       
   136 	
       
   137 CL2CAPMux::~CL2CAPMux()
       
   138 	{
       
   139 	LOG_FUNC
       
   140 	__ASSERT_DEBUG(iDataHandlers.IsEmpty() && iSapSignalHandlers.IsEmpty(),
       
   141 	               Panic(EL2CAPMuxDeleteWithResourcesStillRegistered));
       
   142 
       
   143 	iAsyncCallBackForTryToSend->Cancel();
       
   144 	delete iAsyncCallBackForTryToSend;
       
   145 
       
   146 	iAsyncCallBackForIdleMux->Cancel();
       
   147 	delete iAsyncCallBackForIdleMux;
       
   148 	 
       
   149 	MuxController().Protocol().ControlPlane().UnsubscribePhysicalLink(*this,iRemote);
       
   150 	delete iBoundSAP;
       
   151 
       
   152 	// Remove timer entry if one has been queued.
       
   153 	CancelIdle();
       
   154 
       
   155 	iFragmentSender->PDUSenderFailed();
       
   156 	
       
   157 	// Some PDUs may hold a reference to this Mux.
       
   158 	TDblQueIter<HL2CapPDU> resendIter(iPDUsWaitingResendQ);
       
   159 	TDblQueIter<HL2CapPDU> sendIter(iPDUsWaitingSend);
       
   160 	HL2CapPDU* pduPtr;
       
   161 	
       
   162 	while((pduPtr = resendIter++) != NULL)
       
   163 		{
       
   164 		pduPtr->DeregisterPduOwner();
       
   165 		}
       
   166 	while((pduPtr = sendIter++) != NULL)
       
   167 		{
       
   168 		pduPtr->DeregisterPduOwner();
       
   169 		}
       
   170 	
       
   171 	iIncomingPDU.Free();
       
   172 	iMuxControllerLink.Deque();
       
   173 	delete iBoundLinkSignalHandler;
       
   174 	delete iFragmentSender;
       
   175 	
       
   176 #ifdef _DEBUG
       
   177 	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EMuxes,
       
   178 	                             L2capDebugInfo::EDeleted));
       
   179 #endif	                             
       
   180 	}
       
   181 
       
   182 
       
   183 TInt CL2CAPMux::SetOption(TUint level,TUint name,const TDesC8 &anOption)
       
   184 	{
       
   185 	LOG_FUNC
       
   186 	return iBoundSAP->SetOption(level, name, anOption);
       
   187 	}
       
   188 
       
   189 
       
   190 TInt CL2CAPMux::GetOption(TUint level,TUint name,TDes8& anOption) const
       
   191 	{
       
   192 	LOG_FUNC
       
   193 	return iBoundSAP->GetOption(level, name, anOption);
       
   194 	}
       
   195 
       
   196 
       
   197 void CL2CAPMux::DetachFromMux(CL2CapSAPSignalHandler& aSAPSigHandler)
       
   198 	{
       
   199 	LOG_FUNC
       
   200 	// Check if this SSH had a Echo Request outstanding.  If it did discard the 
       
   201 	// response when it arrives.
       
   202 	iBoundLinkSignalHandler->DeregisterOutstandingEchoRequests(aSAPSigHandler);
       
   203 	
       
   204 	if(Idle())
       
   205 		{
       
   206 		LOG(_L("CL2CAPMux: DetatchFromMux -- no current SAPs, queuing idle callback"));
       
   207 
       
   208 		// The Muxer will be destroyed and
       
   209 		// the ACL / baseband will be removed by CL2CAPMux::AsyncCallBackForIdleMux()...
       
   210 		iAsyncCallBackForIdleMux->CallBack();
       
   211 		}
       
   212 	else
       
   213 		{
       
   214 		LOG(_L("CL2CAPMux: DetatchFromMux -- still have SAPs present or are still sending data"));
       
   215 		}
       
   216 	}
       
   217 	
       
   218 TInt CL2CAPMux::MuxIdled()
       
   219 	{
       
   220 	LOG_FUNC
       
   221 
       
   222 	// register we have no intention of sending out for now..
       
   223 	// if data comes in we may if necessary send data later, in which 
       
   224 	// case we will reopen our link
       
   225 	if (iLinkState != ELinkNone)
       
   226 		{
       
   227 		LOG(_L("CL2CAPMux: MuxIdled -- iLinkState != ELinkNone"));
       
   228 
       
   229 		// Don't attempt to send anymore data.
       
   230 		iBoundLinkSignalHandler->FlushPendingCommands();
       
   231 		
       
   232 		// Shutdown the ACL.
       
   233 		iBoundSAP->Shutdown(CServProviderBase::EStopOutput); // we might get overtures back in
       
   234 		iLinkState = ELinkInbound;
       
   235 		}
       
   236 	else
       
   237 		{
       
   238 		delete this;
       
   239 		}
       
   240 	return KErrNone;
       
   241 	}
       
   242 
       
   243 TUint8 CL2CAPMux::NextSigId()
       
   244 	{
       
   245 	LOG_FUNC
       
   246 	// 0 is invalid, so don't use it
       
   247 	++iSigId;
       
   248 	if (iSigId == 0)
       
   249 		{
       
   250 		iSigId = 1;
       
   251 		}
       
   252 	LOG1(_L("L2CAP [l2signalmgr.cpp]: Next signalling Id is %d"), iSigId);
       
   253 	return iSigId;
       
   254 	}
       
   255 
       
   256 
       
   257 TBool CL2CAPMux::Idle()
       
   258 /**
       
   259 	Test to see if this L2CAP mux is no longer required.
       
   260 	If there are no SSHs connected to this muxer, shutdown the ACL
       
   261 **/
       
   262 	{
       
   263 	LOG_FUNC
       
   264 	return (iSapSignalHandlers.IsEmpty() &&
       
   265 			iLinkState != ELinkPending &&
       
   266 			!iFragmentSender->IsPDUBeingSent() &&
       
   267 			!iIdleTimerActive);
       
   268 	}
       
   269 
       
   270 void CL2CAPMux::StartIdleTimer()
       
   271 	{
       
   272 	LOG_FUNC
       
   273 	CancelIdle();
       
   274 	iIdleTimerActive = ETrue;
       
   275     BTSocketTimer::Queue(KL2MuxerIdleTimeout * KL2ProtocolSecondTimerMultiplier, iIdleTimerEntry);
       
   276 	}
       
   277 
       
   278 
       
   279 TInt CL2CAPMux::AsyncCallBackForIdleMux(TAny *aMuxer)
       
   280 /**
       
   281 	Static function called through TCallBack. aMuxer holds the muxer
       
   282 	that is idle. Ask mux to bring down its own link.
       
   283 */
       
   284 	{
       
   285 	LOG_STATIC_FUNC
       
   286 
       
   287 	CL2CAPMux* muxer = static_cast<CL2CAPMux*>(aMuxer);
       
   288 
       
   289 	if (muxer->Idle())
       
   290 		{
       
   291 		// We're (still) idle! Let's disconnect.
       
   292 		muxer->MuxIdled();
       
   293 		}
       
   294 	return EFalse;	 // no more callbacks thanks!
       
   295 	}
       
   296 
       
   297 
       
   298 TInt CL2CAPMux::AsyncCallBackForTryToSend(TAny *aMuxer)
       
   299 /**
       
   300 	Static function called whenever idle processing can be scheduled.
       
   301 	This deals with doing async requests to send data over HCI,
       
   302 	notifications to SSHs 
       
   303 **/
       
   304 	{
       
   305 	LOG_STATIC_FUNC
       
   306 	CL2CAPMux* muxer = static_cast<CL2CAPMux*>(aMuxer);
       
   307 
       
   308 	muxer->TryToSend();
       
   309 	return EFalse;	// Don't call back any more.
       
   310 	}
       
   311 
       
   312 // from MSocketNotify
       
   313 void CL2CAPMux::ConnectComplete()
       
   314 /**
       
   315 	The link for this muxer has come up.
       
   316 	SSHs are notified by the protocol (who notifies us too).
       
   317 	Set the Idle timer going here, so if no SAP attaches to this
       
   318 	Mux, it'll just tidy itself up.
       
   319 **/
       
   320 	{
       
   321 	LOG_FUNC
       
   322 	__ASSERT_DEBUG(iLinkState != EConnected, Panic(EL2CAPLinkDownConnectComplete));
       
   323 
       
   324 	// Get the MTU
       
   325 	TPckgBuf<TInt> buf;
       
   326 
       
   327 	TInt err;
       
   328 
       
   329 	err = iBoundSAP->GetOption(KSolBtACL, ELMOutboundACLSize, buf);
       
   330 	ASSERT_DEBUG(!err);
       
   331 	iACLMTU = buf();
       
   332 
       
   333 	err = iBoundSAP->GetOption(KSolBtACL, ELMInboundACLSize, buf);
       
   334 	ASSERT_DEBUG(!err);
       
   335 	iACLMRU = buf();
       
   336 
       
   337 	(void)(err != KErrNone); // keep the compiler happy by taking err as an r-value in urel
       
   338 
       
   339 	iLinkState = EConnected;
       
   340 
       
   341 	// Send an Information Request as soon as possible.
       
   342 	TL2CapEntityInfo info;
       
   343 	iBoundLinkSignalHandler->PeerEntityConfig().PeerL2CapSupportedFeatures(info);
       
   344 	
       
   345 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
   346 	sapSignalIter.SetToFirst();
       
   347 	CL2CapSAPSignalHandler* sapPtr;
       
   348 	
       
   349 	while((sapPtr = sapSignalIter++) != NULL)
       
   350 		{
       
   351 		sapPtr->LinkUp();
       
   352 		}
       
   353 	
       
   354 	// No point hanging around if nobody actually connects to us!
       
   355 	// Mainly useful for incoming connections
       
   356 	if(Idle())
       
   357 		{
       
   358 		StartIdleTimer();
       
   359 		}
       
   360 	}
       
   361 
       
   362 void CL2CAPMux::NewL2CAPData(RMBufChain& aData, TUint8 aFlag)
       
   363 	{
       
   364 	LOG_FUNC
       
   365 	TUint8 l2Flags = static_cast<TUint8>(aFlag>>KPacketPBBCFlagShift & KPacketPBFlagMask);
       
   366 	LOG1(_L("L2CAP Mux received data with flags, %x"), aFlag);
       
   367 
       
   368 	switch(l2Flags)
       
   369 		{
       
   370 		case KFirstHLFragment:
       
   371 			// This is the start of a PDU.  If an incoming PDU already exists
       
   372 			// delete it and start a new one.
       
   373 			if(!iIncomingPDU.IsEmpty())
       
   374 				{
       
   375 				LOG(_L("L2CAP [l2signalmgr.cpp]: Warning: Dropped previous incoming packet - start of next packet received"));
       
   376 
       
   377 				iIncomingPDU.Free();
       
   378 				}
       
   379 			break;
       
   380 
       
   381 		case KContinuingHLFragment:
       
   382 			// This is a continuation so an existing PDU should exist.
       
   383 			// If it doesn't drop this data and wait for the next start of 
       
   384 			// PDU.
       
   385 			if(iIncomingPDU.IsEmpty())
       
   386 				{
       
   387 				LOG(_L("L2CAP [l2signalmgr.cpp]: Warning: Continuation fragment received and dropped - waiting for start"));
       
   388 	
       
   389 				aData.Free();
       
   390 				return;
       
   391 				}
       
   392 			break;
       
   393 
       
   394 		default:
       
   395 			LOG1(_L("L2CAP [l2signalmgr.cpp] Warning: Unexpected ACL packet type received: %d"), aFlag);
       
   396 			return;
       
   397 		};
       
   398 
       
   399 	if(HL2CapPDU::AddFragment(iIncomingPDU, aData))
       
   400 		{
       
   401 		// PDU complete.
       
   402 		PacketComplete();
       
   403 		__ASSERT_DEBUG(iIncomingPDU.IsEmpty(), Panic(EL2CAPPacketCompleteFailedToConsumeIncomingPDU));
       
   404 		}
       
   405 	}
       
   406 	
       
   407 // A full packet is now in the buffer.  Process it
       
   408 void CL2CAPMux::PacketComplete()
       
   409 	{
       
   410 	LOG_FUNC
       
   411 	TBool packetDelivered = EFalse;
       
   412 	
       
   413 	if(iIncomingPDU.Length() >= HL2CapPDU::KPDUHeaderLength)
       
   414 		{
       
   415 		iIncomingPDU.Align(HL2CapPDU::KPDUHeaderLength);
       
   416 		TUint16 cid = HL2CapPDU::PDUCID(iIncomingPDU);
       
   417 
       
   418 		switch(cid)
       
   419 			{
       
   420 			case KL2CapSignallingCID:
       
   421 				{
       
   422 				// This is a signalling packet
       
   423 				HCFramePDU* cFramePtr = new HCFramePDU(iIncomingPDU, iACLMTU);
       
   424 				if(cFramePtr)
       
   425 					{
       
   426 					cFramePtr->CheckDecode();
       
   427 					if(cFramePtr->HasCommands())
       
   428 						{
       
   429 						// The C-Frame can contain many L2CAP commands.  Not all of
       
   430 						// the commands will be for a SAP signal handler.  If a
       
   431 						// command can be processed it will be removed from the
       
   432 						// C-Frame.  Any remaining commands will be offered to the
       
   433 						// other SAP signal handlers, then the whole process of
       
   434 						// offering the commands to the SAP signal handlers is
       
   435 						// repeated until no more commands can be handled by them,
       
   436 						// after which the commands are offered to the link signal
       
   437 						// handler.  Only one command is handled at a time because a
       
   438 						// Command Reject may delete a SAP signal handler, thereby
       
   439 						// rendering it ineffective at processing further commands.
       
   440 
       
   441 						TBool commandsWereHandled;
       
   442 						TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
   443 						CL2CapSAPSignalHandler* sshPtr;
       
   444 						do
       
   445 							{
       
   446 							commandsWereHandled = EFalse;
       
   447 							sapSignalIter.SetToFirst();
       
   448 							while (!packetDelivered && (sshPtr = sapSignalIter++) != NULL)
       
   449 								{
       
   450 								commandsWereHandled |= sshPtr->HandleIncomingCFrame(cFramePtr);
       
   451 
       
   452 								// If all commands from the C-Frame have been processed then
       
   453 								// consider the packet delivered.
       
   454 								packetDelivered = !cFramePtr->HasCommands();
       
   455 								}
       
   456 							}
       
   457 						while (!packetDelivered && commandsWereHandled);
       
   458 
       
   459 						if (!packetDelivered)
       
   460 							{
       
   461 							// Offer the remaining commands to the link signal handler.
       
   462 							while (iBoundLinkSignalHandler->HandleIncomingCFrame(cFramePtr))
       
   463 								;
       
   464 							}
       
   465 						}
       
   466 
       
   467 					// Delete the CFrame.
       
   468 					delete cFramePtr;
       
   469 					}
       
   470 				else
       
   471 					{
       
   472 					ErrorAllSignalHandlers(KErrNoMemory);
       
   473 					iIncomingPDU.Free();
       
   474 					}
       
   475 				}
       
   476 				break;
       
   477 
       
   478 			case KL2CapConnectionlessCID:
       
   479 				// Connectionless L2CAP is not currently supported.
       
   480 				iIncomingPDU.Free();
       
   481 				break;
       
   482 
       
   483 			default:
       
   484 				{
       
   485 				if(cid >= KL2CapDynamicCIDStart)
       
   486 					{
       
   487 					// This is a data frame.
       
   488 					TDblQueIter<CL2CapBasicDataController> dataControllerIter(iDataHandlers);
       
   489 					CL2CapBasicDataController* dcPrt;
       
   490 					while((dcPrt = dataControllerIter++) != NULL && !packetDelivered)
       
   491 						{
       
   492 						packetDelivered = dcPrt->HandleIncomingDataFrame(iIncomingPDU);
       
   493 						}
       
   494 					}
       
   495 
       
   496 				if(!packetDelivered)
       
   497 					{
       
   498 					// This data frame was not for any channel or was using an
       
   499 					// invalid CID.  Drop it.
       
   500 					iIncomingPDU.Free();
       
   501 					}
       
   502 				}
       
   503 				break;
       
   504 			};
       
   505 		}
       
   506 	else
       
   507 		{
       
   508 		// Invalid PDU length.  Drop it.
       
   509 		iIncomingPDU.Free();
       
   510 		}
       
   511 	}
       
   512 
       
   513 void CL2CAPMux::ErrorAllSignalHandlers(TInt aError)
       
   514 	{
       
   515 	LOG_FUNC
       
   516 	TDblQueIter<CL2CapSAPSignalHandler> iter(iSapSignalHandlers);
       
   517 	CL2CapSAPSignalHandler* sapPtr;
       
   518 	while((sapPtr = iter++) != NULL)
       
   519 		{
       
   520 		sapPtr->Error(aError, MSocketNotify::EErrorAllOperations);
       
   521 		}
       
   522 	iBoundLinkSignalHandler->Error(aError, MSocketNotify::EErrorAllOperations);
       
   523 	}
       
   524 
       
   525 
       
   526 
       
   527 void CL2CAPMux::NewData(TUint aCount)
       
   528 	{
       
   529 	LOG_FUNC
       
   530 	__ASSERT_DEBUG(iBoundSAP, Panic(EL2CAPUnexpectedSocketUpcall));
       
   531 
       
   532 	// got data in - we may have half-shutdown (in which case link is ENone(!)
       
   533 	// reactivate link as we're likely to send out data - we're unlikely to be
       
   534 	// going idle at this rate
       
   535 	if (iLinkState == ELinkInbound)
       
   536 		{
       
   537 		// to regain full duplex
       
   538 		iBoundSAP->ActiveOpen();
       
   539 		}
       
   540 
       
   541 	while (aCount)
       
   542 		{
       
   543 		RMBufChain recvBuffer;
       
   544 		// Params: data, length, options, aAddr.
       
   545 		// Of these only data is used in CACLLink::GetData()
       
   546 		iBoundSAP->GetData(recvBuffer, 0, 0, NULL);
       
   547 
       
   548 		LOG(_L("CL2CAPMux: Getting data from bound SAP"))
       
   549 
       
   550 		// we get a datagram
       
   551 		// format...
       
   552 		// |-----|------------------/
       
   553 		// |flag |data              /
       
   554 		// |-----|------------------/
       
   555 
       
   556 		ASSERT_DEBUG(recvBuffer.Length()>=1);
       
   557 		LOG1(_L("CL2CAPMux: Got data length, %d"), recvBuffer.Length())
       
   558 		TUint8 flags = (recvBuffer.First())->Ptr()[0];
       
   559 		recvBuffer.TrimStart(1);		// Remove the flags
       
   560 		NewL2CAPData(recvBuffer, flags);
       
   561 		
       
   562 		aCount--;
       
   563 		}
       
   564 	}
       
   565 
       
   566 void CL2CAPMux::ConnectComplete(const TDesC8& /*aConnectData*/)
       
   567 	{
       
   568 	LOG_FUNC
       
   569 #ifdef _DEBUG
       
   570 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   571 #endif
       
   572 	}
       
   573 
       
   574 void CL2CAPMux::ConnectComplete(CServProviderBase& /*aSSP*/)
       
   575 	{
       
   576 	LOG_FUNC
       
   577 	// passive connects should come via the listener
       
   578 #ifdef _DEBUG
       
   579 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   580 #endif
       
   581 	}
       
   582 
       
   583 void CL2CAPMux::ConnectComplete(CServProviderBase& /*aSSP*/,const TDesC8& /*aConnectData*/)
       
   584 	{
       
   585 	LOG_FUNC
       
   586 #ifdef _DEBUG
       
   587 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   588 #endif
       
   589 	}
       
   590 
       
   591 void CL2CAPMux::CanClose(TDelete aDelete)
       
   592 	{
       
   593 	LOG_FUNC
       
   594 	if (aDelete == EDetach)
       
   595 		{
       
   596 		// so we don't delete the bound SAP - it's decided to own itself
       
   597 		iBoundSAP = NULL;
       
   598 		}
       
   599 	// Delete the Mux.	
       
   600 	delete this;
       
   601 	}
       
   602  
       
   603 void CL2CAPMux::CanSend()
       
   604 	{
       
   605 	LOG_FUNC
       
   606 	iAsyncCallBackForTryToSend->CallBack();
       
   607 	}
       
   608 	
       
   609 void CL2CAPMux::TryToSend()
       
   610 /**
       
   611    We may now be able to send data.
       
   612    Drain out the Q while we don't get an error on write.
       
   613    Deal with sent packets: either delete, or put onto response pendingQ
       
   614    if the ResponseIsExpected flag is set.
       
   615 **/
       
   616 	{
       
   617 	LOG_FUNC
       
   618 	__ASSERT_DEBUG(iACLMTU, Panic(EL2CAPZeroAclMtuInTryToSend)); // zero would be useless...
       
   619 
       
   620 	TBool flowControlledOff = EFalse;
       
   621 
       
   622 	TBool dataToSend = ETrue;
       
   623 
       
   624 	TDblQueIter<CL2CapSAPSignalHandler> sigIter(iSapSignalHandlers);
       
   625 	TDblQueIter<CL2CapBasicDataController> dcIter(iDataHandlers);
       
   626 
       
   627 	HL2CapPDU* pduToSend = NULL;
       
   628 
       
   629 	if(iUpdateTryToSendPriority && !iAsyncCallBackForTryToSend->IsActive())
       
   630 		{
       
   631 		iAsyncCallBackForTryToSend->SetPriority(iTryToSendPriority);
       
   632 		iUpdateTryToSendPriority = EFalse;
       
   633 		}
       
   634 		
       
   635 	while(dataToSend && !flowControlledOff)
       
   636 		{
       
   637 		if(!iFragmentSender->IsPDUBeingSent())
       
   638 			{
       
   639 			pduToSend = iBoundLinkSignalHandler->GetPDU();
       
   640 			if(!pduToSend && !iSapSignalHandlers.IsEmpty())
       
   641 				{
       
   642 				//Check to see if there are any signalling packets ready
       
   643 				sigIter.SetToFirst();
       
   644 				
       
   645 				CL2CapSAPSignalHandler* sapPtr;
       
   646 				while((sapPtr = sigIter++) != NULL && !pduToSend)
       
   647 					{
       
   648 					pduToSend = sapPtr->GetPDU();
       
   649 					}
       
   650 				}
       
   651 
       
   652 			if(!pduToSend && !iDataHandlers.IsEmpty())
       
   653 				{
       
   654 				// This data is prioritised.
       
   655 				dcIter.SetToFirst();
       
   656 				
       
   657 				CL2CapBasicDataController* dcPtr;
       
   658 				while((dcPtr = dcIter++) != NULL && !pduToSend)
       
   659 					{
       
   660 					pduToSend = dcPtr->GetPdu();
       
   661 					// If the next controller in the ordered list has the same priority
       
   662 					// Remove this one and move it to the end of the controllers with
       
   663 					// equal priority.
       
   664 					if(pduToSend && dcIter && 
       
   665 					   ((CL2CapBasicDataController*)dcIter)->Config().ChannelPriority() == dcPtr->Config().ChannelPriority())
       
   666 						{
       
   667 						dcPtr->iLink.Deque();
       
   668 						PriorityAddDataController(*dcPtr);
       
   669 						}
       
   670 					}
       
   671 				}
       
   672 				
       
   673 			if(pduToSend)
       
   674 				{
       
   675 				TInt err = iFragmentSender->FragmentPDU(*pduToSend);
       
   676 				if(err == KErrNone)
       
   677 					{
       
   678 					if (!pduToSend->HasOwner())
       
   679 						{
       
   680 						// If the data controller doesn't claim ownership of the PDU, we take over.
       
   681 						// DCs take care of I-Frames and we own pretty much everything else
       
   682 						// (B-,C-,S-Frames).
       
   683 						pduToSend->SetPduOwner(this);
       
   684 						iPDUsWaitingSend.AddLast(*pduToSend);
       
   685 						}
       
   686 					}
       
   687 				else
       
   688 					{
       
   689 					// Error all the SAPs
       
   690 					ErrorAllSignalHandlers(err);
       
   691 					delete pduToSend;
       
   692 					}
       
   693 				}
       
   694 			else
       
   695 				{
       
   696 				dataToSend = EFalse;
       
   697 				}
       
   698 			}
       
   699 
       
   700 		if(iFragmentSender->IsPDUBeingSent())
       
   701 			{
       
   702 			HFragmentedPDUSender::TFragmentSenderStatus rStatus = iFragmentSender->WriteNextFragment(*iBoundSAP, iACLMTU);
       
   703 			switch(rStatus)
       
   704 				{
       
   705 				case HFragmentedPDUSender::EFragmentOK:
       
   706 					break;
       
   707 					
       
   708 				case HFragmentedPDUSender::EFragmentationComplete:
       
   709 					__ASSERT_DEBUG(!iFragmentSender->IsPDUBeingSent(), Panic(EL2CAPPDUBeingSentAfterFragmentationComplete));
       
   710 
       
   711 					// Check if PDU's are still present in the re-send queue.
       
   712 					if(!iPDUsWaitingResendQ.IsEmpty())
       
   713 						{
       
   714 						pduToSend = iPDUsWaitingResendQ.First();
       
   715 						pduToSend->iLink.Deque();
       
   716 						TInt err = iFragmentSender->FragmentPDU(*pduToSend);
       
   717 						if(err == KErrNone)
       
   718 							{
       
   719 							__ASSERT_DEBUG(pduToSend->IsOwner(this), Panic(EL2CAPUnownedPduOnMuxQ));
       
   720 							iPDUsWaitingSend.AddLast(*pduToSend);
       
   721 							}
       
   722 						else
       
   723 							{
       
   724 							delete pduToSend;
       
   725 							// Error all the SAPs
       
   726 							ErrorAllSignalHandlers(err);
       
   727 							}
       
   728 						}
       
   729 					else
       
   730 						{
       
   731 						LOG(_L("CL2CAPMux: TryToSend -- finished sending a PDU, no more waiting"));
       
   732 
       
   733 						// If we have no PDUs to send, the last PDU *may* have been the last disconnect
       
   734 						// on the link.  This would mean that we have no SAPs left, so we can destroy the
       
   735 						// underlying ACL link.
       
   736 						
       
   737 						if(Idle())
       
   738 							{
       
   739 							LOG(_L("CL2CAPMux: TryToSend -- no current SAPs, queuing idle callback"));
       
   740 
       
   741 							// The Muxer will be destroyed and
       
   742 							// the ACL / baseband will be removed by CL2CAPMux::AsyncCallBackForIdleMux()...
       
   743 							iAsyncCallBackForIdleMux->CallBack();
       
   744 							}
       
   745 						else
       
   746 							{
       
   747 							LOG(_L("CL2CAPMux: TryToSend -- still have SAPs present"));
       
   748 							}
       
   749 						}
       
   750 					break;
       
   751 					
       
   752 				case HFragmentedPDUSender::EFlowControlledOff:
       
   753 					flowControlledOff = ETrue;
       
   754 					break;
       
   755 					
       
   756 				default:
       
   757 					Panic(EL2CAPInvalidHFragmentedPDUSenderStatusCode);
       
   758 					break;
       
   759 				};
       
   760 			}
       
   761 		}
       
   762 	}
       
   763 
       
   764 void CL2CAPMux::CanClose(const TDesC8& /*aDisconnectData*/, TDelete /*aDelete*/)
       
   765 	{
       
   766 	LOG_FUNC
       
   767 #ifdef _DEBUG
       
   768 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   769 #endif
       
   770 	}
       
   771 
       
   772 void CL2CAPMux::Error(TInt aError,TUint /*aOperationMask*/)
       
   773 /**
       
   774    The link has not come up.
       
   775    Error any SSHs that are hanging around.
       
   776 **/
       
   777 	{
       
   778 	LOG_FUNC
       
   779 	iLinkState = ELinkNone;
       
   780 
       
   781 	// In the case where a SAP requested a connection but then
       
   782 	// disconnected prior to the connection failing ensure that
       
   783 	// the idle timer is started.
       
   784 	if(Idle())
       
   785 		{
       
   786 		// The Muxer will be destroyed and
       
   787 		// the ACL / baseband will be removed by CL2CAPMux::AsyncCallBackForIdleMux()...
       
   788 		iAsyncCallBackForIdleMux->CallBack();
       
   789 		}	
       
   790 	else
       
   791 		{
       
   792 		// Leave Mux around - SSHs detach as necessary
       
   793 		ErrorAllSignalHandlers(aError);
       
   794 		}
       
   795 	}
       
   796 
       
   797 void CL2CAPMux::Disconnect()
       
   798 /**
       
   799    We no longer have a link to run on.
       
   800 **/
       
   801 	{
       
   802 	LOG_FUNC
       
   803 	__ASSERT_DEBUG(iLinkState == EConnected, Panic(EL2CAPLinkDownWhenNotUp));
       
   804 
       
   805 	// no link!
       
   806 	iLinkState = ELinkNone;
       
   807 
       
   808 	// Signal to all signal handlers that the link has gone.
       
   809 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
   810 	CL2CapSAPSignalHandler* sapPtr;
       
   811 
       
   812 	while((sapPtr = sapSignalIter++) != NULL)
       
   813 		{
       
   814 		sapPtr->Error(KErrHCILinkDisconnection, MSocketNotify::EErrorAllOperations);
       
   815 		}
       
   816 	iBoundLinkSignalHandler->Error(KErrHCILinkDisconnection, MSocketNotify::EErrorAllOperations);
       
   817 	delete this;
       
   818 	}
       
   819 
       
   820 
       
   821 TInt CL2CAPMux::IdleTimerExpired(TAny *aMuxer)
       
   822 /**
       
   823 	Idle timer has expired.
       
   824 	Static function called through TCallBack. aMuxer holds the muxer
       
   825 	that has actually expired. Ask mux to down its own link.
       
   826 **/
       
   827 	{
       
   828 	LOG_STATIC_FUNC
       
   829 	CL2CAPMux* muxer = static_cast<CL2CAPMux*>(aMuxer);
       
   830 	// record that no further idle timer is queued:
       
   831 	muxer->iIdleTimerActive = EFalse;
       
   832 
       
   833 	if (muxer->Idle())
       
   834 		{
       
   835 		// We're (still) idle! Lets disconnect.
       
   836 		muxer->MuxIdled();
       
   837 		}
       
   838 	return EFalse;	 // no more callbacks thanks!
       
   839 	}
       
   840 
       
   841 
       
   842 void CL2CAPMux::CancelIdle()
       
   843 	{
       
   844 	LOG_FUNC
       
   845 	if(iIdleTimerActive)
       
   846 		{
       
   847 		// there's something to cancel
       
   848 		iIdleTimerActive = EFalse;
       
   849 		BTSocketTimer::Remove(iIdleTimerEntry);
       
   850 		}
       
   851 	}
       
   852 
       
   853 
       
   854 
       
   855 void CL2CAPMux::Disconnect(TDesC8& /*aDisconnectData*/)
       
   856 	{
       
   857 	LOG_FUNC
       
   858 #ifdef _DEBUG
       
   859 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   860 #endif
       
   861 	}
       
   862 
       
   863 void CL2CAPMux::IoctlComplete(TDesC8* /*aBuf*/)
       
   864 	{
       
   865 	LOG_FUNC
       
   866 #ifdef _DEBUG
       
   867 		Panic(EL2CAPUnexpectedSocketUpcall);
       
   868 #endif
       
   869 	}
       
   870 
       
   871 void CL2CAPMux::NoBearer(const TDesC8& /*aConnectionInfo*/)
       
   872 	{
       
   873 	LOG_FUNC
       
   874 #ifdef _DEBUG
       
   875 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   876 #endif
       
   877 	}
       
   878 
       
   879 void CL2CAPMux::Bearer(const TDesC8& /*aConnectionInfo*/)
       
   880 	{
       
   881 	LOG_FUNC
       
   882 #ifdef _DEBUG
       
   883 	Panic(EL2CAPUnexpectedSocketUpcall);
       
   884 #endif
       
   885 	}
       
   886 
       
   887 void CL2CAPMux::HandlePduSendComplete(HL2CapPDU& aPdu)
       
   888 	{
       
   889 	LOG_FUNC
       
   890 	// We were honored with the ownership of the PDU, so it must be on our list.
       
   891 	aPdu.iLink.Deque(); 
       
   892 	delete &aPdu;
       
   893 	}
       
   894 
       
   895 void CL2CAPMux::HandlePduSendError(HL2CapPDU& aPdu)
       
   896 	{
       
   897 	LOG_FUNC
       
   898 	L2CAP_DEBUG(UpdateFlushCounters(L2capDebugInfo::EFlushedPDUMuxerResend));
       
   899 	// Note: this only handles PDUs we're the owner of.
       
   900 
       
   901 	// Delink it from iPDUsWaitingSendQ.
       
   902 	aPdu.iLink.Deque(); 
       
   903 
       
   904 #ifdef _DEBUG
       
   905 	// Check that the PDU does not already exist in the list.
       
   906 	TDblQueIter<HL2CapPDU> iter(iPDUsWaitingResendQ);
       
   907 	HL2CapPDU* pduPtr;
       
   908 		
       
   909 	while((pduPtr = iter++) != NULL)
       
   910 		{
       
   911 		if(pduPtr == &aPdu)
       
   912 			{
       
   913 			Panic(EL2CAPRequestToResendAPDUThatIsAlreadyInTheResendQueue);
       
   914 			}
       
   915 		}
       
   916 #endif
       
   917 	iPDUsWaitingResendQ.AddLast(aPdu);
       
   918 	}
       
   919 
       
   920 void CL2CAPMux::RegisterDataPDUHandler(CL2CapBasicDataController& aPDUDataHandler)
       
   921 	{
       
   922 	LOG_FUNC
       
   923 	PriorityAddDataController(aPDUDataHandler);
       
   924 	iNumberOfDataChannels++;
       
   925 	
       
   926 	iMuxController.UpdateMuxerPriorities();
       
   927 	}
       
   928 
       
   929 void CL2CAPMux::DataChannelRemoved(CL2CapBasicDataController* aDataController)
       
   930 	{
       
   931 	LOG_FUNC
       
   932 	aDataController->iLink.Deque();
       
   933 	iNumberOfDataChannels--;
       
   934 	
       
   935 	iMuxController.UpdateMuxerPriorities();
       
   936 	}
       
   937 
       
   938 void CL2CAPMux::ChannelPriorityUpdated(CL2CapBasicDataController& aDataController)
       
   939 	{
       
   940 	LOG_FUNC
       
   941 	// First remove the channel.
       
   942 	aDataController.iLink.Deque();
       
   943 
       
   944 	// Now re-register the channel with the Muxer.
       
   945 	RegisterDataPDUHandler(aDataController);
       
   946 	}
       
   947 	
       
   948 void CL2CAPMux::MuxerPriorityUpdate(TInt aPriority)
       
   949 	{
       
   950 	LOG_FUNC
       
   951 	iTryToSendPriority = aPriority;
       
   952 	if(!iAsyncCallBackForTryToSend->IsActive())
       
   953 		{
       
   954 		iAsyncCallBackForTryToSend->SetPriority(iTryToSendPriority);
       
   955 		}
       
   956 	else
       
   957 		{
       
   958 		iUpdateTryToSendPriority = ETrue;
       
   959 		}
       
   960 	}	
       
   961 
       
   962 TInt CL2CAPMux::GetSumMuxerChannelPriorities()
       
   963 	{
       
   964 	LOG_FUNC
       
   965 	// The sum is used to calculate the mux priority for inter-mux scheduling.
       
   966 	TInt prioritySum = 0;
       
   967 
       
   968 	TDblQueIter<CL2CapBasicDataController> dataControllerIter(iDataHandlers);
       
   969 	CL2CapBasicDataController* dcPrt;
       
   970 	while((dcPrt = dataControllerIter++) != NULL)
       
   971 		{
       
   972 		prioritySum += dcPrt->Config().ChannelPriority();
       
   973 		}
       
   974 
       
   975 	return prioritySum;
       
   976 	}	
       
   977 
       
   978 
       
   979 void CL2CAPMux::PDUAvailable()
       
   980 	{
       
   981 	LOG_FUNC
       
   982 	iAsyncCallBackForTryToSend->CallBack();
       
   983 	}
       
   984 
       
   985 TBool CL2CAPMux::HardwareFlushAllowed()
       
   986 // H/W flush allowed if no channel using Basic Mode.
       
   987 // Channels using flow control are deemed unreliable
       
   988 // so expect to be flushed if need be.
       
   989 // Channels using L2Cap retransmission are covered by that
       
   990 // retransmission, and so can have the current transmission
       
   991 // flushed if need be.
       
   992 	{
       
   993 	LOG_FUNC
       
   994 	TDblQueIter<CL2CapBasicDataController> iter(iDataHandlers);
       
   995 	CL2CapBasicDataController* handlerPtr;
       
   996 	TBool rerr = ETrue;
       
   997 	
       
   998 	while((handlerPtr = iter++) != NULL)
       
   999 		{
       
  1000 		if(handlerPtr->IsBasicDataVersion())
       
  1001 			{
       
  1002 			rerr = EFalse;
       
  1003 			break;
       
  1004 			}
       
  1005 		}
       
  1006 	return rerr;
       
  1007 	}
       
  1008 	
       
  1009 void CL2CAPMux::ProcessFlushTimerExpiry()
       
  1010 	{
       
  1011 	LOG_FUNC
       
  1012 	// The PDU currently being sent could have been flushed.  If it has
       
  1013 	// set the current outgoing PDU pointer to zero.
       
  1014 	iFragmentSender->CheckForFlushed();
       
  1015 	
       
  1016 	if(HardwareFlushAllowed())
       
  1017 		{
       
  1018 		iBoundSAP->SetOption(KSolBtACL, KSolBtACLFlushOccured, KNullDesC8);
       
  1019 		}
       
  1020 
       
  1021 	PDUAvailable();
       
  1022 	}
       
  1023 
       
  1024 void CL2CAPMux::RegisterSAPSignalHandler(CL2CapSAPSignalHandler& aSAPSigHandler)
       
  1025 	{
       
  1026 	LOG_FUNC
       
  1027 	// Cancel the idle timer if it is running.
       
  1028 	CancelIdle();
       
  1029 
       
  1030 #ifdef _DEBUG
       
  1031 	// Check that the SAP signal handler does not already exist in the list.
       
  1032 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
  1033 	while (sapSignalIter)
       
  1034 		{
       
  1035 		if (&aSAPSigHandler == sapSignalIter++)
       
  1036 			{
       
  1037 			Panic(EL2CAPSAPSignalHandlerRegisteredTwice);
       
  1038 			}
       
  1039 		}
       
  1040 #endif
       
  1041 	iSapSignalHandlers.AddLast(aSAPSigHandler);
       
  1042 	
       
  1043 	aSAPSigHandler.SAPSignalHandlerRegistered(*this, iBoundLinkSignalHandler->PeerEntityConfig());
       
  1044 	// If the ACL link is closing, re-open it by calling active
       
  1045 	// open.  If there is currently is no link and this Muxer
       
  1046 	// is configured for the desired remote address, then
       
  1047 	// call active open to establish a connection.
       
  1048 	if(iLinkState == ELinkInbound || 
       
  1049 	   ((iLinkState == ELinkNone) && iBoundSAP))
       
  1050 		{
       
  1051 		iLinkState = ELinkPending;
       
  1052 		iBoundSAP->ActiveOpen();
       
  1053 		}
       
  1054 	else
       
  1055 		{
       
  1056 		// The link is already up.  Inform the SAP signal handler.	
       
  1057 		if(iLinkState == EConnected)
       
  1058 			{
       
  1059 			aSAPSigHandler.LinkUp();
       
  1060 			}
       
  1061 		}
       
  1062 	}
       
  1063 	
       
  1064 void CL2CAPMux::L2CapEntityConfigUpdated()
       
  1065 	{
       
  1066 	LOG_FUNC
       
  1067 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
  1068 	sapSignalIter.SetToFirst();
       
  1069 	CL2CapSAPSignalHandler* sapPtr;
       
  1070 		
       
  1071 	while((sapPtr = sapSignalIter++) != NULL)
       
  1072 		{
       
  1073 		sapPtr->L2CapEntityConfigUpdated();
       
  1074 		}
       
  1075 	}
       
  1076 
       
  1077 TUint16 CL2CAPMux::SigMTU() const
       
  1078 	{
       
  1079 	LOG_FUNC
       
  1080 	return iBoundLinkSignalHandler->SigMTU();
       
  1081 	}
       
  1082 
       
  1083 TInt CL2CAPMux::SendEchoRequest(const TDes8* aData, CL2CapSAPSignalHandler& aEchoResponseHandler)
       
  1084 	{
       
  1085 	LOG_FUNC
       
  1086 	return iBoundLinkSignalHandler->ConstructEchoRequest(aData, aEchoResponseHandler);
       
  1087 	}
       
  1088 
       
  1089 void CL2CAPMux::EchoResponseReceived(const TDesC8* aData, MEchoResponseHandler& aEchoResponseHandler)
       
  1090 	{
       
  1091 	LOG_FUNC
       
  1092 	// Pass the response to the originator.
       
  1093 	aEchoResponseHandler.EchoResponseReceived(aData);
       
  1094 	}
       
  1095 
       
  1096 TInt CL2CAPMux::GetFreeCID(TL2CAPPort& aReturnPort)
       
  1097 	{
       
  1098 	LOG_FUNC
       
  1099 	TBool CIDIsFree;
       
  1100 	TL2CAPPort startCID = iNextCID;
       
  1101 	
       
  1102 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
  1103 	CL2CapSAPSignalHandler* handler;
       
  1104 
       
  1105 	aReturnPort = 0;
       
  1106 	do
       
  1107 		{
       
  1108 		sapSignalIter.SetToFirst();
       
  1109 		CIDIsFree = ETrue;
       
  1110 		while((handler = sapSignalIter++) != NULL)
       
  1111 			{
       
  1112 			if(handler->LocalPort()	== iNextCID)
       
  1113 				{
       
  1114 				CIDIsFree = EFalse;
       
  1115 				break;
       
  1116 				}
       
  1117 			}
       
  1118 
       
  1119 		if(CIDIsFree)
       
  1120 			{
       
  1121 			aReturnPort = iNextCID;
       
  1122 			}
       
  1123 
       
  1124 		if(iNextCID++ == KL2CapDynamicCIDEnd)
       
  1125 			{
       
  1126 			iNextCID = KL2CapDynamicCIDStart;
       
  1127 			}
       
  1128 		} while(!aReturnPort && startCID != iNextCID);
       
  1129 
       
  1130 	return aReturnPort?KErrNone:KErrL2CAPNoFreeCID;
       
  1131 	}
       
  1132 
       
  1133 TInt CL2CAPMux::GetACLMTU() const
       
  1134 	{
       
  1135 	return iACLMTU;
       
  1136 	}
       
  1137 
       
  1138 CL2CapSAPSignalHandler* CL2CAPMux::GetSignalHandlerWithRemoteCID(TL2CAPPort aRemoteCID)
       
  1139 	{
       
  1140 	LOG_FUNC
       
  1141 	TDblQueIter<CL2CapSAPSignalHandler> sapSignalIter(iSapSignalHandlers);
       
  1142 	sapSignalIter.SetToFirst();
       
  1143 	CL2CapSAPSignalHandler* sapPtr;
       
  1144 	
       
  1145 	while((sapPtr = sapSignalIter++) != NULL)
       
  1146 		{
       
  1147 		if(sapPtr->RemotePort() == aRemoteCID)
       
  1148 			{
       
  1149 			break;
       
  1150 			}
       
  1151 		}	
       
  1152 	// returns CL2CapSAPSignalHandler with matching remote CID or NULL if one not found
       
  1153 	return sapPtr;
       
  1154 	}
       
  1155 
       
  1156 // Adds the data controller to the Muxers list in priority order.
       
  1157 // If a Data controller of equal priority in the queue, the new one 
       
  1158 // will be added after it.
       
  1159 void CL2CAPMux::PriorityAddDataController(CL2CapBasicDataController& aDataController)
       
  1160 	{
       
  1161 	LOG_FUNC
       
  1162 	if(iDataHandlers.IsEmpty())
       
  1163 		{
       
  1164 		iDataHandlers.AddFirst(aDataController);
       
  1165 		}
       
  1166 	else
       
  1167 		{
       
  1168 		TUint8 channelPriority = aDataController.Config().ChannelPriority();
       
  1169 		
       
  1170 		TDblQueIter<CL2CapBasicDataController> iter(iDataHandlers);
       
  1171 		CL2CapBasicDataController* handler;
       
  1172 
       
  1173 		if(channelPriority > (iter++)->Config().ChannelPriority())
       
  1174 			{
       
  1175 			iDataHandlers.AddFirst(aDataController);
       
  1176 			}
       
  1177 		else
       
  1178 			{
       
  1179 			TBool controllerAdded = EFalse;
       
  1180 			while((handler = iter++) != NULL && !controllerAdded)
       
  1181 				{
       
  1182 				if(channelPriority > handler->Config().ChannelPriority())
       
  1183 					{
       
  1184 					handler->iLink.AddBefore(&(aDataController.iLink));
       
  1185 					controllerAdded = ETrue;
       
  1186 					}
       
  1187 				}
       
  1188 			if(!controllerAdded)
       
  1189 				{
       
  1190 				iDataHandlers.AddLast(aDataController);
       
  1191 				}
       
  1192 			}
       
  1193 		}
       
  1194 	}
       
  1195 	
       
  1196 	
       
  1197 void CL2CAPMux::PhysicalLinkChange(const TBTBasebandEventNotification& aEvent, CPhysicalLink& /*aPhysicalLink*/)
       
  1198 	{
       
  1199 	LOG_FUNC
       
  1200 	
       
  1201 	if (aEvent.EventType() & ENotifySniffMode)
       
  1202 		{
       
  1203 		//Entered SniffMode
       
  1204 		TPckgBuf<TBasebandTime> buf = 0;
       
  1205 		TInt err = iBoundSAP->GetOption(KSolBtLM, EBBGetSniffInterval, buf);
       
  1206 		__ASSERT_DEBUG(!err, Panic(EL2CAPGetOptionFailed));
       
  1207 		if (KErrNone==err)
       
  1208 			{
       
  1209 			iSniffInterval = buf();
       
  1210 			}
       
  1211 		}
       
  1212 		
       
  1213 	if ((aEvent.EventType() & ENotifyActiveMode) && iSniffInterval)
       
  1214 		{
       
  1215 		//Exited SniffMode
       
  1216 		iSniffInterval = 0;
       
  1217 		}
       
  1218 	}
       
  1219 	
       
  1220 TUint8 CL2CAPMux::AdjustRTXTimerForSniffMode(TUint8 aBaseRTXTimerDuration) const
       
  1221 	{
       
  1222 	LOG_FUNC
       
  1223 	TUint8 sniffModeRTXTimerDuration = aBaseRTXTimerDuration;
       
  1224 	
       
  1225 	if (iSniffInterval != 0)
       
  1226 		{		
       
  1227 		// RTX Timer value must be set to at least twice the sniff interval to allow
       
  1228 		// us to send a request in one transmission slot and for the remote device
       
  1229 		// to respond in the next. This assumes that the remote device can turn around the
       
  1230 		// request in one sniff interval but if we have a small interval this may not
       
  1231 		// be the case so we need to add a constant to allow for the remote to process the
       
  1232 		// request.
       
  1233 		TReal sniffModeAdjustment = (iSniffInterval * KBasebandSlotTime * 2) + KRemoteDeviceProcessRequestDuration;
       
  1234 		
       
  1235 		sniffModeRTXTimerDuration = Max(ceil(sniffModeAdjustment),aBaseRTXTimerDuration);
       
  1236 		}
       
  1237 		
       
  1238 	return sniffModeRTXTimerDuration;
       
  1239 	}