--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/l2capLinkSignalHandler.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,552 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <bluetooth/logger.h>
+
+#include "l2capLinkSignalHandler.h"
+
+#include "l2capSAPSignalHandler.h"
+
+#include "l2capSigPacketEcho.h"
+#include "l2capSigPacketInformation.h"
+#include "l2capSigPacketConnection.h"
+#include "l2capSigPacketConfigure.h"
+#include "l2capSigPacketDisconnection.h"
+#include "l2capSigPacketCommandReject.h"
+
+#include "l2capCommand.h"
+
+#include "l2capMuxController.h"
+#include "l2signalmgr.h"
+
+#include "l2capEntityConfig.h"
+
+#include "l2util.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
+#endif
+
+CL2CapLinkSignalHandler* CL2CapLinkSignalHandler::NewL(CL2CAPMux* aMuxer)
+ {
+ LOG_STATIC_FUNC
+ CL2CapLinkSignalHandler* linkSigHandler=new (ELeave) CL2CapLinkSignalHandler(aMuxer);
+ CleanupStack::PushL(linkSigHandler);
+ linkSigHandler->ConstructL();
+ CleanupStack::Pop();
+ return linkSigHandler;
+ }
+
+CL2CapLinkSignalHandler::~CL2CapLinkSignalHandler()
+ {
+ LOG_FUNC
+ DeleteCommands(iPendingCommands);
+ DeleteCommands(iCommandsAwaitingResponse);
+ }
+
+
+
+void CL2CapLinkSignalHandler::ConstructL()
+ {
+ LOG_FUNC
+ }
+
+// Disable warning WINS 4355: 'this' : used in base member initializer list
+// This will not cause any problems in this usage and is preferable to the use of a
+// non-owned pointer.
+#pragma warning (disable: 4355)
+CL2CapLinkSignalHandler::CL2CapLinkSignalHandler(CL2CAPMux* aMuxer)
+ : CL2CapSignalHandler(aMuxer),
+ iPeerL2CapEntityConfig(*this),
+ iSigMTU(KL2MinMTU)
+ {
+ LOG_FUNC
+ }
+#pragma warning (default: 4355)
+
+
+TBool CL2CapLinkSignalHandler::HandleConnectionRequest(HConnectionRequest* aConnectionRequest)
+ {
+ LOG_FUNC
+ const TL2CAPPort scid = aConnectionRequest->SourceCID();
+ const TInt8 id = aConnectionRequest->ID();
+ TBool scidValid = ETrue;
+
+ if(scid < KL2CapDynamicCIDStart)
+ {
+ scidValid = EFalse;
+ }
+ else
+ {
+ CL2CapSAPSignalHandler* listeningSH = iMuxer->MuxController().FindListeningSignalHandler(aConnectionRequest->PSM());
+ if(!listeningSH)
+ {
+ // Create a Connection Response Command
+ HL2CapCommand* command = HConnectionResponse::New(id, 0, scid, EConnectPSMNotSupported);
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+ }
+ else
+ {
+ // Does given CID already exist in the queue?
+ CL2CapSAPSignalHandler* sh = iMuxer->GetSignalHandlerWithRemoteCID(scid);
+ if (sh)
+ {
+ // ... it does: check whether the Connection Request is a retransmission
+ // (and retransmit the response if so), or a new command (illegal - send CmdRej).
+ if (!sh->IsDuplicateCommandRequest(aConnectionRequest))
+ {
+ LOG1(_L("Received a new Connection Request for an existing CID: 0x%04x"), scid)
+ scidValid = EFalse;
+ }
+ }
+ else
+ {
+ LOG1(_L("Remote CID (0x%04x) is free"),scid)
+ // Usual case, remote CID is free.
+ TInt err = listeningSH->PassiveConnectionRequest(iMuxer->RemoteBTAddr(), aConnectionRequest);
+ if(err != KErrNone)
+ {
+ HL2CapCommand* command = HConnectionResponse::New(id, 0, scid, EConnectPSMNotSupported);
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+ }
+ // If the command could not be created the connection will fail in the
+ // signalling state machine.
+ }
+ }
+ }
+
+ if (!scidValid)
+ {
+ TL2CAPCommandRejectData reason;
+ reason.iReason = EInvalidCID;
+ reason.iLocalEndpoint = 0;
+ reason.iRemoteEndpoint = scid;
+ reason.iMTUExceeded = 0;
+
+ HL2CapCommand* command = HCommandReject::New(reason, id);
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+ }
+
+ // Always return true. This is the only signal handler
+ // that can process this command.
+ return ETrue;
+ }
+
+TInt CL2CapLinkSignalHandler::ConstructEchoRequest(const TDes8* aData, MEchoResponseHandler& aEchoResponseHandler)
+ {
+ LOG_FUNC
+ TInt rerr = KErrNone;
+ HEchoRequest* command = NULL;
+
+ if(aData)
+ {
+ RMBufChain data;
+ TRAP(rerr, data.CreateL(*aData));
+ if(rerr == KErrNone)
+ {
+ command = HEchoRequest::New(data, CurrentRTXTimerDuration(HL2CapCommand::KDefaultRTXTimerDuration));
+ }
+ }
+ else
+ {
+ command = HEchoRequest::New();
+ }
+
+ if(rerr == KErrNone)
+ {
+ if(command)
+ {
+ command->SetEchoResponseHandler(aEchoResponseHandler);
+ AddToOutgoingQueue(command);
+ }
+ else
+ {
+ rerr = KErrNoMemory;
+ }
+ }
+ return rerr;
+ }
+
+void CL2CapLinkSignalHandler::DeregisterOutstandingEchoRequests(MEchoResponseHandler& aEchoResponseHandler)
+ {
+ LOG_FUNC
+ // Find any Echo Request and if the calling reference matches set
+ // it to NULL.
+ HL2CapCommand* l2CapCommand;
+
+ TDblQueIter<HL2CapCommand> iter(iCommandsAwaitingResponse);
+ while((l2CapCommand = iter++) != NULL)
+ {
+ if(l2CapCommand->Code() == EEchoRequest)
+ {
+ HEchoRequest* request = static_cast<HEchoRequest*>(l2CapCommand);
+ if(request->EchoResponseHandler() == &aEchoResponseHandler)
+ {
+ // Found a matching request - there can only be one so stop searching.
+ request->RemoveEchoResponseHandler();
+ break;
+ }
+ }
+ }
+ }
+
+TBool CL2CapLinkSignalHandler::HandleEchoResponse(HEchoResponse* aEchoResponse)
+ {
+ LOG_FUNC
+ // Check that the Echo Response has been requested.
+ HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EEchoRequest, aEchoResponse->ID());
+ if(requestCommand)
+ {
+ HEchoRequest* request = static_cast<HEchoRequest*>(requestCommand);
+ if(request->EchoResponseHandler())
+ {
+ RMBufChain data;
+ HBufC8* echoDataBuf = NULL;
+ if(aEchoResponse->GetData(data) == KErrNone)
+ {
+ echoDataBuf = HBufC8::New(data.Length());
+ if(echoDataBuf)
+ {
+ const TDes8& bufc = echoDataBuf->Des();
+ TDes8& echoData = const_cast<TDes8&>(bufc);
+ echoData.SetMax();
+ data.CopyOut(echoData);
+ }
+ data.Free();
+ }
+
+ iMuxer->EchoResponseReceived(echoDataBuf, *request->EchoResponseHandler());
+ }
+ // Delete the request.
+ delete requestCommand;
+ }
+ // If the response does not have an outstanding request drop
+ // the command silently. Always return true, this command
+ // can only be for the link signal handler.
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleEchoRequest(HEchoRequest* aEchoRequest) //Incoming
+ {
+ LOG_FUNC
+ //1. Create a Echo Response Command
+ HL2CapCommand* command = HEchoResponse::New(aEchoRequest->ID());
+
+ //2. Add to the list of outgoing commands
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+ return ETrue;
+ }
+
+TInt CL2CapLinkSignalHandler::ConstructInformationRequest(TInfoType aInfoType)
+ {
+ LOG_FUNC
+ TInt rerr = KErrNone;
+
+ //1. Create a ConnectionRequest Command
+ HL2CapCommand* command = HInformationRequest::New(aInfoType, CurrentRTXTimerDuration(HL2CapCommand::KDefaultRTXTimerDuration));
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+ else
+ {
+ rerr = KErrNoMemory;
+ }
+ return rerr;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleInformationRequest(HInformationRequest* aInformationRequest)
+ {
+ LOG_FUNC
+ // The peer is requesting the L2CAP entities capabilities.
+ switch(aInformationRequest->InfoType())
+ {
+ case EExtendedFeaturesSupported:
+ {
+ TUint32 extendedFeatures = KL2CAPExtendedFeaturesSupported;
+
+ HL2CapCommand* command = HInformationResponse::New(EExtendedFeaturesSupported, ESuccess, aInformationRequest->ID(), extendedFeatures);
+ if(command)
+ {
+ // Add to the list of outgoing commands
+ AddToOutgoingQueue(command);
+ }
+ // If the command could not be created the connection will fail in the
+ // signalling state machine.
+ break;
+ }
+
+ // If the info requested is Connectionless MTU or a info type that
+ // is not recognised, return a response with result code 'not supported'.
+ case EConnectionlessMTU:
+ default:
+ {
+ //Return InfoType and Not supported
+ HL2CapCommand* command = HInformationResponse::New(aInformationRequest->InfoType(),
+ ENotsupported,
+ aInformationRequest->ID());
+ if(command)
+ {
+ // Add to the list of outgoing commands
+ AddToOutgoingQueue(command);
+ }
+ // If the command could not be created the connection will fail in the
+ // signalling state machine.
+ break;
+ }
+ };
+
+ //This should not occur as it should be handled by derived classes.
+ return(ETrue);
+ }
+
+TBool CL2CapLinkSignalHandler::HandleInformationResponse(HInformationResponse* aInformationResponse)
+ {
+ LOG_FUNC
+ // Check that the Information Response has been requested.
+ HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EInformationRequest, aInformationResponse->ID());
+ if(requestCommand)
+ {
+ HInformationRequest* req = static_cast<HInformationRequest*>(requestCommand);
+ // The Info Type in the response should match that in the
+ // request.
+ if(req->InfoType() == aInformationResponse->InfoType())
+ {
+ switch(aInformationResponse->InfoType())
+ {
+ case EExtendedFeaturesSupported:
+ if(aInformationResponse->Result() == ESuccess)
+ {
+ iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(aInformationResponse->RemoteExtendedFeatureMask());
+ }
+ else
+ {
+ // The result was a failure. Set the supported
+ // features to the default of not supported.
+ iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
+ }
+ iMuxer->L2CapEntityConfigUpdated();
+ break;
+
+ default:
+ break;
+ };
+ }
+ else
+ {
+ // The request and response info types don't match. If the request
+ // was for extended features, [for the sake of interop] assume that
+ // no extended features are supported by the peer device.
+ if(req->InfoType() == EExtendedFeaturesSupported)
+ {
+ iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
+ iMuxer->L2CapEntityConfigUpdated();
+ }
+ }
+
+ // Delete the request.
+ delete requestCommand;
+ }
+ // If the response does not have an outstanding request drop
+ // the command silently. Always return true, this command
+ // can only be for the link signal handler.
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleCommandReject(HCommandReject* aCommandReject)
+ {
+ LOG_FUNC
+ // Process the incoming command reject data
+ TL2CAPCommandRejectData rejectData;
+
+ if (aCommandReject->RejectData(rejectData) != KErrNone)
+ {
+ LOG(_L("CL2CapLinkSignalHandler::HandleCommandReject - reject data could not be parsed"));
+ // Couldn't parse the reject data, but we've got no-one to
+ // pass handling this on to, so we have to say we've processed
+ // it.
+ return ETrue;
+ }
+
+ LOG1(_L("CL2CapLinkSignalHandler::HandleCommandReject - reject data: reason %d"), rejectData.iReason);
+
+ switch(rejectData.iReason)
+ {
+ case ECommandNotUnderstood:
+ {
+ // The peer does not recognise a command we have sent.
+ // Check if the outstanding request is causing the issue.
+ HL2CapCommand* requestCommand = FindMatchingOutstandingRequest(EMatchAnyL2CAPRequest, aCommandReject->ID());
+ if(requestCommand)
+ {
+ // This is a work around to allow the new stack to interop with
+ // stacks that send Command Reject in response to Information Request.
+ if(requestCommand->Code() == EInformationRequest)
+ {
+ // Set the supported features to the default of not supported.
+ iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
+ iMuxer->L2CapEntityConfigUpdated();
+ }
+ delete requestCommand;
+ }
+ }
+ break;
+
+ case EMTUExceeded:
+ iSigMTU = Max(rejectData.iMTUExceeded, KL2MinMTU);
+ break;
+
+ case EInvalidCID:
+ // This handles a corner case where a Disconnect Request command
+ // retransmission crosses over with the Response for the initial
+ // Disconnect Request. The peer will correctly send a Command Reject
+ // for the second Disconnect Request. This should be ignored.
+ break;
+
+ default:
+ break;
+ };
+
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleInvalidCommand(HInvalidCommand* aInvalidCommand)
+ {
+ LOG_FUNC
+ TL2CAPCommandRejectData reason;
+ reason.iReason = ECommandNotUnderstood;
+ // Other reject data fields are not used for Command Not Understood
+ reason.iMTUExceeded = 0;
+ reason.iLocalEndpoint = 0;
+ reason.iRemoteEndpoint = 0;
+
+ HL2CapCommand* command = HCommandReject::New(reason, aInvalidCommand->ID());
+ if(command)
+ {
+ AddToOutgoingQueue(command);
+ }
+
+ // The link signal handler always services invalid commands.
+ return ETrue;
+ }
+
+
+TBool CL2CapLinkSignalHandler::HandleConnectionResponse(HConnectionResponse* /*aConnectionResponse*/)
+ {
+ LOG_FUNC
+ // This command has not been handled by any of the SAP
+ // signal handlers. It's a response so just drop it.
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleConfigureRequest(HConfigureRequest* aConfigRequest)
+ {
+ LOG_FUNC
+ // This command has not been handled by any of the SAP
+ // signal handlers. Send a Command Reject.
+ SendInvalidCIDCommandReject(aConfigRequest->ID(),
+ 0,
+ aConfigRequest->DestinationCID());
+
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleConfigureResponse(HConfigureResponse* /*aConfigResponse*/)
+ {
+ LOG_FUNC
+ // This command has not been handled by any of the SAP
+ // signal handlers. It's a response so just drop it.
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleDisconnectRequest(HDisconnectRequest* aDisconnectRequest)
+ {
+ LOG_FUNC
+ // This command has not been handled by any of the SAP
+ // signal handlers. Send a Command Reject.
+ SendInvalidCIDCommandReject(aDisconnectRequest->ID(),
+ aDisconnectRequest->SourceCID(),
+ aDisconnectRequest->DestinationCID());
+
+ return ETrue;
+ }
+
+TBool CL2CapLinkSignalHandler::HandleDisconnectResponse(HDisconnectResponse* /*aDisconnectResponse*/)
+ {
+ LOG_FUNC
+ // This command has not been handled by any of the SAP
+ // signal handlers. It's a response so just drop it.
+ return ETrue;
+ }
+
+void CL2CapLinkSignalHandler::PendingCommandsDrained()
+ {
+ LOG_FUNC
+ // No action is required here.
+ }
+
+// HIncomingSAPSigPDUHandler Interface Definition.
+void CL2CapLinkSignalHandler::LinkUp()
+ {
+ LOG_FUNC
+ // No action required from the LinkSignalHandler when the link is established.
+ }
+
+void CL2CapLinkSignalHandler::Error(TInt /*aErrorCode*/, MSocketNotify::TOperationBitmasks /*aErrorAction*/)
+ {
+ LOG_FUNC
+ HandleLinkError();
+ }
+
+void CL2CapLinkSignalHandler::CommandResponseFailure(HL2CapCommand* aCommand)
+ {
+ LOG_FUNC
+ switch(aCommand->Code())
+ {
+ case EInformationRequest:
+ //For IOP We set extended feature to basic if there is no reply for info request.
+ iPeerL2CapEntityConfig.UpdatePeerL2CapSupportedFeatures(TL2CapEntityInfo());
+ iMuxer->L2CapEntityConfigUpdated();
+ break;
+
+ default:
+ iMuxer->ErrorAllSignalHandlers(KErrL2CAPRequestTimeout);
+ break;
+ }
+
+ delete aCommand;
+ }
+
+void CL2CapSignalHandler::PendingCommandsDrained()
+ {
+ LOG_FUNC
+ // Currently no action is required by the link signal handler.
+ }
+
+
+
+