bluetooth/btstack/linkmgr/ProxySAP.cpp
changeset 0 29b1cd4cb562
child 14 f8503e232b0c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/ProxySAP.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1214 @@
+// Copyright (c) 2003-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:
+// Implementation of proxy SAP.
+// 
+//
+
+#include <bluetooth/logger.h>
+#include "ProxySAP.h"
+#include "linkutil.h"
+#include "linkconsts.h"
+#include "RawConduit.h"
+#include "physicallinksmanager.h"
+#include "Basebandmodel.h"
+#include "BTSec.h"
+#include "linkmgr.h"
+
+#include <bluetooth/hci/aclpacketconsts.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_LINKMGR);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("proxysap");
+#endif
+
+//Diagnostic string for security check failures, in builds without platsec
+//diagnostics this will be NULL.
+const char* const KBT_PROXYSAP_NAME_DIAG = __PLATSEC_DIAGNOSTIC_STRING("Bluetooth Proxy SAP");
+
+CBTProxySAP::CBTProxySAP(CPhysicalLinksManager& aLinksMan, CPhysicalLink* aPhysicalLink)
+: CBTBasebandSAP(aLinksMan, aPhysicalLink),
+  iRequestedLinkPolicy(EHoldMode | ESniffMode | EParkMode, ETrue),
+  iNotifiedUp(EFalse), iTerminating(ENone), iBasebandNotifyOptions(0),
+  iEventNotificationQueue(_FOFF(TBTQueuedBasebandEventNotification, iLink)),
+  iEventNotificationStatus(EDisabled)
+	{
+	LOG1(_L("Creating proxy SAP 0x%08x"), this);
+#ifdef PROXY_COMMUNICATES
+	iHandle = KHCIBroadcastHandle;
+#endif
+	}
+
+CBTProxySAP* CBTProxySAP::NewLC(CPhysicalLinksManager& aConnectionMan, CPhysicalLink* aPhysicalSAP)
+	{
+	CBTProxySAP* s = new(ELeave) CBTProxySAP(aConnectionMan, aPhysicalSAP);
+	CleanupStack::PushL(s);
+	s->ConstructL();
+	return s;
+	}
+
+CBTProxySAP* CBTProxySAP::NewL(CPhysicalLinksManager& aConnectionMan, CPhysicalLink* aPhysicalSAP)
+	{
+	CBTProxySAP* s = CBTProxySAP::NewLC(aConnectionMan, aPhysicalSAP);
+	CleanupStack::Pop(s);
+	return s;
+	}
+
+void CBTProxySAP::ConstructL()
+	{
+	CBTBasebandSAP::ConstructL();
+	iAsyncCallback = new(ELeave) CAsyncCallBack(CActive::EPriorityStandard);
+
+	if(iPhysicalLink)
+		{
+		User::LeaveIfError(iPhysicalLink->SubscribeProxySAP(*this));
+		}
+	// now we need to go async and check whether the physical link is up
+	// has to be async because we don't have a socket at the moment
+	AsyncCheckLinkUp();
+	}
+
+void CBTProxySAP::ClearPhysicalLink()
+	{
+	if (iPhysicalLink)
+		{
+		iPhysicalLink->UnsubscribeProxySAP(*this);
+		iPhysicalLink = NULL;
+		}
+	}
+
+CBTProxySAP::~CBTProxySAP()
+	{
+	LOG1(_L("Deleting proxy SAP 0x%08x"), this);
+	
+	// If iTerminating is set we are waiting for iLinksMan to call us back 
+	// which means that it holds a pointer to this ProxySAP
+	if (iTerminating!=ENone)
+		{
+		__ASSERT_DEBUG(EFalse, Panic(EBTProxySAPBadCanClose));
+		iLinksMan.ClearTerminatingProxy(this);
+		}
+	
+	ClearPhysicalLink();
+	/*Remove this proxy SAP from the PLM queue*/
+	iPLMLink.Deque();
+	delete iAsyncCallback;
+ 	delete iRawConduit;
+	}
+
+// from SAP - the proxy will not do all of these
+void CBTProxySAP::Start()
+	{
+	// do nothing
+	}
+
+void CBTProxySAP::RemName(TSockAddr& aAddr) const
+	{
+	// our name is the same is that of the PHY, assuming it is connected
+	// note esock doesn't allow a great deal of maneouvour on errors here!
+	if(iPhysicalLink && iPhysicalLink->IsConnected())
+		{
+		TBTSockAddr bbAddr(aAddr);
+		bbAddr.SetBTAddr(iPhysicalLink->BDAddr());
+		aAddr=bbAddr;   // Convert back
+		}
+	}
+
+TInt CBTProxySAP::SetRemName(TSockAddr& aAddr)
+	{
+	TBTSockAddr addr = TBTSockAddr::Cast(aAddr);
+	iRemoteDev = addr.BTAddr();
+
+	// we now know our remote address so should try to get a PHY if there
+	CPhysicalLink *link = iLinksMan.FindPhysicalLink(iRemoteDev);
+
+	// If we're (re-)using the same physical link, there's no
+	// reason to subscribe again
+	if (link != iPhysicalLink)
+		{
+		// Unsubscribe from old link
+		if (iPhysicalLink)
+			{
+			iPhysicalLink->UnsubscribeProxySAP(*this);
+			}
+
+		iPhysicalLink = link;
+
+		// Subscribe to new one
+		if (iPhysicalLink)
+			{
+			return iPhysicalLink->SubscribeProxySAP(*this);
+			}
+		}
+
+	// in any case return no error since the BAP may try to create PHY
+	return KErrNone;
+	}
+
+TInt CBTProxySAP::GetOption(TUint aLevel,TUint aName,TDes8& aOption) const
+	{
+	TInt rerr = KErrNone;
+
+	if(aLevel != KSolBtLMProxy)
+		{
+		rerr = KErrNotSupported;
+		}
+
+	switch (aName)
+		{
+		case EBBEnumeratePhysicalLinks:
+			iLinksMan.EnumeratePhysicalLinks(aOption);
+			break;
+		case EBBGetPhysicalLinkState:
+			{
+			if (aOption.Length() != sizeof(TBTBasebandEventNotification))
+				return KErrArgument;
+			
+			if (!iPhysicalLink)
+				{
+				LOG1(_L("GetOption called on non-existent Phy ....so return %d (KErrDisconnected)"), KErrDisconnected);
+				return KErrDisconnected;
+				}
+			TBTBasebandEventNotification basebandState;
+			iPhysicalLink->GetCurrentBasebandState(basebandState);
+			TBTBasebandEvent pkcgEvent(basebandState);
+			aOption = pkcgEvent;
+			}
+			break;
+		default:
+			rerr = KErrArgument;
+			break;
+		}
+	return rerr;
+	}
+
+void CBTProxySAP::Ioctl(TUint aLevel,TUint aName,TDes8* aOption)
+	{
+	if (aLevel == KSolBtLMProxy)
+		{
+		switch(aName)
+			{
+			case KLMReadRssiIoctl:
+			case KLMReadLinkQualityIoctl:
+			case KLMReadFailedContactCounterIoctl:
+			case KLMReadCurrentTransmitPowerLevelIoctl:
+				{
+				if (!aOption || aOption->Length() != sizeof(TInt))
+					{
+					IoctlComplete(KErrArgument, aLevel, aName);
+					break;
+					}
+				// Add the current request to a queue; pass this pointer to  call IoctlComplete()
+				// when result is available from the controller. Multiple SAPs can queue data on
+				// the same physical link.
+				TPckgBuf<TInt> currentValuePckg;
+				currentValuePckg.Copy(*aOption);
+				
+				if(iPhysicalLink)
+					{
+					iPhysicalLink->ReadNewPhysicalLinkMetricValue(aName, *this, currentValuePckg());
+					}
+				else
+					{
+					IoctlComplete(KErrDisconnected, KSolBtLMProxy, aName, NULL);
+					}
+				
+				break;
+				}
+			case KLMBasebandEventOneShotNotificationIoctl:
+				{
+				ASSERT_DEBUG(iEventNotificationStatus == EDisabled);
+				iEventNotificationStatus = EEnabledOneShot;
+				const TBTBasebandEventNotification* option = reinterpret_cast<const TBTBasebandEventNotification*>(aOption->Ptr());
+				__ASSERT_DEBUG(option->EventType(), Panic(EBTProxySAPInvalidEventMask));
+				SetBasebandNotificationOptions(option->EventType());
+				}
+				break;
+
+			case KLMBasebandEventNotificationIoctl:
+				{
+				ASSERT_DEBUG(iEventNotificationStatus != EEnabledOneShot);
+				const TBTBasebandEventNotification* option = reinterpret_cast<const TBTBasebandEventNotification*>(aOption->Ptr());
+				SetBasebandNotificationOptions(option->EventType());
+
+				if(iEventNotificationStatus == EDisabled)
+					{
+					// Send an initial event describing the current state of the
+					// baseband link.
+					TBTBasebandEventNotification basebandState;
+					
+					if (!iPhysicalLink)
+						{
+						LOG1(_L("Ioctl called on non-existent Phy ....so indicate %d (KErrDisconnected)"), KErrDisconnected);
+						SetNullBasebandState(basebandState);
+						TBTBasebandEvent pkcgEvent(basebandState);
+						IoctlComplete(KErrNone, KSolBtLMProxy, KLMBasebandEventNotificationIoctl, &pkcgEvent);
+						}
+					else
+						{
+						iPhysicalLink->GetCurrentBasebandState(basebandState);
+						TBTBasebandEvent pkcgEvent(basebandState);
+						IoctlComplete(KErrNone, KSolBtLMProxy, KLMBasebandEventNotificationIoctl, &pkcgEvent);
+						}
+					iEventNotificationStatus = EEnabledQueuing;
+					}
+				else
+					{
+					// Check if anything is currently in the queue.
+					iEventNotificationStatus = EEnabledCanSend;
+
+					if(!iEventNotificationQueue.IsEmpty())
+						{
+						TBTQueuedBasebandEventNotification* e = iEventNotificationQueue.First();
+						iEventNotificationQueue.Remove(*e);
+						TBTBasebandEventNotification event(e->EventType() & iBasebandNotifyOptions, e->ErrorCode());
+						delete e;
+
+						if(event.EventType())
+							{
+							TBTBasebandEvent pkcgEvent(event);
+							IoctlComplete(KErrNone, KSolBtLMProxy, KLMBasebandEventNotificationIoctl, &pkcgEvent);
+							iEventNotificationStatus = EEnabledQueuing;
+							}
+						}
+					}
+				}
+				break;
+
+			default:
+				{
+ 				IoctlComplete(KErrNotSupported, aLevel, aName);
+   				break;
+ 				}
+			};
+		}
+	else
+		{
+		IoctlComplete(KErrNotSupported, aLevel, aName);
+		}
+	}
+
+void CBTProxySAP::IoctlComplete(TInt aErr, TUint /*aLevel*/, TUint /*aName*/, TDesC8* aBuf)
+ 	{
+ 
+ 	if (iSocket)
+ 		{
+ 		if (aErr==KErrNone)
+ 			{
+ 			iSocket->IoctlComplete(aBuf);
+ 			}
+ 		else 
+ 			{	
+ 			iSocket->Error(aErr, MSocketNotify::EErrorIoctl);
+ 			}
+   		}
+   	}
+
+void CBTProxySAP::SetNullBasebandState(TBTBasebandEventNotification & aEvent)
+	{
+	// Populate the event with no physical link baseband state.
+	TUint32 events = 0;
+
+	events |= ENotifyPhysicalLinkDown;
+
+	aEvent.SetEventType(events);
+	aEvent.SetErrorCode(0);
+	}
+
+void CBTProxySAP::CancelIoctl(TUint aLevel,TUint aName)
+	{
+	 
+ 	__ASSERT_DEBUG((aLevel == KSolBtLMProxy), Panic(EBTProxySAPInvalidIoctl));
+ 	
+	if (aLevel == KSolBtLMProxy)
+		{
+		switch(aName)
+			{
+			case KLMBasebandEventNotificationIoctl:
+				SetBasebandNotificationOptions(0);	
+				iEventNotificationStatus = EDisabled;
+				ClearBasebandEventQueue();
+				break;
+
+			case KLMBasebandEventOneShotNotificationIoctl:
+				SetBasebandNotificationOptions(0);	
+				iEventNotificationStatus = EDisabled;
+				ClearBasebandEventQueue();
+				break;
+			case KLMReadRssiIoctl:
+			case KLMReadLinkQualityIoctl:
+			case KLMReadFailedContactCounterIoctl:
+			case KLMReadCurrentTransmitPowerLevelIoctl:
+				iPLMLink.Deque();
+				break;
+			default:
+				__ASSERT_DEBUG(EFalse, Panic(EBTProxySAPInvalidIoctl));
+				break;
+			};
+		}
+	}
+
+void CBTProxySAP::ClearBasebandEventQueue()
+	{
+	TSglQueIter<TBTQueuedBasebandEventNotification> iter(iEventNotificationQueue);
+	while (iter)
+		{
+		TBTQueuedBasebandEventNotification* e = iter++;
+		iEventNotificationQueue.Remove(*e);
+		delete e;
+		}
+	}
+
+void CBTProxySAP::SetBasebandNotificationOptions(TUint32 aOption) 
+	{
+	iBasebandNotifyOptions = aOption;
+	}
+
+
+TInt CBTProxySAP::SAPSetOption(TUint aLevel,TUint aName, const TDesC8 &aOption)
+	{
+	LOG3(_L("SetOpt %d, %d on proxy SAP 0x%08x"), aLevel, aName, this);
+	TInt rerr = KErrNone;
+
+	// Arbitration will be required after most operations.
+	TBool arbitrate = ETrue;
+	TBool immediateArbitration = EFalse;
+	TBool localPriority = EFalse;
+
+	if(aLevel != KSolBtLMProxy)
+		{
+		rerr = KErrNotSupported;
+		}
+
+	if(!iPhysicalLink && 
+		aName!=EBBSubscribePhysicalLink)
+		{
+		rerr = KErrDisconnected;
+		}
+
+	if(rerr == KErrNone)
+		{
+		switch (aName)
+			{
+			case EBBSubscribePhysicalLink:
+				{
+				// Make sure we're not already subscribed
+				if (iPhysicalLink)
+					{
+					__ASSERT_DEBUG(EFalse,Panic(EBTProxySAPAlreadySubscribed));
+					rerr = KErrArgument;
+					break;
+					}			
+				
+				TPckgBuf<TBTDevAddr> pckg;
+				pckg.Copy(aOption);
+				// try to find a PHY from addr, and if successful subscribe to it
+				iPhysicalLink = iLinksMan.FindPhysicalLink(pckg());
+				if (iPhysicalLink)
+					{
+					rerr = iPhysicalLink->SubscribeProxySAP(*this);
+					if(rerr == KErrNone)
+						{
+						iRemoteDev = pckg();
+						}
+					}
+				else
+					{
+					LOG1(_L("Proxy SAP 0x%08x -- couldn't find physical link"), this);
+					LOG(_L("Looking for addr: "));
+					LOGBTDEVADDR(pckg());
+					iLinksMan.DumpPhysicalLinks();
+					rerr = KErrDisconnected;
+					}
+
+				arbitrate = EFalse;
+				}
+				break;
+			case EBBBeginRaw:
+				//EBBBeginRaw requires 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, KBT_PROXYSAP_NAME_DIAG);
+				if (rerr != KErrNone)
+					{
+				    break;
+				    }											
+				if(!(iPhysicalLink && iPhysicalLink->Handle()!=KHCIBroadcastHandle))
+				//if no existing, connected PHY, try to find a random PHY which is
+					{
+					// We don't support this option if we're subscribed to the broadcast handle
+					if (iPhysicalLink)
+						{
+						__ASSERT_DEBUG(EFalse,Panic(EBTProxySAPSubscribedToBroadcastHandle));
+						rerr = KErrArgument;
+						break;
+						}
+					
+					iPhysicalLink = iLinksMan.FindPhysicalLink();
+					if (iPhysicalLink)
+						{
+						rerr = iPhysicalLink->SubscribeProxySAP(*this);
+						if(rerr == KErrNone)
+							{
+							iRemoteDev = iPhysicalLink->BDAddr();
+							}
+						}
+					else
+						{
+						rerr = KErrDisconnected;
+						}
+					}
+				if(rerr == KErrNone)
+					{
+					rerr = CreateRawConduit();
+					}
+				arbitrate = EFalse;
+				break;
+			case EBBCancelModeRequest:
+				rerr = SetModeRequested(EActiveMode);
+				break;
+			case EBBRequestSniff:
+				rerr = SetModeRequested(ESniffMode);
+				localPriority = ETrue;
+				break;
+			// clients cannot ask for Hold
+			case EBBRequestPark:
+				rerr = SetModeRequested(EParkMode);
+				localPriority = ETrue;
+				break;
+			case EBBRequestRoleMaster:
+				if(iRequestedLinkPolicy.IsSwitchAllowed() && iPhysicalLink->IsRoleSwitchSupported())
+					{
+					rerr = iPhysicalLink->RequestChangeRole(EMaster);
+					arbitrate = EFalse;
+					}
+				else
+					{
+					rerr = KErrNotSupported;
+					}
+				break;
+
+			case EBBRequestRoleSlave:
+				if(iLinksMan.LinkManagerProtocol().IsRoleSwitchSupportedLocally() && 
+					iRequestedLinkPolicy.IsSwitchAllowed() && iPhysicalLink->IsRoleSwitchSupported())
+					{
+					rerr = iPhysicalLink->RequestChangeRole(ESlave);
+					arbitrate = EFalse;
+					}
+				else
+					{
+					rerr = KErrNotSupported;
+					}
+				break;
+
+			case EBBRequestPreventRoleChange:
+				iRequestedLinkPolicy.SetSwitchAllowed(EFalse);
+				break;
+
+			case EBBRequestAllowRoleChange:
+				iRequestedLinkPolicy.SetSwitchAllowed(ETrue);
+				break;
+				
+			case EBBRequestChangeSupportedPacketTypes:
+				{
+				TUint16 options = *reinterpret_cast<const TUint16*>(aOption.Ptr());
+				if(aOption.Length() != sizeof(TUint16))
+					{
+					rerr = KErrArgument;
+					}
+				else
+					{
+					iPhysicalLink->ChangeConnectionPacketType(options);
+					arbitrate = EFalse;
+					}
+				}
+				break;
+			
+			case EBBRequestLinkAuthentication:
+				rerr = iPhysicalLink->Authenticate(EFalse);
+				break;
+				
+			case EBBRequestExplicitActiveMode:
+				{
+				TBool option = *reinterpret_cast<const TBool*>(aOption.Ptr());
+				if(aOption.Length() != sizeof(TBool))
+					{
+					rerr = KErrArgument;
+					}
+				else
+					{
+					iRequestedActiveMode = option ? ETrue : EFalse;
+					if(iRequestedActiveMode)
+						{
+						localPriority = ETrue;
+						}
+					}
+				}
+				break;
+
+			default:
+				{
+				arbitrate = EFalse;
+				if(aName & EBBRequestPreventAllLowPowerModes)
+					{
+					if (aName & EBBRequestPreventSniff)
+						{
+						if(iRequestedLinkPolicy.IsModeAllowed(ESniffMode))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(ESniffMode, EFalse);
+							arbitrate = ETrue;
+							}
+						}
+					if (aName & EBBRequestPreventHold)
+						{
+						if(iRequestedLinkPolicy.IsModeAllowed(EHoldMode))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(EHoldMode, EFalse);
+							arbitrate = ETrue;
+							}
+						}
+					if (aName & EBBRequestPreventPark)
+						{
+						if(iRequestedLinkPolicy.IsModeAllowed(EParkMode))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(EParkMode, EFalse);
+							arbitrate = ETrue;
+							}
+						}
+					
+					immediateArbitration = ETrue;
+					}
+				else if (aName & EBBRequestAllowAllLowPowerModes)
+					{
+					if (aName & EBBRequestAllowSniff)
+						{
+						if(!(iRequestedLinkPolicy.IsModeAllowed(ESniffMode)))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(ESniffMode, ETrue);
+							arbitrate = ETrue;
+							}
+						}
+					if (aName & EBBRequestAllowHold)
+						{
+						if(!(iRequestedLinkPolicy.IsModeAllowed(EHoldMode)))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(EHoldMode, ETrue);
+							arbitrate = ETrue;
+							}
+						}
+					if (aName & EBBRequestAllowPark)
+						{
+						if(!(iRequestedLinkPolicy.IsModeAllowed(EParkMode)))
+							{
+							iRequestedLinkPolicy.SetModeAllowed(EParkMode, ETrue);
+							arbitrate = ETrue;
+							}
+						}
+					
+					immediateArbitration = ETrue;
+					}
+				else
+					{
+					rerr = KErrUnknown;
+					}
+				}
+			};
+		}	
+
+	// Check if arbitration is required.
+	if(arbitrate && rerr == KErrNone)
+		{
+		rerr = iPhysicalLink->Arbitrate(immediateArbitration, localPriority);
+		}
+
+	return rerr;
+	}
+
+TInt CBTProxySAP::SetModeRequested(TBTLinkMode aMode)
+	{
+	TInt retVal = KErrNotSupported;
+
+	if(aMode == EActiveMode)
+		{
+		retVal = iRequestedLinkPolicy.SetModeRequested(aMode);
+		}
+	else
+		{
+		if(iLinksMan.LinkManagerProtocol().IsModeSupportedLocally(aMode) && 
+		   iPhysicalLink->IsModeSupportedRemotely(aMode))
+			{
+			retVal = iRequestedLinkPolicy.SetModeRequested(aMode);
+			}
+		}
+	return retVal;
+	}
+
+TBool CBTProxySAP::CanCreatePhysicalLink()
+	{
+	TBool ret = EFalse;
+	// return ETrue if allowed to create phy
+	if (iPhysicalLink)
+		{
+		// already there!
+		iSocket->ConnectComplete();
+		}
+	else if(!(Baseband().IsACLPossible()))
+		{
+		iSocket->Error(KErrInsufficientBasebandResources, MSocketNotify::EErrorConnect);
+		}
+	else
+		{
+		ret = ETrue;
+		}
+	return ret;
+	}
+
+
+void CBTProxySAP::ActiveOpen()
+	{
+	// create physical link for bonding
+	TBool proceed = CanCreatePhysicalLink();
+	if (proceed)
+		{
+		// right, go and connect - no juice on this overload
+		TRAPD(err, iPhysicalLink = &iLinksMan.NewPhysicalLinkL(iRemoteDev));
+		if(err == KErrNone)
+			{
+			iPhysicalLink->SubscribeProxySAP(*this);
+			iPhysicalLink->Connect(EPagingNormal);
+			}
+		else
+			{
+			iSocket->Error(KErrNoMemory, MSocketNotify::EErrorConnect);
+			}
+		}
+	}
+
+void CBTProxySAP::ActiveOpen(const TDesC8& aConnectionToken)
+	{
+	// create physical link for faster connection
+	TBool proceed = CanCreatePhysicalLink();
+	if (proceed)
+		{
+		// set the cookie
+		TPhysicalLinkQuickConnectionTokenBuf tokenBuf;
+		tokenBuf.Copy(aConnectionToken);
+
+		TRAPD(err, iPhysicalLink = &iLinksMan.NewPhysicalLinkL(tokenBuf().iDevice));
+		if(err == KErrNone)
+			{
+			iPhysicalLink->SubscribeProxySAP(*this);
+			iPhysicalLink->Connect(tokenBuf().iPolicy.iPageTimePolicy); // user determines paging policy with their "cookie"
+			}
+		else
+			{
+			iSocket->Error(KErrNoMemory, MSocketNotify::EErrorConnect);
+			}
+		}
+	}
+
+TInt CBTProxySAP::PassiveOpen(TUint /*aQueSize*/)
+	{
+	return KErrNotSupported;
+	}
+
+TInt CBTProxySAP::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/)
+	{
+	return KErrNotSupported;
+	}
+
+void CBTProxySAP::Shutdown(TCloseType aCloseType)
+	{
+	// just our phy to shutdown
+	Shutdown(aCloseType, KDisconnectOnePhysicalLink);
+	}
+
+void CBTProxySAP::Shutdown(TCloseType aCloseType,const TDesC8& aDisconnectOption)
+	{
+	
+	//Only ENormal and EImmediate may be used for BaseBand connections
+	__ASSERT_DEBUG((aCloseType == CServProviderBase::ENormal||aCloseType == CServProviderBase::EImmediate),Panic(EBTProxySAPInvalidTerminate));
+	
+	
+	if (aDisconnectOption == KDisconnectOnePhysicalLink && aCloseType== CServProviderBase::ENormal)
+		{
+		// Unbinding Socket, no additional Caps required
+		// Remove ourselves from the physical SAP - doesnt detach the PHY itself
+		ClearPhysicalLink();
+		}
+	else
+		{		
+		//Atleast one Physical link is to be terminated,  any 'Shutdown' on physical 
+		//links requires an additional security check for the NetworkControl Cap.
+		//This is required in addition to the LocalServices that was required to create the SAP
+		__ASSERT_DEBUG(iSecurityChecker, User::Panic(KSECURITY_PANIC, EBTPanicNullSecurityChecker));
+			
+		TInt rerr = iSecurityChecker->CheckPolicy(KNETWORK_CONTROL, KBT_PROXYSAP_NAME_DIAG);
+		if (rerr != KErrNone)
+			{
+			if(iSocket)
+				iSocket->Error(rerr, MSocketNotify::EErrorClose);
+			return;
+			}										
+
+		if (aDisconnectOption == KDisconnectAllPhysicalLinks)
+			{
+			// Disconnecting All BT Physical Links
+			// Only support link *termination*, this is done as normal cos esock weirdness
+			__ASSERT_ALWAYS(aCloseType == CServProviderBase::ENormal, Panic(EBTProxySAPInvalidTerminate));
+			rerr = iLinksMan.TerminateAllPhysicalLinks(this);
+			LOG2(_L("Proxy SAP 0x%08x -- Terminating all PHY Links, error: %d"), this, rerr);
+			
+			// If there was an error terminating any of the physical links then we can 
+			// call CanClose straight away, otherwise this is done when iLinksMan calls
+			// TerminatePhysicalLinksComplete()
+			if (rerr == KErrNone)
+				{
+				iTerminating=ETerminatingAllLinks;
+				return;
+				}
+			}
+		else
+			{
+			//Disconnecting only One Physical Link
+			CPhysicalLink* phy2Term = NULL;
+			
+			if (aDisconnectOption == KDisconnectOnePhysicalLink)
+				{
+				// EImmediate Shutdown - Terminate the Physical link
+				phy2Term = iPhysicalLink;
+				}
+			else
+				{
+				// Shutdown on a specific address (a PHY we arent attached to)
+				// again done as normal since esock is weird
+				TBTDevAddr addr(aDisconnectOption);
+				phy2Term = iLinksMan.FindPhysicalLink(addr);		
+				}
+				
+			if(phy2Term)
+				{
+				LOG1(_L("Proxy SAP 0x%08x -- Immediate ShutDown, terminate PHY Link"), this);
+
+				// If EImmediate shutdown then esock doesn't expect us to call CanClose() so
+				// we don't want iLinksMan to let us know when the physical link has been terminated
+				if (aCloseType == CServProviderBase::EImmediate)
+					{
+					rerr = iLinksMan.TerminatePhysicalLink(phy2Term, NULL);
+					}
+				else
+					{
+					rerr = iLinksMan.TerminatePhysicalLink(phy2Term, this);
+				
+					// If there was an error terminating the physical link then we can 
+					// call CanClose straight away, otherwise this is done when iLinksMan calls
+					// TerminatePhysicalLinksComplete()
+					if (rerr == KErrNone)
+						{
+						iTerminating=ETerminatingSingleLink;
+						return;
+						}
+					}
+				}
+			else
+				{
+				// Possible race Condition - the phy may have gone anyway
+				LOG1(_L("Proxy SAP 0x%08x -- PHY Link already terminated by other process"), this);
+				}
+			}
+		}
+		
+	// this may change if esock is altered
+	if (aCloseType==CServProviderBase::ENormal)
+		{
+		// Signal that SAP can be deleted
+		iSocket->CanClose();
+		}
+	// CAREFUL - might be deleted at this point
+	}
+	
+
+void CBTProxySAP::AutoBind()
+	{
+#ifndef PROXY_COMMUNICATES
+	Panic(EBTProxySAPUnexpectedEvent);
+#endif
+	}
+
+#ifdef PROXY_COMMUNICATES
+TUint CBTProxySAP::Write(const TDesC8& aData,TUint aOptions, TSockAddr* /*aAddr*/)
+	{
+	// we can throw away some of the options - we only allow them to be 8bit
+	__ASSERT_DEBUG(iRawConduit, Panic(EBTProxySAPNotReadyToSendRawData));
+	if(!iRawConduit)
+		{
+		iSocket->Error(KErrNotReady, MSocketNotify::EErrorSend);
+		return 0; //Indicates write could not be completed
+		}
+
+	TUint8 flags = static_cast<TUint8>(aOptions);
+	__ASSERT_DEBUG((flags & KPacketPBFlagMask) == 0, Panic(EBTProxyUserAttemptingToTransmitL2CAPDirectData));
+	if(flags & KPacketPBFlagMask)
+		{
+		iSocket->Error(KErrNotSupported, MSocketNotify::EErrorSend);
+		return 0; //Indicates write could not be completed
+		}
+
+	// push the data onto the ACL Pool
+	// the ACL Pool in this build has a reserved slot for broadcast (could use flags!)
+	TUint retVal =0;
+	if (iPhysicalLink)
+		{
+		// only allowed to write raw stuff when a phy is in place
+		// mainly our restriction - but definately the case for broadcasting
+		retVal = iRawConduit->Write(aData, flags);
+		if (retVal==0)
+ 			{
+			iSocket->Error(KErrInUse, MSocketNotify::EErrorSend);
+ 			}
+		}
+	else
+		{
+		// haven't even got a phy
+		iSocket->Error(KErrNotReady, MSocketNotify::EErrorSend);
+		}
+
+	return retVal;
+#else
+TUint CBTProxySAP::Write(const TDesC8& /*aDesc*/,TUint /*aOptions*/, TSockAddr* /*aAddr*/)
+	{
+	Panic(EBTProxySAPUnexpectedEvent);
+	return 0;
+#endif
+	}
+
+void CBTProxySAP::Timeout(TBasebandTimeout /*aTimeout*/)
+	{
+	// none of interest
+	}
+
+TInt CBTProxySAP::CreateRawConduit()
+	{
+	// instatiates the method by which a Proxy can send raw data
+	// expected to be created via a SetOpt call into this
+	__ASSERT_DEBUG(!iRawConduit, Panic(EBTProxySAPRawConduitAlreadyExists));
+
+	TInt err = KErrAlreadyExists;
+
+	if(!iRawConduit)
+		{
+		TRAP(err, iRawConduit = CACLRawConduit::NewL(*this));
+		}
+
+	return err;
+	}
+
+void CBTProxySAP::DataReceived()
+	{
+	// do we dont know if the socket was interested in the data?!
+	// but we're unreliable, so people get whatever is here
+
+	// we can check the sock address in getdata and junk if it's not required
+	if (iSocket && iNotifiedUp)
+		{
+		iSocket->NewData(1);
+		}
+	// else drop
+	}
+
+void CBTProxySAP::GetData(TDes8& aData,TUint /*aOptions*/,TSockAddr* /*aAddr*/)
+	{
+	// the conduit has data ready for us...get it now
+	__ASSERT_DEBUG(iRawConduit, Panic(EBTProxySAPNoRawConduit));
+	if(iRawConduit)
+		{
+		iRawConduit->GetData(aData);
+		}
+	}
+
+TBool CBTProxySAP::IsModeRequested(TBTLinkMode aMode) const
+	{
+	return !(iRequestedLinkPolicy.IsModeRequested(aMode));
+	}
+
+TBool CBTProxySAP::IsAnyModeChangeRequested() const
+	{
+	return iRequestedLinkPolicy.IsAnyModeRequested();
+	}
+
+void CBTProxySAP::AsyncCheckLinkUp()
+	{
+	TCallBack cb(SignalConnectComplete, this);
+	iAsyncCallback->Set(cb);
+	iAsyncCallback->SetPriority(CActive::EPriorityHigh);
+	iAsyncCallback->CallBack();
+	}
+
+/*static*/ TInt CBTProxySAP::SignalConnectComplete(TAny* aCBTProxySAP)
+/**
+	For breaking synchronous call chain
+**/
+	{
+	// if the PhysicalSAP is connected, we should tell the proxy ASAP (asynchronously though!)
+	__ASSERT_ALWAYS(aCBTProxySAP, Panic(EBTProxySAPNullCallback));
+
+	CBTProxySAP& p = *static_cast<CBTProxySAP*>(aCBTProxySAP);
+
+	if (p.iPhysicalLink && p.iPhysicalLink->IsConnected())
+		{
+		p.iSocket->ConnectComplete();
+		p.iNotifiedUp = ETrue;
+		// lower priority back - might be useful for other async operations
+		p.iAsyncCallback->SetPriority(CActive::EPriorityStandard);
+		}
+	return EFalse;
+	}
+
+void CBTProxySAP::TerminatePhysicalLinksComplete()
+	{
+	iTerminating=ENone;
+	
+	if (iSocket)
+		{
+		// Signal that SAP can be deleted
+		iSocket->CanClose();
+		}
+	// CAREFUL - might be deleted at this point
+	}
+
+void CBTProxySAP::PhysicalLinkUp()
+	{
+	// ah! good! let's tell our socket
+	if (iSocket)
+		{
+		iSocket->ConnectComplete();
+		iNotifiedUp = ETrue;
+		}
+	}
+
+void CBTProxySAP::PhysicalLinkDown()
+	{
+	if (iSocket && iNotifiedUp)
+		{
+		iSocket->Disconnect();
+		iNotifiedUp = EFalse;
+		}
+	ClearPhysicalLink();
+	}
+
+void CBTProxySAP::PhysicalLinkError(TInt aError)
+	{
+	if (iSocket)
+		{
+		iSocket->Error(aError, MSocketNotify::EErrorAllOperations);
+		}
+	ClearPhysicalLink();
+	}
+
+void CBTProxySAP::PhysicalLinkChange(const TBTBasebandEventNotification& aEvent, CPhysicalLink& /*aPhysicalLink*/)
+/**
+	PHY has notified us of a change - demux here
+*/
+	{
+	switch(aEvent.EventType())
+		{
+		case ENotifyPhysicalLinkUp:
+			{
+			PhysicalLinkUp();
+			}
+			break;
+
+		case ENotifyPhysicalLinkDown:
+			{
+			PhysicalLinkDown();
+			}
+			break;
+
+		case ENotifyPhysicalLinkError:
+			PhysicalLinkError(aEvent.ErrorCode());
+			if(iEventNotificationStatus == EEnabledOneShot)
+				{
+				iEventNotificationStatus = EDisabled;
+				}
+			return;
+
+		default:
+			break;
+		};	
+	
+	if(iEventNotificationStatus == EEnabledOneShot)
+		{
+		TBTBasebandEventNotification event(aEvent.EventType() & iBasebandNotifyOptions, aEvent.ErrorCode());
+		if(event.EventType())
+			{
+				TBTBasebandEvent pkcgEvent(event);
+				IoctlComplete(KErrNone, KSolBtLMProxy, KLMBasebandEventOneShotNotificationIoctl, &pkcgEvent);
+
+				iEventNotificationStatus = EDisabled;
+			}
+		}
+
+	else if(iEventNotificationStatus != EDisabled)
+		{
+		TBTBasebandEventNotification event(aEvent.EventType() & iBasebandNotifyOptions, aEvent.ErrorCode());
+		if(event.EventType())
+			{
+			if(iEventNotificationQueue.IsEmpty() && iEventNotificationStatus == EEnabledCanSend)
+				{
+				// The queue is empty.  Send the event now.
+				TBTBasebandEvent pkcgEvent(event);
+				IoctlComplete(KErrNone, KSolBtLMProxy, KLMBasebandEventNotificationIoctl, &pkcgEvent);
+
+				iEventNotificationStatus = EEnabledQueuing;
+				}
+			else
+				{
+				TBTQueuedBasebandEventNotification* e = new TBTQueuedBasebandEventNotification(event);
+				if (e)
+					{
+					iEventNotificationQueue.AddLast(*e);
+					}
+				}
+			}
+		}
+	}
+
+TUint8 CBTProxySAP::GetRequestedModes() const
+	{
+	return iRequestedLinkPolicy.CurrentModeRequest();
+	}
+
+TUint8 CBTProxySAP::GetAllowedModes() const
+	{
+	return iRequestedLinkPolicy.ModesAllowed();
+	}
+
+TBool CBTProxySAP::IsRoleSwitchAllowed() const
+	{
+	return iRequestedLinkPolicy.IsSwitchAllowed();
+	}
+
+TBool CBTProxySAP::RequestedActiveMode() const
+	{
+	return iRequestedActiveMode;
+	}
+
+TRequestedLinkPolicy::TRequestedLinkPolicy(TUint8 aModesAllowed, TBool aSwitchAllowed)
+  : iSwitchAllowed(aSwitchAllowed), iModesAllowed(aModesAllowed),
+    iCurrentModeRequest(0)
+	{
+	}
+
+TBool TRequestedLinkPolicy::IsModeAllowed(TBTLinkMode aMode) const
+	{
+	TBool allowed = EFalse;
+
+	switch (aMode)
+		{
+		case EActiveMode:
+			allowed = ETrue;
+			break;
+
+		case EHoldMode:
+		case ESniffMode:
+		case EParkMode:
+			allowed = iModesAllowed & aMode;
+			break;
+
+		default:
+			Panic(EBTConnectionUnknownLowPowerMode);
+		}	
+	return allowed;
+	}
+
+TBool TRequestedLinkPolicy::IsSwitchAllowed() const
+	{
+	return iSwitchAllowed;
+	}
+
+void TRequestedLinkPolicy::SetModeAllowed(TBTLinkMode aMode, TBool aAllowed)
+	{
+	switch (aMode)
+		{
+		case EHoldMode:
+		case ESniffMode:
+		case EParkMode:
+			aAllowed ? iModesAllowed |= aMode : iModesAllowed &= ~aMode;
+			break;
+		default:
+			Panic(EBTConnectionUnknownLowPowerMode);
+		}
+	}
+
+void TRequestedLinkPolicy::SetSwitchAllowed(TBool aAllowed)
+	{
+	iSwitchAllowed = aAllowed;
+	}
+
+
+TBool TRequestedLinkPolicy::IsModeRequested(TBTLinkMode aMode) const
+	{
+	TBool requested = EFalse;
+
+	switch (aMode)
+		{
+		case EActiveMode:
+		case EHoldMode:
+		case ESniffMode:
+		case EParkMode:
+			requested = iCurrentModeRequest & aMode;
+			break;
+
+		default:
+			Panic(EBTConnectionUnknownLowPowerMode);
+		}	
+	return requested;
+	}
+
+TBool TRequestedLinkPolicy::IsAnyModeRequested() const
+	{
+	return iCurrentModeRequest;
+	}
+
+
+TInt TRequestedLinkPolicy::SetModeRequested(TBTLinkMode aMode)
+	{
+	switch (aMode)
+		{
+		case EActiveMode:
+		case EHoldMode:
+		case ESniffMode:
+		case EParkMode:
+			iCurrentModeRequest = TUint8(aMode);
+			break;
+
+		default:
+			Panic(EBTConnectionUnknownLowPowerMode);
+		}
+		return KErrNone;
+	}
+
+TUint8 TRequestedLinkPolicy::ModesAllowed() const		
+	{ 
+	return iModesAllowed; 
+	}
+
+TUint8 TRequestedLinkPolicy::CurrentModeRequest() const	
+	{ 
+	return iCurrentModeRequest; 
+	}