bluetooth/btstack/linkmgr/VendorSAP.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/VendorSAP.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,382 @@
+// Copyright (c) 2005-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 "VendorSAP.h"
+#include "vendorspecific.h"
+#include "linkmgr.h"
+#include "hcifacade.h"
+#include "BTSec.h"
+
+
+//Diagnostic string for security check failures, in builds without platsec
+//diagnostics this will be NULL.
+const char* const KVENDOR_SAP_NAME_DIAG = __PLATSEC_DIAGNOSTIC_STRING("Vendor SAP");
+
+// only does IOCTLs
+
+CVendorSAP* CVendorSAP::NewL(CLinkMgrProtocol& aProtocol)
+	{
+	return new(ELeave) CVendorSAP(aProtocol);
+	}
+
+CVendorSAP::CVendorSAP(CLinkMgrProtocol& aProtocol)
+: iDebugEventQueue(_FOFF(TVendorDebugEvent, iEventLink)),
+  iProtocol(aProtocol)
+	{
+	iProtocol.iVendorSpecificSAP = this;
+	}
+
+CVendorSAP::~CVendorSAP()
+	{
+	iProtocol.iVendorSpecificSAP = NULL;
+	
+	//need to empty the queue.
+	while (!(iDebugEventQueue.IsEmpty()))
+		{
+		TVendorDebugEvent* theEvent = iDebugEventQueue.First();
+		theEvent->iEventLink.Deque();
+		delete theEvent;
+		}
+	}
+
+void CVendorSAP::Ioctl(TUint aLevel,TUint aName,TDes8* aOption)
+/**
+**/
+	{
+	__ASSERT_DEBUG(iIoctlLevel == 0, Panic(EVendorTwoIoctls));
+	__ASSERT_DEBUG(iIoctlName == 0, Panic(EVendorTwoIoctls));
+	
+	iIoctlLevel = aLevel;
+	iIoctlName = aName;
+	
+	//Do security check on following Ioctls
+	TInt rerr = KErrNone;
+	switch(aName)
+		{
+		case KHCIWaitForVendorSpecificDebugEventIoctl:
+		case KHCIWriteVendorSpecificFrameIoctl:
+		case KHCIWriteVendorSpecificFrameNoEventExpectedIoctl:
+			{
+			//The above Ioctl require additional security checking, NetworkControl
+			//in addition to the LocalServices that was required to create the SAP
+			__ASSERT_DEBUG(iSecurityChecker, User::Panic(KSECURITY_PANIC, EBTPanicNullSecurityChecker));
+			rerr = iSecurityChecker->CheckPolicy(KNETWORK_CONTROL, KVENDOR_SAP_NAME_DIAG);
+			if (rerr != KErrNone)
+				{
+				NotifyIoctlComplete(rerr,
+									KSolBtHCI,
+									aName,
+									NULL);
+				}								
+			break;
+			}
+		default:
+		//	Other Ioctls require just LocalServices - effectively policed when BT socket is created/transferred
+		break;	
+		}
+	if (rerr != KErrNone)
+		{
+		return;				
+		}
+	
+	// have passed security check so continue to handle ioctl		
+	switch(aName)
+		{
+		case KHCIWaitForVendorSpecificDebugEventIoctl:
+			{
+
+			/*
+			If VendorSpecificWaitForDebugEvent ioctl 
+			See if we can complete it synchronously
+			*/
+			TryToCompleteVendorDebugEventIoctl();	
+			break;
+			}
+		case KHCIWriteVendorSpecificFrameIoctl:
+			{
+			if(aOption->Length() != sizeof(THCIWriteVendorSpecificFrameIoctl))
+				{
+				NotifyIoctlComplete(KErrBadDescriptor,
+						KSolBtHCI,
+						KHCIWriteVendorSpecificFrameIoctl,
+						NULL);
+				return;
+				}
+			const THCIWriteVendorSpecificFrameIoctl* ioctl =
+				reinterpret_cast<const THCIWriteVendorSpecificFrameIoctl*>(aOption->Ptr());
+			
+			TRAPD(err,iProtocol.HCIFacade().VendorSpecificCommandL(ioctl->iOpcode, ioctl->iParams));
+			if (err)
+				{
+				NotifyIoctlComplete(err,
+									KSolBtHCI,
+									KHCIWriteVendorSpecificFrameIoctl,
+									NULL);
+				}
+			// if no error wait for event before completing
+
+			break;
+			}
+		case KHCIWriteVendorSpecificFrameNoEventExpectedIoctl:
+			{
+			if(aOption->Length() != sizeof(THCIWriteVendorSpecificFrameIoctl))
+				{
+				NotifyIoctlComplete(KErrBadDescriptor,
+						KSolBtHCI,
+						KHCIWriteVendorSpecificFrameNoEventExpectedIoctl,
+						NULL);
+				return;
+				}
+			const THCIWriteVendorSpecificFrameIoctl* ioctl =
+				reinterpret_cast<const THCIWriteVendorSpecificFrameIoctl*>(aOption->Ptr());
+			
+			TRAPD(err,iProtocol.HCIFacade().VendorSpecificCommandL(ioctl->iOpcode, ioctl->iParams));
+			// notify completion now though really could wait until delivered from q
+			NotifyIoctlComplete(err,
+								KSolBtHCI,
+								KHCIWriteVendorSpecificFrameNoEventExpectedIoctl,
+								NULL);
+			break;
+			}
+		default:
+			NotifyIoctlComplete(
+				KErrNotSupported,
+				iIoctlLevel,
+				iIoctlName,
+				NULL
+			);
+			break;
+		} // END Switch
+	}
+
+
+void CVendorSAP::VendorCommandCompleteEvent(TInt aErr, const TDesC8* aEvent)
+	{
+	if(iIoctlName == KHCIWriteVendorSpecificFrameIoctl)
+		{
+		/*
+		A client is waiting for this.
+		*/
+		NotifyIoctlComplete(aErr, iIoctlLevel, KHCIWriteVendorSpecificFrameIoctl, aEvent);
+		}
+	}
+
+void CVendorSAP::VendorDebugEvent(TInt aErr, const TDesC8* aEvent)
+	{
+	// Some events will not contain an event descriptor.
+	TPtrC8 eventDesc = aEvent?*aEvent:KNullDesC8; 
+	
+	// Holds the data from an *expected* event (expected as in conduit said so!).
+	TVendorDebugEvent* newEvent = NewDebugEventData(eventDesc, aErr);	
+	
+	if(newEvent)
+		{
+		iDebugEventQueue.AddLast(*newEvent); // add this event to the end of the list of events already queued
+		}
+	else
+		{
+		NotifyIoctlComplete(KErrNoMemory,
+							iIoctlLevel,
+							iIoctlName,
+							NULL);
+		return;
+		}
+	TryToCompleteVendorDebugEventIoctl();
+	}
+
+
+TInt CVendorSAP::SecurityCheck(MProvdSecurityChecker *aSecurityChecker)
+	{
+	__ASSERT_ALWAYS(aSecurityChecker, User::Panic(KSECURITY_PANIC, EBTPanicNullSecurityChecker));
+		
+	iSecurityChecker = aSecurityChecker;
+	return iSecurityChecker->CheckPolicy(KLOCAL_SERVICES, KVENDOR_SAP_NAME_DIAG);				
+	}
+
+void CVendorSAP::NotifyIoctlComplete(TInt aErr, TUint aLevel, TUint aName, const TDesC8* aBuffer)
+	{
+	if (iIoctlLevel == aLevel && iIoctlName == aName)
+		{
+		if (aErr == KErrNone)
+			{
+			if(iSocket)
+				iSocket->IoctlComplete(const_cast<TDesC8*>(aBuffer));
+			}
+		else
+			{
+			if(iSocket)
+				iSocket->Error(aErr, MSocketNotify::EErrorIoctl);
+			}
+		}
+	
+	iIoctlLevel=0;
+	iIoctlName=0;
+	}
+	
+
+CVendorSAP::TVendorDebugEvent* CVendorSAP::NewDebugEventData(const TDesC8& aBuf, TInt aError)
+/**
+@param aBuf The Vendor event buffer. Must not be NULL
+**/
+	{
+	TVendorDebugEvent* event = new TVendorDebugEvent;
+	if(!event)
+		{
+		return 0;
+		}
+	event->iEventBuf.Copy(aBuf.Left(Min(CHctlCommandFrame::KHCIMaxCommandLength, aBuf.Length())));
+	event->iEventError = aError;
+	return event;
+	}
+
+void CVendorSAP::TryToCompleteVendorDebugEventIoctl()
+	{
+	// check to see if anyone expecting a debug event completion
+	if (iIoctlName != KHCIWaitForVendorSpecificDebugEventIoctl)
+		{
+		return;
+		}
+
+	// nothing to do
+	if(iDebugEventQueue.IsEmpty())
+		{
+		return;
+		}
+
+	TVendorDebugEvent* theEvent = iDebugEventQueue.First();
+
+	// belt and braces!
+	if(theEvent == NULL)
+		{
+		return;
+		}
+	
+	// De-queue the event, as it is being consumed
+	theEvent->iEventLink.Deque();
+
+	// Complete the waiting ioctl, passing the the first appropriate
+	// event in the queue back up.
+	NotifyIoctlComplete(
+		theEvent->iEventError,
+		KSolBtHCI,
+		KHCIWaitForVendorSpecificDebugEventIoctl,
+		&(theEvent->iEventBuf)
+		);
+
+	// Event has been consumed, may now be deleted
+	delete theEvent;
+		
+	}
+
+
+void CVendorSAP::Start()
+	{
+	// do nothing
+	}
+
+void CVendorSAP::LocalName(TSockAddr& /*aAddr*/) const
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+TInt CVendorSAP::SetLocalName(TSockAddr& /*aAddr*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+void CVendorSAP::RemName(TSockAddr& /*aAddr*/) const
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+TInt CVendorSAP::SetRemName(TSockAddr& /*aAddr*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+TInt CVendorSAP::GetOption(TUint /*aLevel*/,TUint /*aName*/,TDes8& /*aOption*/) const
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+void CVendorSAP::CancelIoctl(TUint __DEBUG_ONLY(aLevel),TUint __DEBUG_ONLY(aName))
+	{
+	__ASSERT_DEBUG(iIoctlLevel == aLevel, Panic(EVendorSAPBadIoctlCancel));
+	__ASSERT_DEBUG(iIoctlName == aName, Panic(EVendorSAPBadIoctlCancel));
+	
+	iIoctlName = 0;
+	iIoctlLevel = 0;
+	}
+
+TInt CVendorSAP::SetOption(TUint /*aLevel*/,TUint /*aName*/,const TDesC8& /*aOption*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+void CVendorSAP::ActiveOpen()
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+void CVendorSAP::ActiveOpen(const TDesC8& /*aConnectionData*/)
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+TInt CVendorSAP::PassiveOpen(TUint /*aQueSize*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+TInt CVendorSAP::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return KErrNotSupported;
+	}
+
+void CVendorSAP::AutoBind()
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+TUint CVendorSAP::Write(const TDesC8& /*aDesc*/, TUint /*aOptions*/, TSockAddr* /*aAddr*/)
+	{
+	Panic(EVendorSAPBadCall);
+	return 0;
+	}
+
+void CVendorSAP::GetData(TDes8& /*aDesc*/,TUint /*aOptions*/,TSockAddr* /*aAddr*/)
+	{
+	Panic(EVendorSAPBadCall);
+	}
+
+void CVendorSAP::Shutdown(TCloseType aCloseType)
+	{
+	if (aCloseType == ENormal)
+		{
+		iSocket->CanClose();
+		}
+	}
+
+void CVendorSAP::Shutdown(TCloseType /*aOption*/,const TDesC8& /*aDisconnectionData*/)
+	{
+	Panic(EVendorSAPBadCall);
+	}
+