bluetoothcommsprofiles/btpan/bnep/CBnepLink.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/bnep/CBnepLink.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,438 @@
+// 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 <bluetooth/logger.h>
+#include "bt_sock.h"
+#include "CBnepLink.h"
+#include "CSocketReader.h"
+#include "CSocketWriter.h"
+#include "CMultiAddrFilterTable.h"
+#include "CNetTypeFilterTable.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_BNEP);
+#endif
+
+// Class CBnepLink 
+
+/**
+Construct a link.
+@param aBridge The CBnepBridge that this link may eventually be attached to to.
+@param aSocket The socket handed up to the agent from L2CAP which this link will use.
+@param aParser The CBnepChannelController for this link.
+@internalComponent
+*/
+CBnepLink::CBnepLink (MPanDeviceOwner& aBridge, RInternalSocket& aSocket, MLinkManager& aParser)
+    : iLinkManager(aParser), iNegotiating(ETrue)
+    {
+    LOG_FUNC
+    
+    // Take ownership of the socket and acquire the remote end's BT address.                                                                                      	
+    iSocket.Transfer(aSocket);
+    TBTSockAddr btSockAddr;
+    iSocket.RemoteName(btSockAddr);
+    iAddr = btSockAddr.BTAddr();
+    
+    // We tell the link who it's owner is likely to be.
+    // Note that the link is NOT yet attached, though.
+    SetOwner(aBridge); 
+    SetOwnerCountPtr(NULL);    
+    }
+
+/**
+Remove from bridge, delete reader and writer.
+@internalComponent
+*/
+CBnepLink::~CBnepLink()
+    {
+    LOG_FUNC
+    
+#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+    // With 399 we null iOwner if the CBnepBridge is deleted before all the
+    // links go down (see Invalidate())
+    
+    // If we're not actually attached, the bridge will ignore the request.
+    __ASSERT_DEBUG(iOwner,BnepUtils::Panic(Bnep::ENullPointer));
+#endif
+    if(iOwner)
+        {
+        iOwner->LinkGoingDown(*this);
+        }
+    
+    delete iReader;
+    delete iWriter;
+
+	TRequestStatus status;
+	iSocket.Shutdown(RSocket::ENormal, status);
+	User::WaitForRequest(status);
+	iSocket.Close();
+	
+    delete iMultiAddrFilters;
+    delete iNetTypeFilters;
+    
+    iOutgoing.Reset();
+    iIncoming.Reset();
+    }
+
+
+/**
+Create the reader and writer objects, and 
+attempt to attach this device to the bridge.
+@internalComponent
+*/
+void CBnepLink::ConstructL ()
+    {
+    LOG_FUNC
+    iReader = CSocketReader::NewL(iSocket, *this);
+    iWriter = CSocketWriter::NewL(iSocket, *this);
+    
+    // If this leaves, we have an unattached link that will be deleted during cleanup. 
+    // This is the scenario in which we don't want to attempt to notify the 
+    // bridge of our demise.
+    User::LeaveIfError(iOwner->AttachDevice(*this));
+    
+    // Start the reader running
+    iReader->Read();
+    }
+
+/**
+Create a BNEP link object.
+@param aBridge The CBnepBridge that this link may eventually be attached to to.
+@param aSocket The socket handed up to the agent from L2CAP which this link will use.
+@param aParser The CBnepChannelController for this link.
+@internalComponent
+*/
+CBnepLink* CBnepLink::NewL (MPanDeviceOwner& aBridge, RInternalSocket& aSocket, MLinkManager& aParser)
+    {
+    LOG_STATIC_FUNC
+    CBnepLink* self = new(ELeave) CBnepLink(aBridge, aSocket, aParser);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return(self);
+    }
+
+/**
+Call from the bridge to send a packet.
+@param aFrame The RBnepFrame from which a packet will be created.
+@internalComponent
+*/
+void CBnepLink::Process (RBnepFrame& aFrame)
+    {
+    LOG_FUNC
+    if(iNegotiating)
+        {
+        LOG(_L8("Dropping data frame from bridge during role negotiation"));
+		return;
+        }
+
+    TInt err = SendFrame(aFrame);
+        
+    if (err != KErrNone)
+      	{
+      	// Log error but don't send it to the bridge as the IP stack
+       	// should not be flowed off if there is a problem with one link
+        LOG1(_L8("Sending data frame returned error: %d"), err);    	
+       	}
+ 	else
+ 		{
+ 		UpdateOwnerCount(0, aFrame.PayloadLength());
+ 		}
+    
+    }
+
+/**
+Call from a control processor to cache a control for 
+later output processing. This call transfers ownership of the 
+RBnepControl object down into the RBnepFrame on which it is queued.
+@param aCommand The control to be cached.
+@internalComponent
+*/
+void CBnepLink::QueueOnOutput (RBnepControl* aCommand)
+    {
+    
+    LOG_FUNC
+    iOutgoing.InsertControl(aCommand);
+    }
+
+/**
+This is called from within the RunL of the SocketReader 
+when new data has been presented to the incoming side of the link.
+@internalComponent
+*/
+void CBnepLink::ReadComplete (RMBufChain& aChain)
+    {
+    LOG_FUNC
+    iOutgoing.Reset();  // The output side is set to a known state
+    // The input side of the link attempts to parse the 
+    // input packet into something meaningful.          
+    TRAPD(err, iIncoming.ParseBnepFrameL(aChain, LocalAddr(), iAddr));
+    aChain.Free(); // we're finished with this now, regardless.
+
+    if (!err)
+        {
+        Proceed(); // Start processing the contents of the input side of the link.
+        }
+    else
+        {
+        iIncoming.Reset(); // Discard the contents of the input side: they are unusuable.
+        }
+    }
+
+/**
+The remote device has disconnected.
+@internalComponent
+*/
+void CBnepLink::RemoteDeviceDisconnect (TInt aError)
+    {
+    
+    LOG_FUNC
+    iReader->Cancel();
+    iWriter->Cancel();
+    iLinkManager.RemoteDeviceDisconnect(aError);
+    }
+
+/**
+(Re)start data transfer
+@internalComponent
+*/
+void CBnepLink::ResumeDataTransfer ()
+    {
+    LOG_FUNC
+    iNegotiating = EFalse;
+	}
+
+/**
+Request to send a frame from either the bridge or the channel controller
+@param aFrame the frame to be sent
+@internalComponent
+*/
+TInt CBnepLink::SendFrame (RBnepFrame& aFrame)
+    {
+    LOG_FUNC
+	TBool filterEthernetPayload = EFalse;
+	TInt rerr = KErrNone;
+	
+    if(!aFrame.Includes(RBnepFrame::EControl)) // Don't filter controls
+        {
+        LOG(_L8("Not a control message"));
+        if(iMultiAddrFilters) // If no Multicast Address filters have been set, pass this regardless
+            {
+            LOG(_L8("We have Multicast Address filters set"));
+            if (RBnepFrame::EMulticast == aFrame.DestinationType()) // Is the destination a valid multicast address?
+                { 
+                LOG(_L8("We have a Multicast destination type"));   	
+                TBTDevAddr dest = aFrame.DestAddr();
+                if(iMultiAddrFilters->FilteredOut(dest)) // // Are we within a permissible range?
+                    {
+					filterEthernetPayload = ETrue;
+                    }
+                }
+            }
+
+        if(iNetTypeFilters) // If no Network Type Protocol filters have been set, pass this regardless.
+            {
+            LOG(_L8("We have Network Protocol Type filters set"));
+            TUint16 protocol = aFrame.Protocol();
+            LOG1(_L8("Frame protocol = %04x"),protocol);
+            if(iNetTypeFilters->FilteredOut(protocol))// Are we within a permissible range?
+                {
+				filterEthernetPayload = ETrue;                
+				}
+            }
+        }
+
+	// Check there is something to send.
+	if(aFrame.Includes(RBnepFrame::EControl) ||
+	   (aFrame.Includes(RBnepFrame::EDataFrame) && (!filterEthernetPayload || aFrame.Includes(RBnepFrame::EExtensionHeaders))))
+	   	{
+		// there is something valid to send.
+	    RMBufChain chain; // Beware the potential memory leak.
+	    TRAP(rerr, aFrame.BuildBnepFrameL(chain, LocalAddr(), iAddr, filterEthernetPayload));
+	    if (!rerr)
+	        {
+	        iWriter->Write(chain); // SocketWriter will free the chain for us.
+	        }
+	    else
+	        {
+	        chain.Free(); // Otherwise we need to plug the potential leak.
+	        }
+	   	}
+	// ELSE: Nothing to send.  Return KErrNone.
+
+    return rerr;
+    }
+
+/**
+Suspend data transfer whilst new roles are negotiated
+@internalComponent
+*/
+void CBnepLink::SuspendDataTransfer ()
+    {
+    LOG_FUNC
+    iNegotiating = ETrue;
+    }
+
+void CBnepLink::RemoteDeviceReady()
+	{
+    iOwner->RemoteDeviceReady();
+	}
+
+/**
+Install a table of Multicast Address filters on this link. 
+Any existing table will be deleted.
+@param aFilterTable The filter table to be installed. Can be NULL, which disables the filter.
+@internalComponent
+*/
+void CBnepLink::Install (CMultiAddrFilterTable* aFilterTable)
+    {
+    delete iMultiAddrFilters;
+    iMultiAddrFilters = aFilterTable;
+    }
+
+/**
+Install a table of Network Protocol Type filters on this link.
+Any existing table will be deleted.
+@param aFilterTable The filter table to be installed. Can be NULL, which disables the filter.
+@internalComponent
+*/
+void CBnepLink::Install (CNetTypeFilterTable* aFilterTable)
+    {
+    delete iNetTypeFilters;
+    iNetTypeFilters = aFilterTable;
+    }
+
+/**
+The control processing method of the link. This method supports re-entrant calls 
+because of the ambiguity of the interface between BNEP and the PAN Agent.
+Input side processing has priority over output side. When all input side 
+processing has finished, the output side will be addressed if there is 
+anything outstanding.
+@internalComponent
+*/
+void CBnepLink::Proceed ()
+    {
+    LOG_FUNC
+    
+    if(iInvalid)
+    	{
+    	// The link is only ever put into an invalid state when the
+    	// CBnepBridge it is attached to is deleted.
+    	// As the CBnepChannelControllers (and therefore CBnepLinks) are owned
+    	// by Pan Agent, the CBnepBridge ignores tidying them up, leaving the
+    	// job upto Pan Agent. The design of Bnep is such that it is assumed
+    	// that Pan Agent will tidy up these links in the same operation that 
+    	// deletes the packet driver (which is our local device bnep
+    	// representation).
+    	// As this behaviour is determined by the NifMan implementation, we get
+    	// Bnep to "invalidate" the links attached to it on deletion, such that
+    	// if we find they are left dangling in debug builds we will be 
+    	// informed by a panic, and otherwise we will handle the strange
+    	// situation as gracefully as possible by dropping packets on this
+    	// rogue link.
+    	__ASSERT_DEBUG(EFalse, BnepUtils::Panic(Bnep::EProceedingOnInvalidLink));
+    	iIncoming.Reset();
+    	return;
+    	}
+
+    if(iIncoming.Includes(RBnepFrame::EControl))
+        {
+        LOG(_L8("Proceeding with a control message"));
+        iIncoming.ExecuteControl(iLinkManager);
+        }
+
+	UpdateOwnerCount(iIncoming.PayloadLength(), 0);
+	
+    if(iIncoming.Includes(RBnepFrame::EDataFrame))
+        {
+        // Only send if we are enabled for data transfer. 
+        // Otherwise the packet is dropped.
+        if(!iNegotiating)
+            {
+            iIncoming.SetUplinkAccessAllowedForBnepLink(iUplinkAccessAllowed);
+            iOwner->Process(iIncoming, iAddr);
+            }
+        else
+            {
+            LOG(_L8("Negotiating roles: inbound traffic data not allowed: dropping inbound frame."));
+            }
+        }
+    
+    
+    // All input side processing is now 'finished'. 
+    
+	// If we've finished with the incoming packet...
+    if (iIncoming.IsEmpty())
+    	{
+    	// We can now queue a new read.
+    	iReader->Read();
+    	
+    	// Should we be sending a response yet?
+		if (!iOutgoing.IsEmpty() && iOutgoing.Includes(RBnepFrame::EControl) &&	// We have controls to respond with
+			!iLinkManager.AwaitingResponse())									// We're not still waiting for something else
+	        {
+	        TInt err = SendFrame(iOutgoing);
+	        if (err)
+	            {
+	            LOG1(_L8("Dropped a packet: SendFrame error %d"),err);
+	            }
+			else
+				{
+				UpdateOwnerCount(0, iOutgoing.PayloadLength());
+				}            
+	        }
+    	}
+    }
+
+/**
+Stops all pending reads on a link..
+*/
+void CBnepLink::Stop ()
+    {
+    iReader->Cancel();
+    }
+    
+
+/**
+Invalidates the link when it is no longer connected to a bridge.
+*/
+void CBnepLink::Invalidate ()
+	{
+	iInvalid = ETrue;
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY	
+    iOwner = NULL; // No longer valid
+#endif
+	}
+
+void CBnepLink::UpdateOwnerCount(TInt aReceivedCount, TInt aSentCount)
+	{
+	if(iOwnerCountPtr && (aReceivedCount>0 || aSentCount>0)) // iOwnerCountPtr will be NULL if CBnepBridge::iBnepPacketNotifier is NULL
+ 		{
+  		iOwnerCountPtr->iBytesReceived += aReceivedCount;
+ 		iOwnerCountPtr->iBytesSent += aSentCount;
+  		iOwner->DataCountUpdated();
+  		}
+  	}
+
+void CBnepLink::SetUplinkAccessAllowedForBnepLink(TBool aAllowed)
+	{
+	iUplinkAccessAllowed = aAllowed;
+	}
+
+