diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/bnep/CBnepLink.cpp --- /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 +#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; + } + +