diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/bnep/RBnepFrame.cpp --- /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 +#include +#include +#include + +#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(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(((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 pkgFrameType(frameType); + aChain.CopyIn(pkgFrameType,RBnepControl::KControlTypeOffset); + if(ebit) // We have at least one extension + { + TSglQueIter iter(iCommandQueue); + iter.SetToFirst(); + RBnepControl* element; + while ((element = iter++), element) + { + TPckgBuf aLength(static_cast(element->Length())); + element->PrependL(sizeof(TInt8)); + element->CopyIn(aLength); + + element->PrependL(sizeof(TUint8)); + if(iCommandQueue.IsLast(element)) + { + TPckgBuf extFrameType(static_cast(EBnepExtensionControl)); + element->CopyIn(extFrameType); + } + else + { + // The extension bit must be set. + TPckgBuf extExtFrameType(static_cast(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 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 protocolBuf; + protocolBuf.SetMax(); + + if (Includes(EHas1Q)) + { + BigEndian::Put16(&protocolBuf[0], static_cast(KQTag)); + } + else + { + BigEndian::Put16(&protocolBuf[0], static_cast(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 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 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 protocolBuf; + protocolBuf.SetMax(); + tempFrame.PrependL(KNetworkProtocolTypeFieldLength); + BigEndian::Put16(&protocolBuf[0], static_cast(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(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(aInboundChain.First()->Ptr()[0]); + aInboundChain.TrimStart(sizeof(TUint8)); + // Test the extension bit + TBool ebit = type & KEBit; + // Discard the extension bit + type = static_cast(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 protocolBuf; + protocolBuf.SetMax(); + if(aFrame.Length() < KIEEE802_1QTagFieldLength + KNetworkProtocolTypeFieldLength) + { + aFrame.Free(); + User::Leave(KErrCorrupt); + } + aFrame.CopyOut(protocolBuf, KIEEE802_1QTagFieldLength); + iProtocol = static_cast((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(sizeof(TUint16))) + { + User::Leave(KErrCorrupt); + } + TBuf8 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(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 protocolBuf; + protocolBuf.SetMax(); + + aInboundChain.CopyOut(protocolBuf, offset); + + iProtocol = static_cast((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 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(buf[0]); + ebit = type & KEBit; + type = static_cast(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 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; + }