bluetoothcommsprofiles/btpan/bnep/CBnepBridge.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/bnep/CBnepBridge.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,628 @@
+// 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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <e32std.h>
+#include <bluetooth/logger.h>
+#include <bttypes.h>
+#include <comms-infras/eintsock.h>
+#include <elements/nm_interfaces.h>
+#include "CBnepBridge.h"
+#include "CBnepChannelController.h"
+#include "RBnepFrame.h"
+#include "bneputils.h"
+#include "CBnepLocalDevice.h"
+#include "CBnepLink.h"
+#include <networking/pktdrv.h>
+#include "pancommon.h"
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+#include <elements/nm_node.h>
+#include <comms-infras/ss_common.h>
+#include "panmessages.h"
+#include <bt_sock.h>
+#include <bttypes.h>
+
+using namespace ESock;
+using namespace Messages;
+
+#ifdef ESOCK_EXTLOG_ACTIVE
+_LIT8(KBnepSubTag, "bnep");
+#endif
+
+#endif
+// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_BNEP);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("panbnep");
+#endif
+
+// Class CBnepBridge 
+/**
+   Create the bridge and attach the local device to it.
+*/
+CBnepBridge::CBnepBridge (MPanDevice& aLocalDevice) : iDataTransferred(KMaxPanConnections)
+    {
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+    NM_LOG_NODE_CREATE(KBnepSubTag, CBnepBridge);
+#endif
+
+    CONNECT_LOGGER
+    LOG_FUNC
+    iLinks[KBnepLocalDeviceArrayId] = &aLocalDevice; 
+    iLinkCount = 1;
+    LOG2(_L8("CBnepBridge::iLinks[%d] = 0x%08x"),KBnepLocalDeviceArrayId,iLinks[KBnepLocalDeviceArrayId]);
+    }
+
+/**
+   Destroy the bridge.  Does not delete the devices as they are not owned by
+   the bridge. The links will be deleted when the CBnepChannelControllers are deleted.
+*/
+CBnepBridge::~CBnepBridge()
+    {
+    LOG_STATIC_FUNC
+    /**
+       Destroy the bridge.  Does not delete the devices as they are not owned by
+       the bridge. The links will be deleted when the CBnepChannelControllers are deleted.
+       @internalComponent
+    */
+
+    delete iDataCounterTimer;
+
+    if (iBnepPacketNotifier)
+    	{
+    	iBnepPacketNotifier->MbpnbRelease();
+    	iBnepPacketNotifier = NULL;
+    	}
+   
+
+    iLib.Close();
+    iDataTransferred.Close();
+
+    LOG1(_L8("CBnepBridge holds %d links on destruction - Invalidating links..."),iLinkCount);
+    for (TUint index = 0; index < KMaxPanConnections; ++index)
+        {
+        if((index != KBnepLocalDeviceArrayId) && (iLinks[index]))
+            {
+			// Invalidate the link as it is no longer bound to a bridge.
+            static_cast<CBnepLink*>(iLinks[index])->Invalidate();
+            }
+        }
+        
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+    // Deregister custom messages with the comms transport
+    TPanMessage::DeRegister();
+
+    NM_LOG_NODE_DESTROY(KBnepSubTag, CBnepBridge);
+
+	delete iPanLinkControl;
+#endif
+
+	CLOSE_LOGGER
+    }
+
+/**
+   Add a new device to the bridge
+   @return KErrOverflow The maximum number of supported devices are already
+   in the network.
+*/
+TInt CBnepBridge::AttachDevice (MPanDevice& aDevice)
+    {
+    LOG_FUNC
+    TUint spareSlot;
+    TInt err = GetVacantSlot(spareSlot);
+    if(KErrNone == err)
+        {
+        iLinks[spareSlot] = &aDevice;
+        iLinkCount++;
+        LOG2(_L8("CBnepBridge attaching iLinks[%d] = 0x%08x"),spareSlot,iLinks[spareSlot]);
+        LOG1(_L8("CBnepBridge holds %d links"),iLinkCount);
+        if (iBnepPacketNotifier) 
+        	{
+        	TBnepBytesTransferred counter;
+        	counter.iBytesReceived=0;
+        	counter.iBytesSent=0;
+        	counter.iBTDevAddr=aDevice.iAddr;
+        	
+	      	__ASSERT_ALWAYS(iDataTransferred.Append(counter)==KErrNone,BnepUtils::Panic(Bnep::EAppendFailed)); // Shouldn't fail as the granularity of the array is the maximum number of devices available.
+	      	
+ 	      	TInt pos = iDataTransferred.Find(counter);
+			__ASSERT_ALWAYS(pos != KErrNotFound, BnepUtils::Panic(Bnep::EAppendFailed));
+			TBnepBytesTransferred* countPtr = &iDataTransferred[pos];
+ 			aDevice.SetOwnerCountPtr(countPtr);
+	  
+	      	iBnepPacketNotifier->MbpnDeviceAdded(aDevice.iAddr);
+	      	__ASSERT_ALWAYS(iDataCounterTimer,BnepUtils::Panic(Bnep::ENullPointer));
+    	    if (!iDataCounterTimer->IsActive())
+    			{
+    				iIdleCount=0;
+    				iDataCounterTimer->Start(KBnepPacketNotifyInterval,KBnepPacketNotifyInterval,TCallBack(DataCounterCallBack,this)); // Start the timer if it's not already started
+    			}
+        	}
+
+        }
+    return err; 
+    }
+
+/**
+   Get the default (local) address for this bridge (i.e. address of it's local device).
+*/
+const TBTDevAddr& CBnepBridge::DefaultAddress () const
+    {
+    LOG_FUNC
+    __ASSERT_ALWAYS(iLinks[KBnepLocalDeviceArrayId],BnepUtils::Panic(Bnep::ENullPointer));
+    LOG_BT(_L8("CBnepBridge::DefaultAddress: %S"),iLinks[KBnepLocalDeviceArrayId]->iAddr);
+    return iLinks[KBnepLocalDeviceArrayId]->iAddr; 
+    }
+
+/**
+   Notify the bridge of the imminent destruction of a link.. 
+   This is normally called by a CBnepLink destructor, to notify the bridge that 
+   it is going down. However, it is possible for a CBnepLink instance to exist 
+   for a time without being attached to the bridge. This instance is silently managed.
+*/
+void CBnepBridge::LinkGoingDown (MPanDevice& aDevice)
+    {
+    LOG_FUNC
+    // We may safely ignore the return value here.
+    RemoveDevice(aDevice);
+    }
+
+void CBnepBridge::RemoteDeviceReady ()
+	{
+    LOG_FUNC
+	// Inform the local device that a remote device is ready
+	static_cast<CBnepLocalDevice*> (iLinks[KBnepLocalDeviceArrayId])->RemoteDeviceReady();
+	}
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+/**
+   Create a new bnep channel as a result of an incoming request
+   @param aMessage The message that requested the new channel controller
+*/
+void CBnepBridge::AttemptNewBnepConnection(const Messages::TNodeId& aSender, const Messages::TSignatureBase& aMessage, TUint16 aActivityId)
+    {
+    LOG_FUNC
+    CBnepChannelController* bnepChannelControl = NULL;
+
+	// If this assert fails check your commdb. It probably means that a non-399 commdb
+	// has been imported and is using the basic Ethernet MCPR rather than the Pan
+	// Ethernet MCPR
+	ASSERT_DEBUG(iPktDrvOwner);
+
+    // The RInternalSocket pointer in the message is owned by PAN and must
+    // not be deleted or used. The internal socket implementation must be
+    // transfered to a local RInternalSocket (see CBnepLink)
+    const TPanMessage::TCreateChannelController& msg = message_cast<const TPanMessage::TCreateChannelController>(aMessage);
+    
+    // msg.iSender in this case should be an instance of the CPanRemoteDeviceStateMachine
+    TRAPD(err, bnepChannelControl = CBnepChannelController::NewL(*this, *msg.iSocket, aSender, *iPktDrvOwner));
+    if (err != KErrNone)
+        {
+        // Report failure to create
+        TPanMessage::TChannelControllerCreated failMsg(err);
+        RClientInterface::OpenPostMessageClose(TNodeCtxId(aActivityId,Id()),aSender,failMsg);
+        return;
+        }
+
+	// Same timing as pre-399, give the notifier something to call into
+    if (iBnepPacketNotifier) 
+    	{
+    	iBnepPacketNotifier->MbpnSetLinkControl(*iPanLinkControl);
+    	}
+
+    // Send the ack on behalf of the new channel controller
+    TPanMessage::TChannelControllerCreated successMsg(KErrNone);
+    RClientInterface::OpenPostMessageClose(TNodeCtxId(aActivityId,bnepChannelControl->Id()),aSender,successMsg);
+    }
+
+#else
+// !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+/**
+   Create a new bnep channel as a result of an incoming request
+   @param aConnectedSocket A connected L2CAP socket, ready for BNEP signalling
+   @param aNotify Object to inform of events
+*/
+MBnepChannelControl& CBnepBridge::NewBnepConnectionL(RInternalSocket& aConnectedSocket, MPanConnectionNotify& aNotify)
+    {
+    LOG_FUNC
+    MBnepChannelControl& bnepChannelControl = *CBnepChannelController::NewL(*this, aConnectedSocket, aNotify);
+    if (iBnepPacketNotifier) 
+    	{
+    	iBnepPacketNotifier->MbpnSetLinkControl(aNotify.BnepConnectionController());
+    	}
+    return bnepChannelControl;
+    }
+#endif
+// SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+CBnepBridge* CBnepBridge::NewL (MPanDevice& aLocalDevice)
+    {
+    LOG_STATIC_FUNC
+    CBnepBridge* self = new(ELeave) CBnepBridge(aLocalDevice);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self; 
+    }
+
+void CBnepBridge::ConstructL() 
+	{
+    LOG_FUNC
+	        
+    _LIT(KBnepPacketNotifier,"bnepPacketNotifier.dll");
+    
+    if (iLib.Load(KBnepPacketNotifier)==KErrNone) 
+    	{
+    	TLibraryFunction func=iLib.Lookup(1);
+    	MBnepPacketNotifierBase* notifier;
+    	notifier = (MBnepPacketNotifierBase*) (*func)();
+    	iBnepPacketNotifier = (MBnepPacketNotifier*) notifier->MbpnbGetInterface(KUidBnepPacketNotifierV1);
+    	__ASSERT_DEBUG(iBnepPacketNotifier, BnepUtils::Panic(Bnep::ENullPointer));
+    	
+    	if (iBnepPacketNotifier) 
+    		{
+    		iDataCounterTimer=CPeriodic::NewL(CActive::EPriorityStandard);
+    		}
+ 		}
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+    // Register with the comms transport so we can receive custom messages
+    TPanMessage::RegisterL();
+	// Create our own MPanLinkControl implementation
+	iPanLinkControl = CPanLinkControl::NewL();
+#endif    
+	}
+
+TInt CBnepBridge::DataCounterCallBack(TAny* aThis) 
+	{
+    LOG_STATIC_FUNC
+	CBnepBridge* self = static_cast<CBnepBridge*>(aThis);
+	self->DataCounterNotify();
+	return KErrNone;
+	}
+
+void CBnepBridge::DataCounterNotify()
+	{
+    LOG_FUNC
+	TBool dataTransferred=EFalse;
+	iBnepPacketNotifier->MbpnBnepDataTransferred(iDataTransferred.Array()); // Notify the number of bytes transferred
+	for (TUint dev=0;dev<iDataTransferred.Count();++dev)
+		{
+		if (iDataTransferred[dev].iBytesSent!=0 || iDataTransferred[dev].iBytesReceived!=0)
+			{
+			iDataTransferred[dev].iBytesSent=0;
+			iDataTransferred[dev].iBytesReceived=0;
+			dataTransferred=ETrue;
+			}
+		} // Work out whether any bytes have been transferred
+	if (!dataTransferred)  // If not
+		{
+		iIdleCount++; // Increase the idle count by 1
+		if (iIdleCount >= KBnepPacketNotifySleepTicks) // If the idle count has been hit
+			{
+			__ASSERT_ALWAYS(iDataCounterTimer,BnepUtils::Panic(Bnep::ENullPointer));
+			iDataCounterTimer->Cancel(); // Cancel the timer
+			}
+		}
+	else  // If data has been transferred
+		{
+		iIdleCount=0; // Reset the idle counter
+		}
+	}
+
+/**
+   Pass a BNEP frame onto the required device(s).
+   Possible options are: local device, multicast address, single remote device.
+   @return KReadyForMoreData in all cases.
+*/
+TInt CBnepBridge::Process (RBnepFrame& aFrame, const TBTDevAddr& aSourceIfAddr)
+    {  
+    LOG_FUNC
+    TBool foundDevice = EFalse;
+    LOG(_L8("CBnepBridge: Delivering packet:"));
+    LOG_BT(_L8("CBnepBridge: Source address: %S"), aFrame.SrcAddr());
+    LOG_BT(_L8("CBnepBridge: Destination address: %S"), aFrame.DestAddr());
+    TUint link;
+    switch (aFrame.DestinationType())
+        {
+        case RBnepFrame::ELocal:
+            LOG(_L8("CBnepBridge: Frame type: RBnepFrame::ELocal"));	
+            iLinks[KBnepLocalDeviceArrayId]->Process(aFrame);
+            break;
+
+        case RBnepFrame::EMulticast:
+            LOG(_L8("CBnepBridge: Frame type: RBnepFrame::EMulticast"));
+            LOG_BT(_L8("Source address %S"),aSourceIfAddr);
+            for (link = 0; link < KMaxPanConnections; link++)
+                {
+                LOG1(_L8("iLinks[%d]"),link);
+                if ((iLinks[link] != NULL) &&
+                    (!(aSourceIfAddr == (iLinks[link]->iAddr))) &&
+                    (!(aFrame.SrcAddr() == (iLinks[link]->iAddr))) )
+                    {
+                    LOG_BT(_L8("Multicasting to %S"), iLinks[link]->Addr());
+                    iLinks[link]->Process(aFrame);
+                    }
+                }
+            break;
+
+        case RBnepFrame::ENormal:
+            LOG(_L8("CBnepBridge: Frame type: RBnepFrame::ENormal"));
+            for (link = 0; link < KMaxPanConnections; link++)
+                {
+                if (iLinks[link])
+                    {
+                    MPanDevice* linkDev = iLinks[link];
+                    if (linkDev->ForThisDevice(aFrame.DestAddr()))
+                        {
+                        LOG_BT(_L8("Found match, delivering to %S"), linkDev->Addr());
+                        linkDev->Process(aFrame);
+                        foundDevice = ETrue;
+                        break;
+                        }
+                    }
+                }
+            // unicast frame to a MAC address we haven't found.
+            // We must be in U role connected to a GN/NAP.
+            // In which case this bridge's link count must be EXACTLY 2 
+            // - this device and the GN. 
+            // Otherwise it is a GN and therefore has no
+            //  sensible destination for this frame.
+            if(!foundDevice && (2 == iLinkCount) )
+                {
+                // Never assume thak iLinks[0] is always going to be the local device.
+                // iLinks[KLocalDeviceArrayId] is the local device.
+                for (link = 0; link < KMaxPanConnections; ++link) 
+                    {
+                    // skip the local connection
+                    if(KBnepLocalDeviceArrayId != link)
+                        {
+                        if(iLinks[link])
+                            {
+                            iLinks[link]->Process(aFrame);	
+                            }
+                        }
+                    }
+                }
+            break;	
+
+        default:	
+            // Obviously we shouldn't get here under normal circumstances.
+            // In a UDEB build we'll log the event.
+            // Otherwise, just drop the frame.
+            LOG(_L8("CBnepBridge: Invalid destination type."));
+        }
+    aFrame.Reset();
+    
+   	return (KReadyForMoreData);
+
+    }
+
+
+void CBnepBridge::DataCountUpdated()
+	{
+    LOG_FUNC
+	__ASSERT_ALWAYS(iDataCounterTimer,BnepUtils::Panic(Bnep::ENullPointer));
+	if (!iDataCounterTimer->IsActive()) // If the timer is not active
+		{
+	    iIdleCount = 0; // Reset the idle counter
+ 	    iDataCounterTimer->Start(KBnepPacketNotifyInterval,KBnepPacketNotifyInterval,TCallBack(DataCounterCallBack,this)); // Start the timer
+ 	    }
+ 	}
+
+
+/**
+	Set a flag to enable a connection retry to occur - this means that Nifman will not be signalled when we disconnect all devices
+*/
+void CBnepBridge::SetRetryConnect () 
+	{
+    LOG_FUNC
+	iRetryConnect=ETrue;
+	}
+
+
+/**
+   Remove a device from the bridge.
+*/
+void CBnepBridge::RemoveDevice (MPanDevice& aDevice)
+    {
+    LOG_FUNC
+    for (TUint index = 0; index < KMaxPanConnections; ++index)
+        {
+        if(iLinks[index] == &aDevice)
+            {
+            iLinks[index] = NULL;
+            LOG1(_L8("CBnepBridge removed iLink[%d]"),index);
+            iLinkCount--;
+            LOG1(_L8("CBnepBridge has %d links"),iLinkCount);
+			if (iBnepPacketNotifier) 
+        		{
+        		for (TUint dataIndex=0; dataIndex < iDataTransferred.Count(); ++dataIndex)
+        			{
+        			if (iDataTransferred[dataIndex].iBTDevAddr==aDevice.iAddr) 
+        				{
+        				iDataTransferred.Remove(dataIndex);
+        				}
+        			}
+        		iBnepPacketNotifier->MbpnDeviceRemoved(aDevice.iAddr);
+        		}
+
+			// If no more remote devices, tell the local device
+        	if (iLinkCount == 1 && !iRetryConnect)
+        		{
+	            LOG1(_L8("CBnepBridge::RemoveDevice - Only local link remaining [0x%08x]"), iLinks[KBnepLocalDeviceArrayId]);
+        		static_cast<CBnepLocalDevice*> (iLinks[KBnepLocalDeviceArrayId])->AllRemoteDevicesDisconnected ();
+        		}
+            
+            iRetryConnect = EFalse;
+            
+            break;
+            }
+        }
+    }
+
+/**
+   Forces a disconnect on all links.
+*/
+void CBnepBridge::StopLinks ()
+    {
+    LOG_FUNC
+    for (TUint index = 0; index < KMaxPanConnections; ++index)
+        {
+        if((KBnepLocalDeviceArrayId !=index) &&
+           (NULL != iLinks[index]))
+            {
+            iLinks[index]->Stop(); // Stops all pending reads.
+            }
+        }
+    }
+
+/**
+   Attempts to find the index of a vacant slot in the bridge device array.
+   @param aSlotIndex holds the array index of the vacant slot on success
+   @return KErrNone on success
+   @return KErrOverflow if there is no vacant slot
+*/
+TInt CBnepBridge::GetVacantSlot (TUint& aSlotIndex)
+    {
+    LOG_FUNC
+    
+    for(TUint index = 0; index < KMaxPanConnections; ++index)
+        {
+        if(NULL == iLinks[index])
+            {
+            aSlotIndex = index;
+            return KErrNone;
+            }
+        }
+    return KErrOverflow;
+    }
+
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+/**
+Entry point from the comms transport
+*/
+void CBnepBridge::ReceivedL(const Messages::TRuntimeCtxId& aSender, const Messages::TNodeId& /* aRecipient */, Messages::TSignatureBase& aCFMessage)
+    {
+    LOG_FUNC
+	if (aCFMessage.MessageId().Realm() == TPanMessage::ERealmId)
+    	{
+        switch (aCFMessage.MessageId().MessageId())
+            {
+            case TPanMessage::TCreateChannelController::EId:
+                {
+                const TNodeCtxId& ctxId = address_cast<TNodeCtxId> (aSender);
+                TUint activityId = ctxId.NodeCtx();
+                AttemptNewBnepConnection(ctxId.Node().NodeId(), aCFMessage, activityId);
+                }
+                break;            
+            
+            case TPanMessage::TSetRetryConnect::EId:
+                {
+                // iSender in this case should be the CPanAgent
+                SetRetryConnect();
+                TPanMessage::TSetRetryConnectComplete msg(KErrNone);
+                RClientInterface::OpenPostMessageClose(Id(),aSender,msg);	        
+                }
+                break;
+            
+            default:
+                __ASSERT_DEBUG(EFalse, BnepUtils::Panic(Bnep::EUnexpectedMessage));
+            }
+    	}
+    else
+        {
+        __ASSERT_DEBUG(EFalse, BnepUtils::Panic(Bnep::EUnexpectedMessage));
+        }
+    
+    // Absorb messages
+    aCFMessage.ClearMessageId();
+    }
+
+CBnepBridge::CPanLinkControl* CBnepBridge::CPanLinkControl::NewL()
+    {
+    LOG_STATIC_FUNC
+    CBnepBridge::CPanLinkControl* self = new(ELeave) CPanLinkControl();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self; 
+    }
+
+CBnepBridge::CPanLinkControl::CPanLinkControl()
+	{
+    LOG_FUNC
+	}
+		
+void CBnepBridge::CPanLinkControl::ConstructL()
+	{
+    LOG_FUNC
+	User::LeaveIfError(iSockServ.Connect());
+	}
+
+CBnepBridge::CPanLinkControl::~CPanLinkControl()
+	{
+    LOG_FUNC
+	iSockServ.Close();
+	}
+
+TAny* CBnepBridge::CPanLinkControl::MplcbGetInterface(const TUid & aInterface)
+	{
+    LOG_FUNC
+    if (aInterface ==KUidPanLinkControlV1) 
+        {    
+        return this;
+        }    
+    return NULL;
+	}
+
+TInt CBnepBridge::CPanLinkControl::MplcRequestSniff(const TBTDevAddr &aAddr)
+	{
+    LOG_FUNC
+    RBTPhysicalLinkAdapter physicalLink;
+    TInt err = physicalLink.Open(iSockServ, const_cast<TBTDevAddr&>(aAddr));
+	if(err == KErrNone)
+		{
+    	err = physicalLink.ActivateSniffRequester();
+    	physicalLink.Close();
+		}
+	return err;
+	}
+
+TInt CBnepBridge::CPanLinkControl::MplcRequestActive(const TBTDevAddr &aAddr) 
+	{
+    LOG_FUNC
+    RBTPhysicalLinkAdapter physicalLink;
+    TInt err = physicalLink.Open(iSockServ, const_cast<TBTDevAddr&>(aAddr));
+	if(err == KErrNone)
+		{
+    	physicalLink.ActivateActiveRequester();
+    	physicalLink.Close();
+		}
+	return err;
+	}
+#endif
+