--- /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;
+ }