--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/bnep/RBnepFrame.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1021 @@
+// 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 <e32std.h>
+#include <bttypes.h>
+#include <es_mbuf.h>
+
+#include "RBnepFrame.h"
+#include "bneputils.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_BNEP);
+#endif
+
+const TUint8 KEBit = 0x80;
+const TUint16 KQTag = 0x8100;
+
+// 'minTypeValue' from section 4.2.7.1 of the 802.3-2002 specification
+// Subtract one, as the constant in the spec is for the first non-length value.
+const TUint16 K802_3MaxLength = 1536 - 1;
+
+void doResetControl(TAny* aControl)
+ {
+ /**
+ Reset and destroy an RBnepControl object.
+ */
+ LOG_STATIC_FUNC
+ RBnepControl* control = static_cast<RBnepControl*>(aControl);
+ control->Free();
+ delete control;
+ }
+
+RBnepFrame::RBnepFrame()
+ : iCommandQueue(_FOFF(RBnepControl, iLink))
+ {
+ /**
+ Construct and initialise (reset) a BNEP frame.
+ @internalComponent
+ */
+ LOG_FUNC
+ Reset();
+ }
+
+void RBnepFrame::BuildBnepControlFrameL (RMBufChain& aChain)
+ {
+ /**
+ Build a BNEP control frame from the encapsulated data.
+ @param aChain The target to build the frame into.
+ @internalComponent
+ */
+ LOG_FUNC
+ TUint8 frameType = EBnepControl;
+ // There have to be items in the command queue
+ if(iCommandQueue.IsEmpty())
+ {
+ User::Leave(KErrUnderflow);
+ }
+ else
+ {
+ // If the last item is also the first one, there must be
+ // one and only one item in the queue.
+ // If there is more than one, then the ebit must be set.
+ // Note: there is no checking done here that the queue items are
+ // small enough to fit into an extension header.
+ TUint8 ebit = static_cast<TUint8>(((iCommandQueue.IsLast(iCommandQueue.First())) ? 0 : KEBit));
+ frameType |= ebit;
+
+ RBnepControl* buffer = iCommandQueue.First();
+ buffer->CopyL(aChain);
+ iCommandQueue.Remove(*buffer);
+ buffer->Free();
+ delete buffer;
+
+ aChain.PrependL(sizeof(TUint8));
+ TPckgBuf<TUint8> pkgFrameType(frameType);
+ aChain.CopyIn(pkgFrameType,RBnepControl::KControlTypeOffset);
+ if(ebit) // We have at least one extension
+ {
+ TSglQueIter<RBnepControl> iter(iCommandQueue);
+ iter.SetToFirst();
+ RBnepControl* element;
+ while ((element = iter++), element)
+ {
+ TPckgBuf<TInt8> aLength(static_cast<TInt8>(element->Length()));
+ element->PrependL(sizeof(TInt8));
+ element->CopyIn(aLength);
+
+ element->PrependL(sizeof(TUint8));
+ if(iCommandQueue.IsLast(element))
+ {
+ TPckgBuf<TUint8> extFrameType(static_cast<TUint8>(EBnepExtensionControl));
+ element->CopyIn(extFrameType);
+ }
+ else
+ {
+ // The extension bit must be set.
+ TPckgBuf<TUint8> extExtFrameType(static_cast<TUint8>(EBnepExtensionControl | KEBit));
+ element->CopyIn(extExtFrameType);
+ }
+
+ aChain.Append(*element);
+ }
+ }
+ LOG1(_L8("Final Chain length = %d"),aChain.Length());
+ Reset();
+ }
+ }
+
+void RBnepFrame::BuildBnepDataFrameL(RMBufChain& aChain,
+ const TBTDevAddr& aLocalAddr,
+ const TBTDevAddr& aRemoteAddr,
+ TBool aFilterEthernetPayload)
+ {
+ /**
+ Build a BNEP data frame from the encapsulated data.
+ The method deals with compressing off any unnecessary address data based on
+ the parameters supplied.
+ @param aChain The target to build the frame into.
+ @param aLocalAddr The address of the bridge (local side of BNEP link).
+ @param aRemoteAddr The address of the remote end of the BNEP link.
+ */
+ LOG_FUNC
+ // If the command queue has items in it, we need to build extension headers.
+ TUint8 frameType;
+
+ TBool sendDest = (aRemoteAddr != iDestAddr);
+ TBool sendSrc = (aLocalAddr != iSrcAddr);
+ TInt headerLength;
+ if (sendDest && sendSrc)
+ {
+ frameType = EBnepGeneralEthernet;
+ headerLength = KGeneralEthernetHeaderLength;
+ LOG(_L8("frameType = EBnepGeneralEthernet;"));
+ LOG1(_L8("headerLength = %d"),headerLength);
+ }
+ else
+ {
+ if (sendSrc)
+ {
+ frameType = EBnepCompressedEthernetSourceOnly;
+ headerLength = KCompressedEthernetSourceOnlyHeaderLength;
+ LOG(_L8("frameType = EBnepCompressedEthernetSourceOnly;"));
+ LOG1(_L8("headerLength = %d"),headerLength);
+ }
+ else
+ {
+ if (sendDest)
+ {
+ frameType = EBnepCompressedEthernetDestOnly;
+ headerLength = KCompressedEthernetDestOnlyHeaderLength;
+ LOG(_L8("frameType = EBnepCompressedEthernetDestOnly;"));
+ LOG1(_L8("headerLength = %d"),headerLength);
+ }
+ else
+ {
+ frameType = EBnepCompressedEthernet;
+ headerLength = KCompressedEthernetHeaderLength;
+ LOG(_L8("frameType = EBnepCompressedEthernet"));
+ LOG1(_L8("headerLength = %d"),headerLength);
+ }
+ }
+ }
+ aChain.AllocL(headerLength);
+
+ if(Includes(EExtensionHeaders))
+ {
+ frameType |= KEBit;
+ }
+
+ LOG1(_L8("Setting type to %02x"), frameType);
+ TInt offset = 0;
+ TPckgBuf<TUint8> pkgFrameType(frameType);
+ aChain.CopyIn(pkgFrameType, offset++);
+ if (sendDest)
+ {
+ LOG_BT(_L8("Inserting destination address %S"), iDestAddr);
+ aChain.CopyIn(iDestAddr.Des(), offset);
+ offset += KBTDevAddrSize;
+ }
+ if (sendSrc)
+ {
+ LOG_BT(_L8("Inserting source address %S"), iSrcAddr);
+ aChain.CopyIn(iSrcAddr.Des(), offset);
+ offset += KBTDevAddrSize;
+ }
+
+ // Set-up the protocol ID to use for this packet.
+ TUint16 protocol = (aFilterEthernetPayload ? 0x0000 : iProtocol);
+
+ aChain.AppendL(KNetworkProtocolTypeFieldLength);
+ TBuf8<KNetworkProtocolTypeFieldLength> protocolBuf;
+ protocolBuf.SetMax();
+
+ if (Includes(EHas1Q))
+ {
+ BigEndian::Put16(&protocolBuf[0], static_cast<TUint16>(KQTag));
+ }
+ else
+ {
+ BigEndian::Put16(&protocolBuf[0], static_cast<TUint16>(protocol));
+ }
+ aChain.CopyIn(protocolBuf, offset);
+ offset += KNetworkProtocolTypeFieldLength;
+
+ // Cannot just append the ethernet payload mbufs, because if this is a
+ // multicast frame, this will corrupt it for others
+ RMBufChain finalPacket;
+ CleanupStack::PushL(finalPacket); // This will call Free() as its cleanup
+ iFramePayload.CopyL(finalPacket);
+
+ // Filter out the ethernet payload if required.
+ if(aFilterEthernetPayload)
+ {
+ TInt payloadOffset = 0;
+ // Find the start of the ethernet payload.
+ TBuf8<KExtensionHeaderHeaderBytes> buf;
+ buf.SetMax();
+
+ TUint8 ebit = ETrue;
+ while(ebit)
+ {
+ // The extension must be long enough for the header.
+ if((payloadOffset + KExtensionHeaderHeaderBytes) > finalPacket.Length())
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Move the offset to the next extension header.
+ finalPacket.CopyOut(buf, payloadOffset);
+ ebit = buf[0] & KEBit;
+ payloadOffset += (buf[1] + KExtensionHeaderHeaderBytes);
+ }
+
+ // If the packet includes IEEE 802.1Q fields then these should remain.
+ // The network protocol field should be set to zero.
+ if(Includes(EHas1Q))
+ {
+ if((payloadOffset + KIEEE802_1QTagFieldLength + KNetworkProtocolTypeFieldLength) > finalPacket.Length())
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ protocolBuf[0] = 0;
+ protocolBuf[1] = 0;
+ finalPacket.CopyIn(protocolBuf, payloadOffset + KIEEE802_1QTagFieldLength);
+ payloadOffset += (KIEEE802_1QTagFieldLength + KNetworkProtocolTypeFieldLength);
+ }
+
+ // The extension headers are finished. Remove any remaining data.
+ finalPacket.TrimEnd(payloadOffset);
+ }
+
+ // Append will take ownership of finalPacket
+ CleanupStack::Pop(); // finalPacket
+ // Add any payload onto the chain.
+ aChain.Append(finalPacket);
+
+ LOG1(_L8("RBnepFrame::BuildBnepDataFrameL final Chain length = %d"),aChain.Length());
+ }
+
+void RBnepFrame::BuildBnepFrameL(RMBufChain& aChain, const TBTDevAddr& aLocalAddr, const TBTDevAddr& aRemoteAddr, TBool aFilterEthernetPayload)
+ {
+ /**
+ Build a BNEP frame from encapsulated data.
+ Processes the data carried by this frame to build a frame which can
+ be sent to a remote PAN device. This involves compressing off any
+ addresses which are not required for this link and inserting any
+ extension headers.
+ @param aChain The target MBufChain to build into.
+ @param aLocalAddr The address of the local PAN node.
+ @param aRemoteAddr The address of the remote PAN node.
+ @internalComponent
+ */
+ LOG_FUNC
+ if (Includes(EControl))
+ {
+ BuildBnepControlFrameL(aChain);
+ }
+ else
+ {
+ BuildBnepDataFrameL(aChain, aLocalAddr, aRemoteAddr, aFilterEthernetPayload);
+ }
+ }
+
+void RBnepFrame::BuildEthernetFrameL(RMBufPacket& aChain)
+ {
+ /**
+ Builds an ethernet frame from the BNEP frame.
+ This function ignores away any control data present and simply inserts all
+ addresses, protocol and 802.1Q data, as well as the data payload.
+
+ This function always builds an Ethernet II format frame. This should be
+ accepted by the ethernet NIF, even if it is configured to send in LLC/SNAP
+ format. This behaviour is unlikely to change as it would be valid for a
+ remote wired station to send a mixture of packet formats. As the packet
+ driver has no way of knowing which format has been configured, our options
+ here are limited.
+
+ @param aChain The MBufPacket to build the packet into.
+ @internalComponent
+ */
+ LOG_FUNC
+ // WARNING! Potential for a memory leak follows.
+ // Remember to free this RMBufChain before you exit.
+ RMBufChain tempFrame;
+ CleanupStack::PushL(tempFrame);
+
+ LOG(_L8("Attempting to copy payload"));
+ // Check there is a valid payload
+ if(iFramePayload.IsEmpty())
+ {
+ LOG(_L8("No payload"));
+ User::Leave(KErrUnderflow);
+ }
+ iFramePayload.CopyL(tempFrame);
+
+ // Any extensions need to be removed.
+ if(Includes(EExtensionHeaders))
+ {
+ TBuf8<KExtensionHeaderHeaderBytes> buf;
+ buf.SetMax();
+
+ TUint8 ebit = ETrue;
+ while(ebit)
+ {
+ // The extension must be long enough for the header.
+ if((KExtensionHeaderHeaderBytes) > tempFrame.Length())
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Move the offset to the next extension header.
+ tempFrame.CopyOut(buf, 0);
+ ebit = buf[0] & KEBit;
+ tempFrame.TrimStart(buf[1] + KExtensionHeaderHeaderBytes);
+ }
+ }
+
+ // Check there is some data to send.
+ if(Includes(EHas1Q) && (tempFrame.Length() <= (KIEEE802_1QTagFieldLength + KNetworkProtocolTypeFieldLength)) ||
+ tempFrame.IsEmpty())
+ {
+ LOG(_L8("No data to send pass up."));
+ User::Leave(KErrUnderflow);
+ }
+
+ // Add protocol.
+ TUint16 protocol = (Includes(EHas1Q) ? KQTag : iProtocol);
+
+ TBuf8<KNetworkProtocolTypeFieldLength> protocolBuf;
+ protocolBuf.SetMax();
+ tempFrame.PrependL(KNetworkProtocolTypeFieldLength);
+ BigEndian::Put16(&protocolBuf[0], static_cast<TUint16>(protocol));
+ tempFrame.CopyIn(protocolBuf);
+
+ // Add addresses
+ tempFrame.PrependL(KBTDevAddrSize);
+ LOG_BT(_L8("Inserting source address %S"),iSrcAddr);
+ tempFrame.CopyIn(iSrcAddr.Des());
+
+ tempFrame.PrependL(KBTDevAddrSize);
+ LOG_BT(_L8("Inserting destination address %S"),iDestAddr);
+ tempFrame.CopyIn(iDestAddr.Des());
+
+ // This should be removed when defect DEF066321 is fixed.
+ TInt alignLength = Min(tempFrame.Length(), KMBufSmallSize);
+ if(tempFrame.Align(alignLength) != alignLength)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ RMBufQ tempQueue;
+ tempQueue.Assign(tempFrame);
+ CleanupStack::Pop(); // Remove tempFrame from the cleanup stack
+ CleanupStack::PushL(tempQueue);
+
+ aChain.CreateL(tempQueue);
+ CleanupStack::PopAndDestroy(); // Remove tempQueue from the cleanup stack
+ // As RMBufQs provide support for normal cleanup stack
+ // usage, this will cause the Q to be Free()ed.
+
+ // Create the flags field for the packet info header.
+ // Mark the packet as being from BNEP
+ TUint flags = KBnep;
+
+ // Check if this packet can be forward to DHCP / NAPT
+ if(iUplinkAccessAllowedForBnepLink)
+ {
+ flags |= KBnepForwardingAllowed;
+ }
+
+ aChain.Info()->iFlags = flags;
+ aChain.Pack();
+ }
+
+const TBTDevAddr& RBnepFrame::DestAddr () const
+ {
+ LOG_FUNC
+ return iDestAddr;
+ }
+
+RBnepFrame::TDestAddrType RBnepFrame::DestinationType () const
+ {
+ /**
+ Return the type of destination for the frame (local, multicast address,
+ or a specified machine).
+ @internalComponent
+ */
+ LOG_FUNC
+ if (TBTDevAddr(0) == iDestAddr)
+ {
+ return ELocal;
+ }
+ if (BnepUtils::IsMulticast(iDestAddr))
+ {
+ return EMulticast;
+ }
+ return ENormal;
+ }
+
+TBool RBnepFrame::Includes (TPacketContents aContent) const
+ {
+ /**
+ Accessor function for contents of packet.
+ @param aContent The type of content to check for.
+ @internalComponent
+ */
+ LOG_FUNC
+ return (iPacketContents & static_cast<TUint8>(aContent));
+ }
+
+void RBnepFrame::InsertControl (RBnepControl* aCommand)
+ {
+ /**
+ Inserts and takes ownership of a BNEP command.
+ @param aCommand The command to insert into the frame. The method takes
+ ownership of the object, which should be heap based.
+ @internalComponent
+ */
+ LOG_FUNC
+ //iCommandQueue.AddLast(*aCommand);
+ iCommandQueue.AddLast(*aCommand);
+ SetContents(EControl);
+ }
+
+TBnepPacketType RBnepFrame::ParseBnepFrameL (RMBufChain& aInboundChain, const TBTDevAddr& aLocalAddr, const TBTDevAddr& aRemoteAddr)
+ {
+ /**
+ Parse a supplied BNEP frame.
+ Parses the provided BNEP frame, separating data and control messages and
+ resolving any source and destination addresses.
+ @param aInboundChain The frame received from the remote device
+ @param aLocalAddr The address of the bridge (the local PAN node and possible
+ destination of the packet)
+ @param aRemoteAddr The address of the remote PAN node (the possible source
+ of the packet)
+ @internalComponent
+ */
+ LOG_FUNC
+ if(aInboundChain.Length() < 1)
+ {
+ User::Leave(KErrUnderflow);
+ }
+ Reset();
+ // Extract the packet type and the Extension bit.
+ TBnepPacketType type = static_cast<TBnepPacketType>(aInboundChain.First()->Ptr()[0]);
+ aInboundChain.TrimStart(sizeof(TUint8));
+ // Test the extension bit
+ TBool ebit = type & KEBit;
+ // Discard the extension bit
+ type = static_cast<TBnepPacketType>(type & (~KEBit));
+ LOG1(_L8("Type 0x%02x"),type);
+ LOG1(_L8("Ebit 0x%02x"),ebit);
+ // Based on the packet type, determine whether to extract addresses
+ TBool dest = EFalse;
+ TBool src = EFalse;
+ switch (type)
+ {
+ case EBnepGeneralEthernet:
+ // General ethernet -- both source and destination present
+ LOG(_L8("Type = EBnepGeneralEthernet"));
+ SetContents(EDataFrame);
+ dest = ETrue;
+ src = ETrue;
+ break;
+
+ case EBnepControl:
+ // Control -- no addresses present (or any data)
+ LOG(_L8("Type = EBnepControl"));
+ break;
+
+ case EBnepCompressedEthernetDestOnly:
+ // Comressed destination only -- only destination present
+ LOG(_L8("Type = EBnepCompressedEthernetDestOnly"));
+ SetContents(EDataFrame);
+ dest = ETrue;
+ break;
+
+ case EBnepCompressedEthernetSourceOnly:
+ // Compressed source only -- only source present
+ LOG(_L8("Type = EBnepCompressedEthernetSourceOnly"));
+ SetContents(EDataFrame);
+ src = ETrue;
+ break;
+
+ case EBnepCompressedEthernet:
+ // Compressed -- no addresses present
+ LOG(_L8("Type = EBnepCompressedEthernet"));
+ SetContents(EDataFrame);
+ break;
+
+ default:
+ // Unknown packet type
+ LOG(_L8("RBnepFrame[%x]: Type = Unknown"));
+ User::Leave(KErrCorrupt);
+ break;
+ }
+
+ if (iPacketContents & EDataFrame) // Data present
+ {
+ if (dest)
+ {
+ TrimBTAddrL(aInboundChain, iDestAddr); // Address in packet, extract
+ LOG_BT(_L8("Extracted destination address %S"), iDestAddr);
+ }
+ else
+ {
+ iDestAddr = aLocalAddr; // No address in packet, assume.
+ LOG_BT(_L8("Defaulting destination to %S"), iDestAddr);
+ }
+ if (src)
+ {
+ TrimBTAddrL(aInboundChain, iSrcAddr); // Address in packet, extract
+ LOG_BT(_L8("Extracted source address %S"), iSrcAddr);
+ }
+ else
+ {
+ iSrcAddr = aRemoteAddr; // No address in packet, assume.
+ LOG_BT(_L8("Defaulting source address to %S"), iSrcAddr);
+ }
+ // Extract protocol
+ TrimUint16L(aInboundChain, iProtocol);
+ if(iProtocol == KQTag)
+ {
+ SetContents(EHas1Q);
+ }
+ LOG1(_L8("Extracted protocol %04x"), iProtocol);
+ }
+
+ ParseL(aInboundChain, type, ebit);
+
+ if(EBnepControl != type)
+ {
+ // Extract data from the incoming frame that might (depending on any filters
+ // need to be forwarded.
+ iFramePayload.Assign(aInboundChain);
+ LOG1(_L8("Extracted %d bytes of payload data"), iFramePayload.Length());
+ }
+ return type;
+ }
+
+void RBnepFrame::ParseEthernetFrameL (RMBufChain& aFrame)
+ {
+ /**
+ Parse an ethernet frame.
+ @param aFrame The ethernet frame received from the higher
+ networking layers.
+ @internalComponent
+ */
+ LOG_FUNC
+ Reset();
+ // Extract the source and destination addresses.
+ TrimBTAddrL(aFrame, iDestAddr);
+ TrimBTAddrL(aFrame, iSrcAddr);
+ LOG_BT(_L8("Extracted destination address %S"),iDestAddr);
+ LOG_BT(_L8("Extracted source address %S"),iSrcAddr);
+
+ // Pull out protocol, and, if present, 802.1Q data
+ TrimUint16L(aFrame, iProtocol);
+ LOG1(_L8("Extracted protocol (or type) %04x"), iProtocol);
+
+ if (iProtocol <= K802_3MaxLength)
+ {
+ // 'Protocol' field is overloaded. In 802.3, it actually contains the payload
+ // length. We can therefore use this field to detect an 802.3 format packet,
+ // and behave accordingly. Payload type numbers are guaranteed to be greater
+ // than available packet lengths (by design, in order to allow this distinction.)
+
+ // 802.3 requires additional headers to carry the required data. Most of this
+ // is essentially constant, especially as we only ever parse ethernet frames
+ // provided by the Symbian NIF.
+ //
+ // Expected values:
+ // LLC
+ // DSAP: aa
+ // SSAP: aa
+ // Control: 03
+ //
+ // SNAP
+ // OUI: 00 00 00
+ // Type: varies
+ //
+ // We can therefore trim the next six bytes of the supplied data, then extract
+ // the protocol type. If we were really keen, we could try to verify that the
+ // trimmed bytes are as expected.
+
+ aFrame.TrimStart(6);
+ TrimUint16L(aFrame, iProtocol);
+ }
+
+ if (KQTag == iProtocol)
+ {
+ SetContents(EHas1Q);
+
+ TBuf8<KNetworkProtocolTypeFieldLength> protocolBuf;
+ protocolBuf.SetMax();
+ if(aFrame.Length() < KIEEE802_1QTagFieldLength + KNetworkProtocolTypeFieldLength)
+ {
+ aFrame.Free();
+ User::Leave(KErrCorrupt);
+ }
+ aFrame.CopyOut(protocolBuf, KIEEE802_1QTagFieldLength);
+ iProtocol = static_cast<TUint16>((protocolBuf[0] << 8) + protocolBuf[1]);
+
+ LOG1(_L8("Found 802.1Q header, real protocol %04x"), iProtocol);
+ }
+
+ // Extract frame payload
+ SetContents(EDataFrame);
+ iFramePayload.Assign(aFrame);
+ LOG1(_L8("Extracted %d bytes of payload data"), iFramePayload.Length());
+ aFrame.Free();
+ }
+
+void RBnepFrame::Reset ()
+ {
+ /**
+ Reset a BNEP frame.
+ The object can be allowed to go out of scope only after a call to this
+ function. Note also that some data fields will still contain data after
+ this function returns, so the object should either be destroyed or
+ re-initialised based on another data frame.
+ @internalComponent
+ */
+ LOG_FUNC
+ // Reset contents flag
+ iPacketContents = 0;
+ // Free any payload data
+ iFramePayload.Free();
+ // Remove, free and delete all commands
+ while(!iCommandQueue.IsEmpty())
+ {
+ RBnepControl* element = iCommandQueue.First();
+ iCommandQueue.Remove(*element);
+ element->Free();
+ delete element;
+ }
+
+ // By default remote devices are not permitted to use the uplink
+ iUplinkAccessAllowedForBnepLink = EFalse;
+ }
+
+const TBTDevAddr& RBnepFrame::SrcAddr () const
+ {
+ LOG_FUNC
+ return iSrcAddr;
+ }
+
+void RBnepFrame::TrimBTAddrL (RMBufChain& aChain, TBTDevAddr& aAddr)
+ {
+ /**
+ Populate a Bluetooth address from the front of an MBufChain.
+ Extract the bluetooth address and remove it from the MBufChain.
+ @param aChain The MBufChain starting with a Bluetooth address.
+ @param aAddr The Bluetooth address to populate.
+ @internalComponent
+ */
+ LOG_FUNC
+ TPtr8 ptr = aAddr.Des();
+ if (aChain.Length() < KBTDevAddrSize)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ aChain.CopyOut(ptr);
+ aChain.TrimStart(KBTDevAddrSize);
+ }
+
+void RBnepFrame::TrimUint16L (RMBufChain& aChain, TUint16& aInt)
+ {
+ /**
+ Read a TUint16 from an MBufChain.
+ Reads and removes a TUint16 from the front of an MBufChain.
+ @param aChain The MBufChain starting with a TUint16.
+ @param aInt The TUint16 to populate.
+ @internalComponent
+ */
+ LOG_FUNC
+ if (aChain.Length() < static_cast<TInt>(sizeof(TUint16)))
+ {
+ User::Leave(KErrCorrupt);
+ }
+ TBuf8<sizeof(TUint16)> buf;
+ buf.SetLength(sizeof(TUint16));
+ aChain.CopyOut(buf);
+ // To handle endian issues, copy int out bytewise
+ aInt = BigEndian::Get16(buf.Ptr());
+ aChain.TrimStart(sizeof(TUint16));
+ }
+
+void RBnepFrame::ParseL(RMBufChain& aInboundChain, TBnepPacketType aType, TBool aExt)
+ {
+ /**
+ This method does all the donkey work sorting out the controls and possible extensions on the packet.
+ @param aInboundChain the rest of the packet
+ @param aType the calling method needs to know the packet type when it calls this method
+ @param aExt the calling method needs to know about the existence of extensions when it calls this method.
+ @internalComponent
+ */
+ LOG_FUNC
+ TInt offset = 0;
+ TInt length =0;
+
+ if(aType == EBnepControl)
+ {
+ LOG(_L8("A control"));
+ if(aExt)
+ {
+ LOG(_L8("With extensions"));
+ // This is a control packet with extensions.
+ // We're going to have to apply a little bit of intelligence to this one,
+ // because the spec is a bit unhelpful here (like - how long is the
+ // control part of the message supposed to be BEFORE we start
+ // pulling out the extension headers?)
+ TUint8 uuidSize;
+ TUint16 maListLength;
+ TUint16 ntListLength;
+ TBnepControlType type = static_cast<TBnepControlType>(aInboundChain.First()->Ptr()[0]);
+ LOG1(_L8("TBnepControlType = 0x%02x"), type);
+ switch (type)
+ {
+ case EBnepControlCommandNotUnderstood:
+ LOG(_L8("EBnepControlCommandNotUnderstood"));
+ length = 2*sizeof(TUint8); // Control type byte + 1 byte response message
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepSetupConnectionRequestMessage:
+ LOG(_L8("EBnepSetupConnectionRequestMessage"));
+ uuidSize = aInboundChain.First()->Ptr()[1];
+ length = 2*sizeof(TUint8) + 2*uuidSize; // Control type byte + UUIDsize byte + 2 UUIDs
+ // Note, this NOT where we check that UUIDSize is within bounds. That is done later.
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepSetupConnectionResponseMessage:
+ LOG(_L8("EBnepSetupConnectionResponseMessage"));
+ length = sizeof(TUint8) + sizeof(TUint16); // Control type byte + 2 byte response message
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepFilterNetTypeSetMsg:
+ LOG(_L8("EBnepFilterNetTypeSetMsg"));
+ ntListLength = BigEndian::Get16(aInboundChain.First()->Ptr() + 1);
+ length = sizeof(TUint8) + sizeof(TUint16) + ntListLength; // control type byte + length word + list of filters
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepFilterNetTypeResponse:
+ LOG(_L8("EBnepFilterNetTypeResponse"));
+ length = sizeof(TUint8) + sizeof(TUint16); // Control type byte + 2 byte response message
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepFilterMultiAddrSetMsg:
+ LOG(_L8("EBnepFilterMultiAddrSetMsg"));
+ maListLength = BigEndian::Get16(aInboundChain.First()->Ptr() + 1);
+ length = sizeof(TUint8) + sizeof(TUint16) + maListLength; // control type byte + length word + list of filters
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ case EBnepFilterMultiAddrResponseMsg:
+ LOG(_L8("EBnepFilterMultiAddrResponseMsg"));
+ length = sizeof(TUint8) + sizeof(TUint16); // Control type byte + 2 byte response message
+ ExtractControlL(aInboundChain, length);
+ break;
+
+ default: // We don't really want to execute this bit of code ever.
+ LOG(_L8("Unknown control type - leaving!"));
+ User::Leave(KErrCorrupt);
+ }
+ }
+ else
+ {
+ // This one's quite simple because we know that the packet contains a
+ // control and only a control. So the format is pretty simple to stash
+ // as a command for future processing.
+ LOG(_L8("Without extensions"));
+ length = aInboundChain.Length();
+ ExtractControlL(aInboundChain, length);
+ }
+ }
+
+ if(aExt)
+ {
+ // Extension headers are present.
+ LOG(_L8("Extensions embedded"));
+
+ offset = ParseExtensionL(aInboundChain);
+ }
+
+ // If the packet includes IEEE 802.1Q info then the real protocol field must be
+ // extracted and stored for filtering purposes.
+ if(Includes(EHas1Q))
+ {
+ offset+=KIEEE802_1QTagFieldLength;
+ // Store the extra protcol information.
+ if((offset + KNetworkProtocolTypeFieldLength) > aInboundChain.Length())
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ TBuf8<KNetworkProtocolTypeFieldLength> protocolBuf;
+ protocolBuf.SetMax();
+
+ aInboundChain.CopyOut(protocolBuf, offset);
+
+ iProtocol = static_cast<TUint16>((protocolBuf[0] << 8) + protocolBuf[1]);
+ }
+ }
+
+TInt RBnepFrame::ParseExtensionL(RMBufChain& aInboundChain)
+ {
+ /**
+ Helper method to extract control extension headers from a packet.
+ Non-Control extension headers will remain in the inbound chain
+ @param aInboundChain the rest of the packet
+ @internalComponent
+ */
+ LOG_FUNC
+ TUint16 offset = 0;
+ TUint16 lastExtensionHeaderOffset = 0;
+ TBool ebit = ETrue;
+ TBool removeExtensions = EFalse;
+
+ TBuf8<KExtensionHeaderHeaderBytes> buf;
+ buf.SetMax();
+
+ // Used to verify that the extensions are in assending order.
+ TBnepExtensionType lastExtensionType = EBnepExtensionControl;
+
+ while(ebit)
+ {
+ // Extension headers are 2 bytes long.
+ if((offset + KExtensionHeaderHeaderBytes) > aInboundChain.Length())
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ aInboundChain.CopyOut(buf, offset);
+
+ // Extract the extension header type and e-bit.
+ TBnepExtensionType type = static_cast<TBnepExtensionType>(buf[0]);
+ ebit = type & KEBit;
+ type = static_cast<TBnepExtensionType>(type & (~KEBit));
+
+ if(type < lastExtensionType)
+ {
+ // Extensions are not in assending order. Remove all subsequent
+ // extensions from the packet.
+ if(!removeExtensions)
+ {
+ // The previous extension header bit must be set to zero
+ removeExtensions = ETrue;
+ TBuf8<KSizeOfBnepExtensionType> exTypeBuf;
+ exTypeBuf.SetMax();
+ aInboundChain.CopyOut(exTypeBuf, lastExtensionHeaderOffset);
+ exTypeBuf[0] &= ~KEBit;
+ aInboundChain.CopyIn(exTypeBuf, lastExtensionHeaderOffset);
+ }
+ }
+
+ lastExtensionType = type;
+
+ // Extract the length of this extension header
+ TUint8 length = buf[1];
+
+ LOG4(_L8("Found extension header, type %02x, ebit %02x, length %d, offset %d"),
+ type, ebit, length, offset);
+
+ if((length + KExtensionHeaderHeaderBytes) > (aInboundChain.Length() - offset))
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ if(type == EBnepExtensionControl && !removeExtensions)
+ {
+ // Remove the BNEP extension control header (i.e., [ebit]0x00, Length).
+ aInboundChain.TrimStart(KExtensionHeaderHeaderBytes);
+
+ // Control extention headers need to be extracted.
+ ExtractControlL(aInboundChain, length);
+ }
+ else
+ {
+ if(!removeExtensions)
+ {
+ // If the extension has not been removed adjust the offset.
+ lastExtensionHeaderOffset = offset;
+ offset += (length + KExtensionHeaderHeaderBytes);
+
+ // Note that an extension header is present in the payload.
+ SetContents(EExtensionHeaders);
+ }
+ else
+ {
+ // Remove the extension.
+ RMBufChain tempBuf;
+ // Split the buffer so that aInboundChain includes everything before
+ // the extension to be removed and tempBuf includes everything after
+ // including the extension to be removed.
+ aInboundChain.SplitL(offset, tempBuf);
+
+ // Remove the extension from tempBuf.
+ tempBuf.TrimStart(length + KExtensionHeaderHeaderBytes);
+
+ // Re-join the two buffers
+ aInboundChain.Append(tempBuf);
+ }
+ }
+ }
+
+ return offset;
+ }
+
+void RBnepFrame::ExtractControlL(RMBufChain& aInboundChain, TInt aLength)
+ {
+ /**
+ Helper method to extract the control portion of a packet.
+ @param aInboundChain the rest of the packet.
+ @param aLength the size of the control portion to be extracted.
+ @internalComponent
+ */
+ LOG_FUNC
+ LOG1(_L8("Extraction length = %d bytes"),aLength);
+ if(0 == aLength)
+ {
+ LOG(_L8("Zero length buffer - leaving!"));
+ User::Leave(KErrArgument);
+ }
+ if(aLength > aInboundChain.Length())
+ {
+ LOG(_L8("Corrupted buffer - leaving!"));
+ User::Leave(KErrCorrupt);
+ }
+ RBnepControl* command = new(ELeave) RBnepControl();
+ CleanupStack::PushL(TCleanupItem(doResetControl, command));
+ // MBuf SplitL is a bit awkward here, as it splits off the end of the chain
+ // into the supplied parameter. So move the MBuf data to all be with the
+ // command MBufChain, then split back into the original MBufChain.
+ command->Assign(aInboundChain);
+ command->SplitL(aLength,aInboundChain);
+ CleanupStack::Pop(command);
+ LOG1(_L8("Storing new command 0x%08x in queue"),command);
+ iCommandQueue.AddLast(*command);
+ SetContents(EControl);
+ }
+
+void RBnepFrame::ExecuteControl (MLinkManager& aController)
+ {
+ /**
+ Helper method that pushes the controls in the queue up to the controller for handling
+ and response.
+ @param aController The controller object to pass the control messages to.
+ @internalComponent
+ */
+ LOG_FUNC
+ while(!iCommandQueue.IsEmpty() &&
+ !aController.AwaitingResponse())
+ {
+ RBnepControl* element = iCommandQueue.First();
+ iCommandQueue.Remove(*element);
+ LOG(_L8("Passing command up to controller"));
+ // The controller will now own the control and will become responsible for its memory management
+ aController.Execute(element);
+ }
+
+ // If we reached the end, then show that the packet no longer contains control extensions.
+ if (iCommandQueue.IsEmpty())
+ {
+ iPacketContents &= ~EControl;
+ }
+ }
+
+
+TInt RBnepFrame::PayloadLength() const
+ {
+ return iFramePayload.Length();
+ }
+
+void RBnepFrame::SetUplinkAccessAllowedForBnepLink(TBool aUplinkAccessAllowedForBnepLink)
+ {
+ iUplinkAccessAllowedForBnepLink = aUplinkAccessAllowedForBnepLink;
+ }