diff --git a/AUTHORS b/AUTHORS index bce5553bf..5e7291b4e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -81,6 +81,7 @@ Marco Miozzo (mmiozzo@cttc.es) Faker Moatamri (faker.moatamri@inria.fr) Edvin Močibob Mike Moreton (mjvm_ns@hotmail.com) +Michele Muccio Sidharth Nabar (snabar@uw.edu) Hemanth Narra (hemanth@ittc.ku.edu) Andreas Nilsson diff --git a/CHANGES.html b/CHANGES.html index 73fc05c40..2f7a97430 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -80,6 +80,15 @@ us a note on ns-developers mailing list.

their simulation program. The imlpementation previously provided by the EpcHelper class has been moved to the new derived class PointToPointEpcHelper. +
  • New SixLowPanNetDevice class providing a shim between + IPv6 and real NetDevices. The new module implements 6LoWPAN: + "Transmission of IPv6 Packets over IEEE 802.15.4 Networks" (see + RFC 4944 and + RFC 6262), + resulting in a heavy header compression for IPv6 packets. + The module is intended to be used on 802.15.4 NetDevices, but + it can be used over other NetDevices. See the manual for + further discussion.
  • Changes to build system:

    diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 30c8b8f06..e19a42eea 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -21,6 +21,12 @@ Supported platforms New user-visible features ------------------------- +- new SixLowPanNetDevice model, headers and associated helpers. The + SixLowPanNetDevice is able to act as a shim between IPv6 and a NetDevice, + compressing IPv6 headers according to RFCs 4944 and 6262. + The SixLowPanNetDevice is meant to be used over 802.15.4 NetDevices, + but it can be used on other NetDevices as well (see the manual for full + details). - A new wifi extension for vehicular simulation support is available in src/wave directory. The current code represents an interim capability to realize an diff --git a/doc/models/Makefile b/doc/models/Makefile index 4b043b850..0e6423ef5 100644 --- a/doc/models/Makefile +++ b/doc/models/Makefile @@ -79,6 +79,7 @@ SOURCES = \ $(SRC)/netanim/doc/animation.rst \ $(SRC)/flow-monitor/doc/flow-monitor.rst \ $(SRC)/wave/doc/wave.rst \ + $(SRC)/sixlowpan/doc/sixlowpan.rst \ # list all model library figure files that need to be copied to # $SOURCETEMP/figures. For each figure to be included in all diff --git a/src/internet/model/udp-header.cc b/src/internet/model/udp-header.cc index 01eacc7ca..17b6b6486 100644 --- a/src/internet/model/udp-header.cc +++ b/src/internet/model/udp-header.cc @@ -33,7 +33,8 @@ NS_OBJECT_ENSURE_REGISTERED (UdpHeader) UdpHeader::UdpHeader () : m_sourcePort (0xfffd), m_destinationPort (0xfffd), - m_payloadSize (0xfffd), + m_payloadSize (0), + m_checksum (0), m_calcChecksum (false), m_goodChecksum (true) { @@ -108,7 +109,7 @@ UdpHeader::CalculateHeaderChecksum (uint16_t size) const WriteTo (it, m_source); WriteTo (it, m_destination); - if (Ipv4Address::IsMatchingType(m_source)) + if (Ipv4Address::IsMatchingType (m_source)) { it.WriteU8 (0); /* protocol */ it.WriteU8 (m_protocol); /* protocol */ @@ -116,7 +117,7 @@ UdpHeader::CalculateHeaderChecksum (uint16_t size) const it.WriteU8 (size & 0xff); /* length */ hdrSize = 12; } - else if (Ipv6Address::IsMatchingType(m_source)) + else if (Ipv6Address::IsMatchingType (m_source)) { it.WriteU16 (0); it.WriteU8 (size >> 8); /* length */ @@ -138,6 +139,17 @@ UdpHeader::IsChecksumOk (void) const return m_goodChecksum; } +void +UdpHeader::ForceChecksum (uint16_t checksum) +{ + m_checksum = checksum; +} + +void +UdpHeader::ForcePayloadSize (uint16_t payloadSize) +{ + m_payloadSize = payloadSize; +} TypeId UdpHeader::GetTypeId (void) @@ -175,18 +187,33 @@ UdpHeader::Serialize (Buffer::Iterator start) const i.WriteHtonU16 (m_sourcePort); i.WriteHtonU16 (m_destinationPort); - i.WriteHtonU16 (start.GetSize ()); - i.WriteU16 (0); - - if (m_calcChecksum) + if (m_payloadSize == 0) { - uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); - i = start; - uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum); + i.WriteHtonU16 (start.GetSize ()); + } + else + { + i.WriteHtonU16 (m_payloadSize); + } - i = start; - i.Next (6); - i.WriteU16 (checksum); + if ( m_checksum == 0) + { + i.WriteU16 (0); + + if (m_calcChecksum) + { + uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); + i = start; + uint16_t checksum = i.CalculateIpChecksum (start.GetSize (), headerChecksum); + + i = start; + i.Next (6); + i.WriteU16 (checksum); + } + } + else + { + i.WriteU16 (m_checksum); } } uint32_t @@ -196,9 +223,9 @@ UdpHeader::Deserialize (Buffer::Iterator start) m_sourcePort = i.ReadNtohU16 (); m_destinationPort = i.ReadNtohU16 (); m_payloadSize = i.ReadNtohU16 () - GetSerializedSize (); - i.Next (2); + m_checksum = i.ReadU16 (); - if(m_calcChecksum) + if (m_calcChecksum) { uint16_t headerChecksum = CalculateHeaderChecksum (start.GetSize ()); i = start; @@ -210,5 +237,10 @@ UdpHeader::Deserialize (Buffer::Iterator start) return GetSerializedSize (); } +uint16_t +UdpHeader::GetChecksum () +{ + return m_checksum; +} } // namespace ns3 diff --git a/src/internet/model/udp-header.h b/src/internet/model/udp-header.h index a5854b136..3e131dc40 100644 --- a/src/internet/model/udp-header.h +++ b/src/internet/model/udp-header.h @@ -131,6 +131,41 @@ public: */ bool IsChecksumOk (void) const; + /** + * \brief Force the UDP checksum to a given value. + * + * This might be useful for test purposes or to + * restore the UDP checksum when the UDP header + * has been compressed (e.g., in 6LoWPAN). + * Note that, normally, the header checksum is + * calculated on the fly when the packet is + * serialized. + * + * When this option is used, the UDP checksum is written in + * the header, regardless of the global ChecksumEnabled option. + * + * \note The checksum value must be a big endian number. + * + * \param checksum the checksum to use (big endian). + */ + void ForceChecksum (uint16_t checksum); + + /** + * \brief Force the UDP payload length to a given value. + * + * This might be useful when forging a packet for test + * purposes. + * + * \param payloadSize the payload length to use. + */ + void ForcePayloadSize (uint16_t payloadSize); + + /** + * \brief Return the checksum (only known after a Deserialize) + * \return The checksum for this UdpHeader + */ + uint16_t GetChecksum (); + private: /** * \brief Calculate the header checksum @@ -145,6 +180,7 @@ private: Address m_source; //!< Source IP address Address m_destination; //!< Destination IP address uint8_t m_protocol; //!< Protocol number + uint16_t m_checksum; //!< Forced Checksum value bool m_calcChecksum; //!< Flag to calculate checksum bool m_goodChecksum; //!< Flag to indicate that checksum is correct }; diff --git a/src/sixlowpan/doc/sixlowpan.rst b/src/sixlowpan/doc/sixlowpan.rst new file mode 100644 index 000000000..033cb0a66 --- /dev/null +++ b/src/sixlowpan/doc/sixlowpan.rst @@ -0,0 +1,147 @@ +PageBreak + +Transmission of IPv6 Packets over IEEE 802.15.4 Networks (6LoWPAN) +------------------------------------------------------------------ + +This chapter describes the implementation of |ns3| model for the +compression of IPv6 packets over IEEE 802.15.4-Based Networks +as specified by RFC 4944 and RFC 6262. + +Model Description +***************** + +The source code for the sixlowpan module lives in the directory ``src/sixlowpan``. + +Design +====== + +The model design does not follow strictly the standard from an architectural +standpoint, as it does extend it beyond the original scope by supporting also +other kinds of networks. + +Other than that, the module strictly follows RFCs 4944 and 6262, with the +following exceptions: +* MESH and LOWPAN_BC0 dispatch types are not supported +* HC2 encoding is not supported +* IPHC's SAC and DAC are not supported + +The MESH and LOWPAN_BC0 are not supported as they do apply only to mesh-under +architecture, which is not one of the goals of the module development. + +The HC2 encoding is not supported, as it has been superseded by IPHC and NHC +compression type (RFC 6262). + +IPHC SAC and DAC are not yet supported, as they do require RFC 6775 for full +compliance. It is planned to support them in the future. + +NetDevice +######### + +The whole module is developed as a transparent NetDevice, which can act as a +proxy between IPv6 and any NetDevice (the module has been successfully tested +with PointToPointNedevice, CsmaNetDevice and LrWpanNetDevice). + +For this reason, the module implements a virtual NetDevice, and all the calls are passed +without modifications to the underlying NetDevice. The only important difference is in +GetMtu behaviour. It will always return *at least* 1280 bytes, as is the minumum IPv6 MTU. + +The module does provide some attributes and some tracesources. +The attributes are: +* Rfc6282 (boolean, default true), used to activate HC1 (RFC 4944) or IPHC (RFC 6282) compression. +* OmitUdpChecksum (boolean, default true), used to activate UDP checksum compression in IPHC. +* FragmentReassemblyListSize (integer, default 0), indicating the number of packets that can be reassembled at the same time. If the limit is reached, the oldest packet is discarded. Zero means infinite. +* FragmentExpirationTimeout (Time, default 60 seconds), being the timeout to wait for further fragments before discarding a partial packet. +* ForceEtherType (boolean, default false), and +* EtherType (unsigned 16 bits integer, default 0xFFFF), to force a particular L2 EtherType. + +The last two attributes are needed to use the module with a NetDevice other than 802.15.4, as +neither IANA or IEEE did reserve an EtherType for 6LoWPAN. As a consequence there might be a +conflict with the L2 multiplexer/demultiplexer which is based on EtherType. The default +value is 0xFFFF, which is reserved by IEEE. +The default module behaviour is to not change the EtherType, however this would not work with +any NetDevice actually understanding and using the EtherType. + +Note that the `ForceEtherType` parameter have also a direct effect on the MAC address kind the +module is expecting to handle: +* ForceEtherType true: Mac48Address (Ethernet, WiFi, etc.). +* ForceEtherType false: Mac16Address or Mac64Address (IEEE 802.15.4). + +Note that using 6LoWPAN over any NetDevice other than 802.15.4 will produce valid .pcap files, +but they will not be correctly dissected by Wireshark. +The reason lies on the fact that 6LoWPAN was really meant to be used only over 802.15.4, so +Wireshark dissectors will not even try to decode 6LoWPAN headers on top of protocols other than +802.15.4. + +The Trace sources are: +* Tx - exposing packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index. +* Rx - exposing packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index. +* Drop - exposing DropReason, packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index. + +The Tx and Rx traces are called as soon as a packet is received or sent. The Drop trace is +invoked when a packet (or a fragment) is discarded. + + +Scope and Limitations +===================== + +Future versions of this module will support RFC 6775, however no timeframe is guaranteed. + +Using 6LoWPAN with IPv4 (or other L3 protocols) +############################################### + +As the name implies, 6LoWPAN can handle only IPv6 packets. Any other protocol will be discarded. +Moreover, 6LoWPAN assumes that the network is uniform, as is all the devices connected by the +same same channel are using 6LoWPAN. Mixed environments are not supported by the standard. +The reason is simple: 802.15.4 frame doesn't have a "protocol" field. As a consequence, +there is no demultiplexing at MAC layer and the protocol carried by L2 frames must be known +in advance. + +In the |ns3| implementation it is possible, but not advisable, to violate this requirement +if the underlying NetDevice is capable of discriminating different protocols. As an example, +CsmaNetDevice can carry IPv4 and 6LoWPAN at the same time. However, this configuration has +not been tested. + +References +========== + +* RFC 4944, "Transmission of IPv6 Packets over IEEE 802.15.4 Networks". +* RFC 6282, "Compression Format for IPv6 Datagrams over IEEE 802.15.4-Based Networks". +* http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xml +* http://standards.ieee.org/develop/regauth/ethertype/eth.txt + +Usage +***** + +Enabling sixlowpan +================== + +Add ``sixlowpan`` to the list of modules built with |ns3|. + +Helper +====== + +The helper is patterned after other device helpers. + +Examples +======== + +The following example can be found in ``src/sixlowpan/examples/``: + +* ``example-sixlowpan.cc``: A simple example showing end-to-end data transfer. + +In particular, the example enables a very simplified end-to-end data +transfer scenario, with a CSMA network forced to carry 6LoWPAN compressed packets. + + +Tests +===== + +The test provided checks the connection between two UDP clients and the correctness of the received packets. + +Validation +********** + +The model has been validated against WireShark, checking whatever the packets are correctly +interpreted and validated. + + diff --git a/src/sixlowpan/examples/example-sixlowpan.cc b/src/sixlowpan/examples/example-sixlowpan.cc new file mode 100644 index 000000000..fd2935502 --- /dev/null +++ b/src/sixlowpan/examples/example-sixlowpan.cc @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ + + +// Network topology +// +// n0 n1 +// +---------+ +--------+ +// | UDP | r | UDP | +// +---------+ +---------+--------+ +--------+ +// | IPv6 | | IPv6 | IPv6 | | IPv6 | +// +---------+ +---------+ | | | +// | 6LoWPAN | | 6LoWPAN | | | | +// +---------+ +---------+--------+ +--------+ +// | CSMA | | CSMA | CSMA | | CSMA | +// +---------+ +---------+--------+ +--------+ +// | | | | +// ================ ================= +// +// - Tracing of queues and packet receptions to file "example-sixlowpan.tr" +// Note that the Pcap packet dissection will not be very meaningful. +// See the module's documentation for a discussion about this. + +#include +#include "ns3/core-module.h" +#include "ns3/internet-module.h" +#include "ns3/csma-module.h" +#include "ns3/applications-module.h" +#include "ns3/ipv6-static-routing-helper.h" + +#include "ns3/ipv6-routing-table-entry.h" +#include "ns3/sixlowpan-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("ExampleSixlowpan") + ; + +int main (int argc, char** argv) +{ + bool verbose = false; + + CommandLine cmd; + cmd.AddValue ("verbose", "turn on some relevant log components", verbose); + cmd.Parse (argc, argv); + + if (verbose) + { + LogComponentEnable ("SixLowPanNetDevice", LOG_LEVEL_ALL); + LogComponentEnable ("Ping6Application", LOG_LEVEL_ALL); + } + + Packet::EnablePrinting (); + Packet::EnableChecking (); + + NS_LOG_INFO ("Create nodes."); + Ptr n0 = CreateObject (); + Ptr r = CreateObject (); + Ptr n1 = CreateObject (); + + + NodeContainer net1 (n0, r); + NodeContainer net2 (r, n1); + NodeContainer all (n0, r, n1); + + NS_LOG_INFO ("Create IPv6 Internet Stack"); + InternetStackHelper internetv6; + internetv6.Install (all); + + NS_LOG_INFO ("Create channels."); + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + NetDeviceContainer d2 = csma.Install (net2); + csma.SetDeviceAttribute ("Mtu", UintegerValue (150)); + NetDeviceContainer d1 = csma.Install (net1); + + SixLowPanHelper sixlowpan; + sixlowpan.SetDeviceAttribute ("ForceEtherType", BooleanValue (true) ); + NetDeviceContainer six1 = sixlowpan.Install (d1); + + NS_LOG_INFO ("Create networks and assign IPv6 Addresses."); + Ipv6AddressHelper ipv6; + ipv6.SetBase (Ipv6Address ("2001:1::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer i1 = ipv6.Assign (six1); + i1.SetForwarding (1, true); + i1.SetDefaultRouteInAllNodes (1); + + ipv6.SetBase (Ipv6Address ("2001:2::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer i2 = ipv6.Assign (d2); + i2.SetForwarding (0, true); + i2.SetDefaultRouteInAllNodes (0); + + /* Create a Ping6 application to send ICMPv6 echo request from n0 to n1 via r */ + uint32_t packetSize = 200; + uint32_t maxPacketCount = 50; + Time interPacketInterval = Seconds (1.); + Ping6Helper ping6; + + ping6.SetLocal (i1.GetAddress (0, 1)); + ping6.SetRemote (i2.GetAddress (1, 1)); + + ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + ping6.SetAttribute ("Interval", TimeValue (interPacketInterval)); + ping6.SetAttribute ("PacketSize", UintegerValue (packetSize)); + ApplicationContainer apps = ping6.Install (net1.Get (0)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (15.0)); + + + AsciiTraceHelper ascii; + csma.EnableAsciiAll (ascii.CreateFileStream ("example-sixlowpan.tr")); + csma.EnablePcapAll (std::string ("example-sixlowpan"), true); + + Simulator::Stop (Seconds (100)); + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} + diff --git a/src/sixlowpan/examples/wscript b/src/sixlowpan/examples/wscript new file mode 100644 index 000000000..d7951f94e --- /dev/null +++ b/src/sixlowpan/examples/wscript @@ -0,0 +1,9 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + if not bld.env['ENABLE_EXAMPLES']: + return; + + obj = bld.create_ns3_program('example-sixlowpan', + ['network', 'sixlowpan', 'internet', 'csma']) + obj.source = 'example-sixlowpan.cc' diff --git a/src/sixlowpan/helper/sixlowpan-helper.cc b/src/sixlowpan/helper/sixlowpan-helper.cc new file mode 100644 index 000000000..27fb2c95a --- /dev/null +++ b/src/sixlowpan/helper/sixlowpan-helper.cc @@ -0,0 +1,83 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ + +#include "sixlowpan-helper.h" +#include "ns3/log.h" +#include "ns3/sixlowpan-net-device.h" +#include "ns3/node.h" +#include "ns3/names.h" + +NS_LOG_COMPONENT_DEFINE ("SixLowPanHelper") + ; + +namespace ns3 { + +SixLowPanHelper::SixLowPanHelper () +{ + NS_LOG_FUNCTION (this); + m_deviceFactory.SetTypeId ("ns3::SixLowPanNetDevice"); +} + +void SixLowPanHelper::SetDeviceAttribute (std::string n1, + const AttributeValue &v1) +{ + NS_LOG_FUNCTION (this); + m_deviceFactory.Set (n1, v1); +} + +NetDeviceContainer SixLowPanHelper::Install (const NetDeviceContainer c) +{ + NS_LOG_FUNCTION (this); + + NetDeviceContainer devs; + + for (uint32_t i = 0; i < c.GetN (); ++i) + { + Ptr device = c.Get (i); + NS_ASSERT_MSG (device != 0, "No NetDevice found in the node " << int(i) ); + + Ptr node = device->GetNode (); + NS_LOG_LOGIC ("**** Install 6LoWPAN on node " << node->GetId ()); + + Ptr dev = m_deviceFactory.Create (); + devs.Add (dev); + node->AddDevice (dev); + dev->SetNetDevice (device); + } + return devs; +} + +int64_t SixLowPanHelper::AssignStreams (NetDeviceContainer c, int64_t stream) +{ + int64_t currentStream = stream; + Ptr netDevice; + for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + netDevice = (*i); + Ptr dev = DynamicCast (netDevice); + if (dev) + { + currentStream += dev->AssignStreams (currentStream); + } + } + return (currentStream - stream); +} + +} // namespace ns3 diff --git a/src/sixlowpan/helper/sixlowpan-helper.h b/src/sixlowpan/helper/sixlowpan-helper.h new file mode 100644 index 000000000..c38b26c7b --- /dev/null +++ b/src/sixlowpan/helper/sixlowpan-helper.h @@ -0,0 +1,102 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ + +#ifndef SIXLOWPAN_HELPER_H +#define SIXLOWPAN_HELPER_H + +#include "ns3/net-device-container.h" +#include "ns3/object-factory.h" +#include + +namespace ns3 { + +class Node; +class AttributeValue; + +/** + * \ingroup sixlowpan + * + * \brief Setup a sixlowpan stack to be used as a shim between IPv6 and a generic NetDevice. + */ +class SixLowPanHelper +{ +public: + /* + * Construct a SixlowpanHelper + */ + SixLowPanHelper (); + /** + * Set an attribute on each ns3::SixlowpanNetDevice created by + * SixlowpanHelper::Install. + * + * \param n1 the name of the attribute to set + * \param v1 the value of the attribute to set + */ + void SetDeviceAttribute (std::string n1, + const AttributeValue &v1); + + /** + * \brief Install the SixLoWPAN stack on top of an existing NetDevice. + * + * This function requires a set of properly configured NetDevices + * passed in as the parameter "c". The new NetDevices will have to + * be used instead of the original ones. In this way these + * SixLoWPAN devices will behave as shims between the NetDevices + * passed in and IPv6. + * + * Note that only IPv6 (and related protocols, such as ICMPv6) can + * be transmitted over a 6LoWPAN interface. + * Any other protocol (e.g., IPv4) will be discarded by 6LoWPAN. + * + * Other protocols (e.g., IPv4) could be used on the original NetDevices + * with some limitations. + * See the manual for a complete discussion. + * + * \note IPv6 stack must be installed \a after SixLoWPAN, + * using the SixLoWPAN NetDevices. See the example in the + * examples directory. + * + * + * \param c the NetDevice container + * \return a container with the newly created SixLowPanNetDevices + */ + NetDeviceContainer Install (NetDeviceContainer c); + + /** + * Assign a fixed random variable stream number to the random variables + * used by this model. Return the number of streams (possibly zero) that + * have been assigned. The Install() method should have previously been + * called by the user. + * + * \param c NetDeviceContainer of the set of net devices for which the + * SixLowPanNetDevice should be modified to use a fixed stream + * \param stream first stream index to use + * \return the number of stream indices assigned by this helper + */ + int64_t AssignStreams (NetDeviceContainer c, int64_t stream); + +private: + ObjectFactory m_deviceFactory; //!< Object factory +}; + +} // namespace ns3 + + +#endif /* SIXLOWPAN_HELPER_H */ diff --git a/src/sixlowpan/model/sixlowpan-header.cc b/src/sixlowpan/model/sixlowpan-header.cc new file mode 100644 index 000000000..222c8ff45 --- /dev/null +++ b/src/sixlowpan/model/sixlowpan-header.cc @@ -0,0 +1,1747 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + * Michele Muccio + */ + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/abort.h" +#include "ns3/address-utils.h" +#include "sixlowpan-header.h" + + +namespace ns3 { + +/* + * SixLowPanDispatch + */ + + +SixLowPanDispatch::SixLowPanDispatch () +{ +} + + +SixLowPanDispatch::Dispatch_e +SixLowPanDispatch::GetDispatchType (uint8_t dispatch) +{ + if (dispatch <= LOWPAN_NALP_N) + { + return LOWPAN_NALP; + } + else if (dispatch == LOWPAN_NOTCOMPRESSED) + { + return LOWPAN_NOTCOMPRESSED; + } + else if (dispatch == LOWPAN_HC1) + { + return LOWPAN_HC1; + } + else if (dispatch == LOWPAN_BC0) + { + return LOWPAN_BC0; + } + else if ((dispatch >= LOWPAN_IPHC) && (dispatch <= LOWPAN_IPHC_N)) + { + return LOWPAN_IPHC; + } + else if ((dispatch >= LOWPAN_MESH) && (dispatch <= LOWPAN_MESH_N)) + { + return LOWPAN_MESH; + } + else if ((dispatch >= LOWPAN_FRAG1) && (dispatch <= LOWPAN_FRAG1_N)) + { + return LOWPAN_FRAG1; + } + else if ((dispatch >= LOWPAN_FRAGN) && (dispatch <= LOWPAN_FRAGN_N)) + { + return LOWPAN_FRAGN; + } + return LOWPAN_UNSUPPORTED; +} + +SixLowPanDispatch::NhcDispatch_e +SixLowPanDispatch::GetNhcDispatchType (uint8_t dispatch) +{ + if ((dispatch >= LOWPAN_NHC) && (dispatch <= LOWPAN_NHC_N)) + { + return LOWPAN_NHC; + } + else if ((dispatch >= LOWPAN_UDPNHC) && (dispatch <= LOWPAN_UDPNHC_N)) + { + return LOWPAN_UDPNHC; + } + return LOWPAN_NHCUNSUPPORTED; +} + + +/* + * SixLowPanHc1 + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanHc1) + ; + +SixLowPanHc1::SixLowPanHc1 () + : m_hopLimit (0) +{ +} + +TypeId SixLowPanHc1::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanHc1").SetParent
    ().AddConstructor (); + return tid; +} + +TypeId SixLowPanHc1::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanHc1::Print (std::ostream & os) const +{ + uint8_t encoding; + encoding = m_srcCompression; + encoding <<= 2; + encoding |= m_dstCompression; + encoding <<= 1; + encoding |= m_tcflCompression; + encoding <<= 2; + encoding |= m_nextHeaderCompression; + encoding <<= 1; + encoding |= m_hc2HeaderPresent; + + os << "encoding " << int(encoding) << ", hopLimit " << int(m_hopLimit); +} + +uint32_t SixLowPanHc1::GetSerializedSize () const +{ + uint32_t serializedSize = 3; + + switch (m_srcCompression) + { + case HC1_PIII: + serializedSize += 16; + break; + case HC1_PIIC: + serializedSize += 8; + break; + case HC1_PCII: + serializedSize += 8; + break; + case HC1_PCIC: + break; + } + switch (m_dstCompression) + { + case HC1_PIII: + serializedSize += 16; + break; + case HC1_PIIC: + serializedSize += 8; + break; + case HC1_PCII: + serializedSize += 8; + break; + case HC1_PCIC: + break; + } + + if (m_tcflCompression == false ) + { + serializedSize += 4; + } + + if (m_nextHeaderCompression == HC1_NC ) + { + serializedSize++; + } + + return serializedSize; +} + +void SixLowPanHc1::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + uint8_t encoding; + encoding = m_srcCompression; + encoding <<= 2; + encoding |= m_dstCompression; + encoding <<= 1; + encoding |= m_tcflCompression; + encoding <<= 2; + encoding |= m_nextHeaderCompression; + encoding <<= 1; + encoding |= m_hc2HeaderPresent; + + i.WriteU8 (SixLowPanDispatch::LOWPAN_HC1); + i.WriteU8 (encoding); + i.WriteU8 (m_hopLimit); + switch (m_srcCompression) + { + case HC1_PIII: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_srcPrefix[j]); + } + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_srcInterface[j]); + } + break; + case HC1_PIIC: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_srcPrefix[j]); + } + break; + case HC1_PCII: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_srcInterface[j]); + } + break; + case HC1_PCIC: + break; + } + switch (m_dstCompression) + { + case HC1_PIII: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_dstPrefix[j]); + } + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_dstInterface[j]); + } + break; + case HC1_PIIC: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_dstPrefix[j]); + } + break; + case HC1_PCII: + for ( int j = 0; j < 8; j++ ) + { + i.WriteU8 (m_dstInterface[j]); + } + break; + case HC1_PCIC: + break; + } + + if ( m_tcflCompression == false ) + { + i.WriteU8 (m_trafficClass); + uint8_t temp[3]; + temp[0] = uint8_t (m_flowLabel & 0xff); + temp[1] = uint8_t ((m_flowLabel >> 8) & 0xff); + temp[2] = uint8_t ((m_flowLabel >> 16) & 0xff); + i.Write (temp, 3); + } + + if (m_nextHeaderCompression == HC1_NC ) + { + i.WriteU8 (m_nextHeader); + } + + // TODO: HC2 is not yet supported. Should be. + NS_ASSERT_MSG ( m_hc2HeaderPresent != true, "Can not compress HC2, exiting. Very sorry." ); +} + +uint32_t SixLowPanHc1::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + uint32_t serializedSize = 3; + + uint8_t dispatch = i.ReadU8 (); + if (dispatch != SixLowPanDispatch::LOWPAN_HC1) + { + return 0; + } + + uint8_t encoding = i.ReadU8 (); + m_hopLimit = i.ReadU8 (); + + m_srcCompression = LowPanHc1Addr_e (encoding >> 6); + m_dstCompression = LowPanHc1Addr_e ( (encoding >> 4) & 0x3); + m_tcflCompression = (encoding >> 3) & 0x1; + m_nextHeaderCompression = LowPanHc1NextHeader_e ( (encoding >> 1) & 0x3); + m_hc2HeaderPresent = encoding & 0x1; + + switch (m_srcCompression) + { + case HC1_PIII: + for ( int j = 0; j < 8; j++) + { + m_srcPrefix[j] = i.ReadU8 (); + } + for ( int j = 0; j < 8; j++) + { + m_srcInterface[j] = i.ReadU8 (); + } + serializedSize += 16; + break; + case HC1_PIIC: + for ( int j = 0; j < 8; j++) + { + m_srcPrefix[j] = i.ReadU8 (); + } + serializedSize += 8; + break; + case HC1_PCII: + for ( int j = 0; j < 8; j++) + { + m_srcInterface[j] = i.ReadU8 (); + } + serializedSize += 8; + break; + case HC1_PCIC: + break; + } + switch (m_dstCompression) + { + case HC1_PIII: + for ( int j = 0; j < 8; j++) + { + m_dstPrefix[j] = i.ReadU8 (); + } + for ( int j = 0; j < 8; j++) + { + m_dstInterface[j] = i.ReadU8 (); + } + serializedSize += 16; + break; + case HC1_PIIC: + for ( int j = 0; j < 8; j++) + { + m_dstPrefix[j] = i.ReadU8 (); + } + serializedSize += 8; + break; + case HC1_PCII: + for ( int j = 0; j < 8; j++) + { + m_dstInterface[j] = i.ReadU8 (); + } + serializedSize += 8; + break; + case HC1_PCIC: + break; + } + + if ( m_tcflCompression == false ) + { + m_trafficClass = i.ReadU8 (); + uint8_t temp[3]; + i.Read (temp, 3); + m_flowLabel = temp[2]; + m_flowLabel = (m_flowLabel << 8) | temp[1]; + m_flowLabel = (m_flowLabel << 8) | temp[0]; + serializedSize += 4; + } + + switch ( m_nextHeaderCompression ) + { + case HC1_NC: + m_nextHeader = i.ReadU8 (); + serializedSize++; + break; + case HC1_TCP: + m_nextHeader = Ipv6Header::IPV6_TCP; + break; + case HC1_UDP: + m_nextHeader = Ipv6Header::IPV6_UDP; + break; + case HC1_ICMP: + m_nextHeader = Ipv6Header::IPV6_ICMPV6; + break; + } + + NS_ASSERT_MSG ( m_hc2HeaderPresent != true, "Can not compress HC2, exiting. Very sorry." ); + + return GetSerializedSize (); +} + +void SixLowPanHc1::SetHopLimit (uint8_t limit) +{ + m_hopLimit = limit; +} + +uint8_t SixLowPanHc1::GetHopLimit () const +{ + return m_hopLimit; +} + +SixLowPanHc1::LowPanHc1Addr_e SixLowPanHc1::GetDstCompression () const +{ + return m_dstCompression; +} + +const uint8_t* SixLowPanHc1::GetDstInterface () const +{ + return m_dstInterface; +} + +const uint8_t* SixLowPanHc1::GetDstPrefix () const +{ + return m_dstPrefix; +} + +uint32_t SixLowPanHc1::GetFlowLabel () const +{ + return m_flowLabel; +} + +uint8_t SixLowPanHc1::GetNextHeader () const +{ + return m_nextHeader; +} + +SixLowPanHc1::LowPanHc1Addr_e SixLowPanHc1::GetSrcCompression () const +{ + return m_srcCompression; +} + +const uint8_t* SixLowPanHc1::GetSrcInterface () const +{ + return m_srcInterface; +} + +const uint8_t* SixLowPanHc1::GetSrcPrefix () const +{ + return m_srcPrefix; +} + +uint8_t SixLowPanHc1::GetTrafficClass () const +{ + return m_trafficClass; +} + +bool SixLowPanHc1::IsTcflCompression () const +{ + return m_tcflCompression; +} + +bool SixLowPanHc1::IsHc2HeaderPresent () const +{ + return m_hc2HeaderPresent; +} + +void SixLowPanHc1::SetDstCompression (LowPanHc1Addr_e dstCompression) +{ + m_dstCompression = dstCompression; +} + +void SixLowPanHc1::SetDstInterface (const uint8_t* dstInterface) +{ + for ( int i = 0; i < 8; i++) + { + m_dstInterface[i] = dstInterface[i]; + } +} + +void SixLowPanHc1::SetDstPrefix (const uint8_t* dstPrefix) +{ + for ( int i = 0; i < 8; i++) + { + m_dstPrefix[i] = dstPrefix[i]; + } +} + +void SixLowPanHc1::SetFlowLabel (uint32_t flowLabel) +{ + m_flowLabel = flowLabel; +} + +void SixLowPanHc1::SetNextHeader (uint8_t nextHeader) +{ + m_nextHeader = nextHeader; + + switch (m_nextHeader) + { + case Ipv6Header::IPV6_UDP: + m_nextHeaderCompression = HC1_UDP; + break; + case Ipv6Header::IPV6_TCP: + m_nextHeaderCompression = HC1_TCP; + break; + case Ipv6Header::IPV6_ICMPV6: + m_nextHeaderCompression = HC1_ICMP; + break; + default: + m_nextHeaderCompression = HC1_NC; + break; + } +} + +void SixLowPanHc1::SetSrcCompression (LowPanHc1Addr_e srcCompression) +{ + m_srcCompression = srcCompression; +} + +void SixLowPanHc1::SetSrcInterface (const uint8_t* srcInterface) +{ + for ( int i = 0; i < 8; i++) + { + m_srcInterface[i] = srcInterface[i]; + } +} + +void SixLowPanHc1::SetSrcPrefix (const uint8_t* srcPrefix) +{ + for ( int i = 0; i < 8; i++) + { + m_srcPrefix[i] = srcPrefix[i]; + } +} + +void SixLowPanHc1::SetTcflCompression (bool tcflCompression) +{ + m_tcflCompression = tcflCompression; +} + +void SixLowPanHc1::SetTrafficClass (uint8_t trafficClass) +{ + m_trafficClass = trafficClass; +} + + +void SixLowPanHc1::SetHc2HeaderPresent (bool hc2HeaderPresent) +{ + m_hc2HeaderPresent = hc2HeaderPresent; +} + + +std::ostream & operator << (std::ostream & os, const SixLowPanHc1 & h) +{ + h.Print (os); + return os; +} + +/* + * SixLowPanFrag1 + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanFrag1) + ; + +SixLowPanFrag1::SixLowPanFrag1 () + : m_datagramSize (0), + m_datagramTag (0) +{ +} + +TypeId SixLowPanFrag1::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanFrag1").SetParent
    ().AddConstructor (); + return tid; +} + +TypeId SixLowPanFrag1::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanFrag1::Print (std::ostream & os) const +{ + os << "datagram size " << m_datagramSize << " tag " << m_datagramTag; +} + +uint32_t SixLowPanFrag1::GetSerializedSize () const +{ + return 4; +} + +void SixLowPanFrag1::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + uint16_t temp = m_datagramSize | ( uint16_t (SixLowPanDispatch::LOWPAN_FRAG1) << 8 ); + + i.WriteU8 (uint8_t (temp >> 8)); + i.WriteU8 (uint8_t (temp & 0xff)); + + i.WriteU16 (m_datagramTag); +} + +uint32_t SixLowPanFrag1::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + uint8_t temp = i.ReadU8 (); + m_datagramSize = (uint16_t (temp) << 8) | i.ReadU8 (); + m_datagramSize &= 0x7FF; + + m_datagramTag = i.ReadU16 (); + return GetSerializedSize (); +} + +void SixLowPanFrag1::SetDatagramSize (uint16_t datagramSize) +{ + m_datagramSize = datagramSize & 0x7FF; +} + +uint16_t SixLowPanFrag1::GetDatagramSize () const +{ + return m_datagramSize & 0x7FF; +} + +void SixLowPanFrag1::SetDatagramTag (uint16_t datagramTag) +{ + m_datagramTag = datagramTag; +} + +uint16_t SixLowPanFrag1::GetDatagramTag () const +{ + return m_datagramTag; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanFrag1 & h) +{ + h.Print (os); + return os; +} + + +/* + * SixLowPanFragN + */ + +NS_OBJECT_ENSURE_REGISTERED (SixLowPanFragN) + ; + +SixLowPanFragN::SixLowPanFragN () + : m_datagramSize (0), + m_datagramTag (0), + m_datagramOffset (0) +{ +} +/* + * SixLowPanFragmentOffset + */ +TypeId SixLowPanFragN::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanFragN").SetParent
    ().AddConstructor (); + return tid; +} + +TypeId SixLowPanFragN::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanFragN::Print (std::ostream & os) const +{ + os << "datagram size " << m_datagramSize << " tag " << m_datagramTag << " offset " << int(m_datagramOffset); +} + +uint32_t SixLowPanFragN::GetSerializedSize () const +{ + return 5; +} + +void SixLowPanFragN::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + uint16_t temp = m_datagramSize | ( uint16_t (SixLowPanDispatch::LOWPAN_FRAGN) << 8 ); + + i.WriteU8 (uint8_t (temp >> 8)); + i.WriteU8 (uint8_t (temp & 0xff)); + + i.WriteU16 (m_datagramTag); + i.WriteU8 (m_datagramOffset); +} + +uint32_t SixLowPanFragN::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + uint8_t temp = i.ReadU8 (); + m_datagramSize = (uint16_t (temp) << 8) | i.ReadU8 (); + m_datagramSize &= 0x7FF; + + m_datagramTag = i.ReadU16 (); + m_datagramOffset = i.ReadU8 (); + + return GetSerializedSize (); +} + +void SixLowPanFragN::SetDatagramSize (uint16_t datagramSize) +{ + m_datagramSize = datagramSize & 0x7FF; +} + +uint16_t SixLowPanFragN::GetDatagramSize () const +{ + return m_datagramSize & 0x7FF; +} + +void SixLowPanFragN::SetDatagramTag (uint16_t datagramTag) +{ + m_datagramTag = datagramTag; +} + +uint16_t SixLowPanFragN::GetDatagramTag () const +{ + return m_datagramTag; +} + +void SixLowPanFragN::SetDatagramOffset (uint8_t datagramOffset) +{ + m_datagramOffset = datagramOffset; +} + +uint8_t SixLowPanFragN::GetDatagramOffset () const +{ + return m_datagramOffset; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanFragN & h) +{ + h.Print (os); + return os; +} + +/* + * SixLowPanIphcHeader + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanIphc) + ; + +SixLowPanIphc::SixLowPanIphc () +{ + // 011x xxxx xxxx xxxx + m_baseFormat = 0x6000; +} + +SixLowPanIphc::SixLowPanIphc (uint8_t dispatch) +{ + // 011x xxxx xxxx xxxx + m_baseFormat = dispatch; + m_baseFormat <<= 8; +} + +TypeId SixLowPanIphc::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanIphc").SetParent
    ().AddConstructor (); + return tid; +} + +TypeId SixLowPanIphc::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanIphc::Print (std::ostream & os) const +{ + os << "Compression kind: " << m_baseFormat; +} + +uint32_t SixLowPanIphc::GetSerializedSize () const +{ + uint32_t serializedSize = 2; + + if ( GetCid () ) + { + serializedSize++; + } + switch ( GetTf () ) + { + case TF_FULL: + serializedSize += 4; + break; + case TF_DSCP_ELIDED: + serializedSize += 3; + break; + case TF_FL_ELIDED: + serializedSize++; + break; + default: + break; + } + if ( GetNh () == false ) + { + serializedSize++; + } + if ( GetHlim () == HLIM_INLINE) + { + serializedSize++; + } + switch (GetSam () ) + { + case HC_INLINE: + if ( GetSac () == false ) + { + serializedSize += 16; + } + break; + case HC_COMPR_64: + serializedSize += 8; + break; + case HC_COMPR_16: + serializedSize += 2; + break; + case HC_COMPR_0: + default: + break; + } + if ( GetM () == false) + { + switch (GetDam () ) + { + case HC_INLINE: + if ( GetDac () == false ) + { + serializedSize += 16; + } + break; + case HC_COMPR_64: + serializedSize += 8; + break; + case HC_COMPR_16: + serializedSize += 2; + break; + case HC_COMPR_0: + default: + break; + } + } + else + { + switch (GetDam () ) + { + case HC_INLINE: + if ( GetDac () == false ) + { + serializedSize += 16; + } + else + { + serializedSize += 6; + } + break; + case HC_COMPR_64: + if ( GetDac () == false ) + { + serializedSize += 6; + } + break; + case HC_COMPR_16: + if ( GetDac () == false ) + { + serializedSize += 4; + } + break; + case HC_COMPR_0: + default: + if ( GetDac () == false ) + { + serializedSize++; + } + break; + } + } + + + + return serializedSize; +} + +void SixLowPanIphc::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + i.WriteHtonU16 (m_baseFormat); + + if ( GetCid () ) + { + i.WriteU8 (m_srcdstContextId); + } + // Traffic Class and Flow Label + switch ( GetTf () ) + { + uint8_t temp; + case TF_FULL: + temp = (m_ecn << 6) | m_dscp; + i.WriteU8 (temp); + temp = m_flowLabel >> 16; + i.WriteU8 (temp); + temp = (m_flowLabel >> 8) & 0xff; + i.WriteU8 (temp); + temp = m_flowLabel & 0xff; + i.WriteU8 (temp); + break; + case TF_DSCP_ELIDED: + temp = (m_ecn << 6) | (m_flowLabel >> 16 ); + i.WriteU8 (temp); + temp = (m_flowLabel >> 8) & 0xff; + i.WriteU8 (temp); + temp = m_flowLabel & 0xff; + i.WriteU8 (temp); + break; + case TF_FL_ELIDED: + temp = (m_ecn << 6) | m_dscp; + i.WriteU8 (temp); + break; + default: + break; + } + // Next Header + if ( GetNh () == false ) + { + i.WriteU8 (m_nextHeader); + } + // Hop Limit + if ( GetHlim () == HLIM_INLINE ) + { + i.WriteU8 (m_hopLimit); + } + // Source Address + switch (GetSam () ) + { + uint8_t temp[16]; + case HC_INLINE: + if ( GetSac () == false ) + { + uint8_t temp[16]; + m_srcAddress.Serialize (temp); + i.Write (temp, 16); + } + break; + case HC_COMPR_64: + m_srcAddress.Serialize (temp); + i.Write (temp + 8, 8); + break; + case HC_COMPR_16: + m_srcAddress.Serialize (temp); + i.Write (temp + 14, 2); + break; + case HC_COMPR_0: + default: + break; + } + // Destination Address + if ( GetM () == false) + { + uint8_t temp[16]; + switch (GetDam () ) + { + case HC_INLINE: + if ( GetDac () == false ) + { + m_dstAddress.Serialize (temp); + i.Write (temp, 16); + } + break; + case HC_COMPR_64: + m_dstAddress.Serialize (temp); + i.Write (temp + 8, 8); + break; + case HC_COMPR_16: + m_dstAddress.Serialize (temp); + i.Write (temp + 14, 2); + break; + case HC_COMPR_0: + default: + break; + } + } + else + { + switch (GetDam () ) + { + uint8_t temp[16]; + case HC_INLINE: + if ( GetDac () == false ) + { + m_dstAddress.Serialize (temp); + i.Write (temp, 16); + } + else + { + m_dstAddress.Serialize (temp); + i.Write (temp + 1, 2); + i.Write (temp + 12, 4); + } + break; + case HC_COMPR_64: + if ( GetDac () == false ) + { + m_dstAddress.Serialize (temp); + i.Write (temp + 1, 1); + i.Write (temp + 11, 5); + } + break; + case HC_COMPR_16: + if ( GetDac () == false ) + { + m_dstAddress.Serialize (temp); + i.Write (temp + 1, 1); + i.Write (temp + 13, 3); + } + break; + case HC_COMPR_0: + default: + if ( GetDac () == false ) + { + m_dstAddress.Serialize (temp); + i.WriteU8 (temp[15]); + } + break; + } + } +} + +uint32_t SixLowPanIphc::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + + m_baseFormat = i.ReadNtohU16 (); + + if ( GetCid () ) + { + m_srcdstContextId = i.ReadU8 (); + } + // Traffic Class and Flow Label + switch ( GetTf () ) + { + uint8_t temp; + case TF_FULL: + temp = i.ReadU8 (); + m_ecn = temp >> 6; + m_dscp = temp & 0x3F; + temp = i.ReadU8 (); + m_flowLabel = temp; + temp = i.ReadU8 (); + m_flowLabel = (m_flowLabel << 8) | temp; + temp = i.ReadU8 (); + m_flowLabel = (m_flowLabel << 8) | temp; + break; + case TF_DSCP_ELIDED: + temp = i.ReadU8 (); + m_ecn = temp >> 6; + m_flowLabel = temp & 0x3F; + temp = i.ReadU8 (); + m_flowLabel = (m_flowLabel << 8) | temp; + temp = i.ReadU8 (); + m_flowLabel = (m_flowLabel << 8) | temp; + break; + case TF_FL_ELIDED: + temp = i.ReadU8 (); + m_ecn = temp >> 6; + m_dscp = temp & 0x3F; + break; + default: + break; + } + // Next Header + if ( GetNh () == false ) + { + m_nextHeader = i.ReadU8 (); + } + // Hop Limit + switch ( GetHlim () ) + { + case HLIM_INLINE: + m_hopLimit = i.ReadU8 (); + break; + case HLIM_COMPR_1: + m_hopLimit = 1; + break; + case HLIM_COMPR_64: + m_hopLimit = 64; + break; + case HLIM_COMPR_255: + default: + m_hopLimit = 255; + break; + + } + // Source Address + switch (GetSam () ) + { + uint8_t temp[16]; + case HC_INLINE: + if ( GetSac () == false ) + { + i.Read (temp, 16); + m_srcAddress = Ipv6Address::Deserialize (temp); + } + break; + case HC_COMPR_64: + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 8, 8); + temp[0] = 0xfe; + temp[1] = 0x80; + m_srcAddress = Ipv6Address::Deserialize (temp); + break; + case HC_COMPR_16: + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 14, 2); + temp[0] = 0xfe; + temp[1] = 0x80; + temp[11] = 0xff; + temp[12] = 0xfe; + m_srcAddress = Ipv6Address::Deserialize (temp); + break; + case HC_COMPR_0: + default: + break; + } + if ( GetSac () == true ) + { + PostProcessSac (); + } + // Destination Address + if ( GetM () == false) + { + uint8_t temp[16]; + switch (GetDam () ) + { + case HC_INLINE: + if ( GetDac () == false ) + { + i.Read (temp, 16); + m_dstAddress = Ipv6Address::Deserialize (temp); + } + break; + case HC_COMPR_64: + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 8, 8); + temp[0] = 0xfe; + temp[1] = 0x80; + m_dstAddress = Ipv6Address::Deserialize (temp); + break; + case HC_COMPR_16: + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 14, 2); + temp[0] = 0xfe; + temp[1] = 0x80; + temp[11] = 0xff; + temp[12] = 0xfe; + m_dstAddress = Ipv6Address::Deserialize (temp); + break; + case HC_COMPR_0: + default: + break; + } + } + else + { + switch (GetDam () ) + { + uint8_t temp[16]; + case HC_INLINE: + if ( GetDac () == false ) + { + i.Read (temp, 16); + m_dstAddress = Ipv6Address::Deserialize (temp); + } + else + { + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 1, 2); + i.Read (temp + 12, 4); + temp[0] = 0xff; + m_dstAddress = Ipv6Address::Deserialize (temp); + } + break; + case HC_COMPR_64: + if ( GetDac () == false ) + { + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 1, 1); + i.Read (temp + 11, 5); + temp[0] = 0xff; + m_dstAddress = Ipv6Address::Deserialize (temp); + } + break; + case HC_COMPR_16: + if ( GetDac () == false ) + { + memset (temp, 0x00, sizeof (temp)); + i.Read (temp + 1, 1); + i.Read (temp + 13, 3); + temp[0] = 0xff; + m_dstAddress = Ipv6Address::Deserialize (temp); + } + break; + case HC_COMPR_0: + default: + if ( GetDac () == false ) + { + memset (temp, 0x00, sizeof (temp)); + temp[15] = i.ReadU8 (); + temp[0] = 0xff; + temp[1] = 0x02; + m_dstAddress = Ipv6Address::Deserialize (temp); + } + break; + } + } + if ( GetDac () == true ) + { + PostProcessDac (); + } + return GetSerializedSize (); +} + +void SixLowPanIphc::SetTf (TrafficClassFlowLabel_e tfField) +{ + uint16_t field = tfField; + m_baseFormat |= (field << 11); +} + +SixLowPanIphc::TrafficClassFlowLabel_e SixLowPanIphc::GetTf (void) const +{ + return TrafficClassFlowLabel_e ((m_baseFormat >> 11) & 0x3); +} + +void SixLowPanIphc::SetNh (bool nhField) +{ + uint16_t field = nhField; + m_baseFormat |= (field << 10); +} + +bool SixLowPanIphc::GetNh (void) const +{ + return ((m_baseFormat >> 10) & 0x1); +} + +void SixLowPanIphc::SetHlim (Hlim_e hlimField) +{ + uint16_t field = hlimField; + m_baseFormat |= (field << 8); +} + +SixLowPanIphc::Hlim_e SixLowPanIphc::GetHlim (void) const +{ + return Hlim_e ((m_baseFormat >> 8) & 0x3); +} + +void SixLowPanIphc::SetCid (bool cidField) +{ + uint16_t field = cidField; + m_baseFormat |= (field << 7); +} + +bool SixLowPanIphc::GetCid (void) const +{ + return ((m_baseFormat >> 7) & 0x1); +} + +void SixLowPanIphc::SetSac (bool sacField) +{ + uint16_t field = sacField; + m_baseFormat |= (field << 6); +} + +bool SixLowPanIphc::GetSac (void) const +{ + return ((m_baseFormat >> 6) & 0x1); +} + +void SixLowPanIphc::SetSam (HeaderCompression_e samField) +{ + uint16_t field = samField; + m_baseFormat |= (field << 4); +} + +SixLowPanIphc::HeaderCompression_e SixLowPanIphc::GetSam (void) const +{ + return HeaderCompression_e ((m_baseFormat >> 4) & 0x3); +} + +void SixLowPanIphc::SetM (bool mField) +{ + uint16_t field = mField; + m_baseFormat |= (field << 3); +} + +bool SixLowPanIphc::GetM (void) const +{ + return ((m_baseFormat >> 3) & 0x1); +} + +void SixLowPanIphc::SetDac (bool dacField) +{ + uint16_t field = dacField; + m_baseFormat |= (field << 2); +} + +bool SixLowPanIphc::GetDac (void) const +{ + return ((m_baseFormat >> 2) & 0x1); +} + +void SixLowPanIphc::SetDam (HeaderCompression_e damField) +{ + uint16_t field = damField; + m_baseFormat |= field; +} + +SixLowPanIphc::HeaderCompression_e SixLowPanIphc::GetDam (void) const +{ + return HeaderCompression_e (m_baseFormat & 0x3); +} + +void SixLowPanIphc::SetSrcContextId (uint8_t srcContextId) +{ + NS_ASSERT_MSG (srcContextId < 16, "Src Context ID too large"); + m_srcdstContextId |= srcContextId << 4; +} + +uint8_t SixLowPanIphc::GetSrcContextId (void) const +{ + return ( m_srcdstContextId >> 4); +} + +void SixLowPanIphc::SetDstContextId (uint8_t dstContextId) +{ + NS_ASSERT_MSG (dstContextId < 16, "Dst Context ID too large"); + m_srcdstContextId |= (dstContextId & 0xF); +} + +uint8_t SixLowPanIphc::GetDstContextId (void) const +{ + return (m_srcdstContextId & 0xF); +} + +void SixLowPanIphc::SetEcn (uint8_t ecn) +{ + NS_ASSERT_MSG (ecn < 4, "ECN too large"); + m_ecn = ecn; +} + +uint8_t SixLowPanIphc::GetEcn (void) const +{ + return m_ecn; +} + +void SixLowPanIphc::SetDscp (uint8_t dscp) +{ + NS_ASSERT_MSG (dscp < 64, "DSCP too large"); + m_dscp = dscp; +} + +uint8_t SixLowPanIphc::GetDscp (void) const +{ + return m_dscp; +} + +void SixLowPanIphc::SetFlowLabel (uint32_t flowLabel) +{ + NS_ASSERT_MSG (flowLabel < 0x100000, "Flow Label too large"); + m_flowLabel = flowLabel; +} + +uint32_t SixLowPanIphc::GetFlowLabel (void) const +{ + return m_flowLabel; +} + +void SixLowPanIphc::SetNextHeader (uint8_t nextHeader) +{ + m_nextHeader = nextHeader; +} + +uint8_t SixLowPanIphc::GetNextHeader (void) const +{ + return m_nextHeader; +} + +void SixLowPanIphc::SetHopLimit (uint8_t hopLimit) +{ + m_hopLimit = hopLimit; +} + +uint8_t SixLowPanIphc::GetHopLimit (void) const +{ + return m_hopLimit; +} + +void SixLowPanIphc::SetSrcAddress (Ipv6Address srcAddress) +{ + m_srcAddress = srcAddress; +} + +Ipv6Address SixLowPanIphc::GetSrcAddress () const +{ + return m_srcAddress; +} + +void SixLowPanIphc::SetDstAddress (Ipv6Address dstAddress) +{ + m_dstAddress = dstAddress; +} + +Ipv6Address SixLowPanIphc::GetDstAddress () const +{ + return m_dstAddress; +} + +void SixLowPanIphc::PostProcessSac () +{ + NS_ABORT_MSG ("Unsupported; Context destination is not implemented"); + return; +} + +void SixLowPanIphc::PostProcessDac () +{ + NS_ABORT_MSG ("Unsupported; Context destination is not implemented"); + return; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanIphc & h) +{ + h.Print (os); + return os; +} + +/* + * SixLowPanNhcExtensionHeader + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanNhcExtension) + ; + +SixLowPanNhcExtension::SixLowPanNhcExtension () +{ + // 1110 xxxx + m_nhcExtensionHeader = 0xE0; + m_nhcNextHeader = 0; + m_nhcBlobLength = 0; +} + +TypeId SixLowPanNhcExtension::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanNhcExtension") + .SetParent
    () + .AddConstructor (); + return tid; +} + +TypeId SixLowPanNhcExtension::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanNhcExtension::Print (std::ostream & os) const +{ + os << "Compression kind: " << int (m_nhcExtensionHeader) << " Size: " << int(GetSerializedSize ()); +} + +uint32_t SixLowPanNhcExtension::GetSerializedSize () const +{ + uint32_t serializedSize = 2; + if ( GetNh () == false ) + { + serializedSize++; + } + return serializedSize + m_nhcBlobLength; +} + +void SixLowPanNhcExtension::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_nhcExtensionHeader); + if ( GetNh () == false ) + { + i.WriteU8 (m_nhcNextHeader); + } + i.WriteU8 (m_nhcBlobLength); + i.Write (m_nhcBlob, m_nhcBlobLength); +} + +uint32_t SixLowPanNhcExtension::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_nhcExtensionHeader = i.ReadU8 (); + if ( GetNh () == false ) + { + m_nhcNextHeader = i.ReadU8 (); + } + m_nhcBlobLength = i.ReadU8 (); + i.Read (m_nhcBlob, m_nhcBlobLength); + + return GetSerializedSize (); +} + +SixLowPanDispatch::NhcDispatch_e +SixLowPanNhcExtension::GetNhcDispatchType (void) const +{ + return SixLowPanDispatch::LOWPAN_NHC; +} + +void SixLowPanNhcExtension::SetEid (Eid_e extensionHeaderType) +{ + uint8_t field = extensionHeaderType; + m_nhcExtensionHeader |= (field << 1); +} + +SixLowPanNhcExtension::Eid_e SixLowPanNhcExtension::GetEid (void) const +{ + return Eid_e ((m_nhcExtensionHeader >> 1) & 0x7); +} + +void SixLowPanNhcExtension::SetNextHeader (uint8_t nextHeader) +{ + m_nhcNextHeader = nextHeader; +} + +uint8_t SixLowPanNhcExtension::GetNextHeader (void) const +{ + return m_nhcNextHeader; +} + +void SixLowPanNhcExtension::SetNh (bool nhField) +{ + uint8_t field = nhField; + m_nhcExtensionHeader |= field; +} + +bool SixLowPanNhcExtension::GetNh (void) const +{ + return m_nhcExtensionHeader & 0x01; +} + +void SixLowPanNhcExtension::SetBlob (const uint8_t* blob, uint32_t size) +{ + NS_ASSERT_MSG ( size < 255, "Buffer too long" ); + + m_nhcBlobLength = size; + std::memcpy (m_nhcBlob, blob, size); +} + +uint32_t SixLowPanNhcExtension::CopyBlob (uint8_t* blob, uint32_t size) const +{ + NS_ASSERT_MSG ( size > m_nhcBlobLength, "Buffer too short" ); + + std::memcpy (blob, m_nhcBlob, m_nhcBlobLength); + return m_nhcBlobLength; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanNhcExtension & h) +{ + h.Print (os); + return os; +} + +/* + * SixLowPanUdpNhcExtension + */ +NS_OBJECT_ENSURE_REGISTERED (SixLowPanUdpNhcExtension) + ; + +SixLowPanUdpNhcExtension::SixLowPanUdpNhcExtension () +{ + // 1111 0xxx + m_baseFormat = 0xF0; + m_checksum = 0; + m_srcPort = 0; + m_dstPort = 0; +} + +TypeId SixLowPanUdpNhcExtension::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanUdpNhcExtension") + .SetParent
    () + .AddConstructor (); + return tid; +} + +TypeId SixLowPanUdpNhcExtension::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void SixLowPanUdpNhcExtension::Print (std::ostream & os) const +{ + os << "Compression kind: " << uint8_t (m_baseFormat); +} + +uint32_t SixLowPanUdpNhcExtension::GetSerializedSize () const +{ + uint32_t serializedSize = 1; + if ( !GetC () ) + { + serializedSize += 2; + } + switch (GetPorts ()) + { + case PORTS_INLINE: + serializedSize += 4; + break; + case PORTS_ALL_SRC_LAST_DST: + case PORTS_LAST_SRC_ALL_DST: + serializedSize += 3; + break; + case PORTS_LAST_SRC_LAST_DST: + serializedSize += 1; + break; + default: + break; + } + return serializedSize; +} + +void SixLowPanUdpNhcExtension::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_baseFormat); + uint8_t temp; + + // Ports + switch ( GetPorts () ) + { + case PORTS_INLINE: + i.WriteHtonU16 (m_srcPort); + i.WriteHtonU16 (m_dstPort); + break; + case PORTS_ALL_SRC_LAST_DST: + i.WriteHtonU16 (m_srcPort); + i.WriteU8 (m_dstPort & 0xff); + break; + case PORTS_LAST_SRC_ALL_DST: + i.WriteU8 (m_srcPort & 0xff); + i.WriteHtonU16 (m_dstPort); + break; + case PORTS_LAST_SRC_LAST_DST: + temp = ((m_srcPort & 0xf) << 4) | (m_dstPort & 0xf); + i.WriteU8 (temp); + break; + default: + break; + } + + // Checksum + if ( !GetC () ) + { + i.WriteU16 (m_checksum); + } + +} + +uint32_t SixLowPanUdpNhcExtension::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + m_baseFormat = i.ReadU8 (); + uint8_t temp; + + // Ports + switch ( GetPorts () ) + { + case PORTS_INLINE: + m_srcPort = i.ReadNtohU16 (); + m_dstPort = i.ReadNtohU16 (); + break; + case PORTS_ALL_SRC_LAST_DST: + m_srcPort = i.ReadNtohU16 (); + m_dstPort = i.ReadU8 (); + break; + case PORTS_LAST_SRC_ALL_DST: + m_srcPort = i.ReadU8 (); + m_dstPort = i.ReadNtohU16 (); + break; + case PORTS_LAST_SRC_LAST_DST: + temp = i.ReadU8 (); + m_srcPort = temp >> 4; + m_dstPort = temp & 0xf; + break; + default: + break; + } + + // Checksum + if ( !GetC () ) + { + m_checksum = i.ReadU16 (); + } + + return GetSerializedSize (); +} + +SixLowPanDispatch::NhcDispatch_e +SixLowPanUdpNhcExtension::GetNhcDispatchType (void) const +{ + return SixLowPanDispatch::LOWPAN_UDPNHC; +} + +void SixLowPanUdpNhcExtension::SetPorts (Ports_e ports) +{ + uint16_t field = ports; + m_baseFormat |= field; +} + +SixLowPanUdpNhcExtension::Ports_e SixLowPanUdpNhcExtension::GetPorts (void) const +{ + return Ports_e (m_baseFormat & 0x3); +} + +void SixLowPanUdpNhcExtension::SetSrcPort (uint16_t srcport) +{ + m_srcPort = srcport; +} + +uint16_t SixLowPanUdpNhcExtension::GetSrcPort (void) const +{ + return m_srcPort; +} + +void SixLowPanUdpNhcExtension::SetDstPort (uint16_t dstport) +{ + m_dstPort = dstport; +} + +uint16_t SixLowPanUdpNhcExtension::GetDstPort (void) const +{ + return m_dstPort; +} + +void SixLowPanUdpNhcExtension::SetC (bool cField) +{ + uint16_t field = cField; + m_baseFormat |= (field << 2); +} + +bool SixLowPanUdpNhcExtension::GetC (void) const +{ + return ((m_baseFormat >> 2) & 0x1); +} + +void SixLowPanUdpNhcExtension::SetChecksum (uint16_t checksum) +{ + m_checksum = checksum; +} + +uint16_t SixLowPanUdpNhcExtension::GetChecksum (void) const +{ + return m_checksum; +} + +std::ostream & operator << (std::ostream & os, const SixLowPanUdpNhcExtension & h) +{ + h.Print (os); + return os; +} + + +} + diff --git a/src/sixlowpan/model/sixlowpan-header.h b/src/sixlowpan/model/sixlowpan-header.h new file mode 100644 index 000000000..5c954adaa --- /dev/null +++ b/src/sixlowpan/model/sixlowpan-header.h @@ -0,0 +1,1214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + * Michele Muccio + */ + +#ifndef SIXLOWPANHEADER_H_ +#define SIXLOWPANHEADER_H_ + +#include "ns3/header.h" +#include "ns3/ipv6-address.h" +#include "ns3/packet.h" +#include "ns3/ipv6-header.h" + +namespace ns3 { + +/** +* \ingroup sixlowpan +* \brief Dispatch header helper. This class only purpose is to interpret +* the Dispatch header into its correct type. +* +* The dispatch type is defined by a zero bit as the first bit and a one +* bit as the second bit. + \verbatim + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 1| Dispatch | type-specific header + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + \endverbatim +*/ +class SixLowPanDispatch +{ +public: + /** + * \brief Dispatch values, as defined in RFC4944 and RFC6282 + \verbatim + Pattern Header Type + +------------+------------------------------------------------+ + | 00 xxxxxx | NALP - Not a LoWPAN frame | + | 01 000000 | ESC - Additional Dispatch byte follows | + | 01 000001 | IPv6 - Uncompressed IPv6 Addresses | + | 01 000010 | LOWPAN_HC1 - LOWPAN_HC1 compressed IPv6 | + | 01 000011 | reserved - Reserved for future use | + | ... | reserved - Reserved for future use | + | 01 001111 | reserved - Reserved for future use | + | 01 010000 | LOWPAN_BC0 - LOWPAN_BC0 broadcast | + | 01 010001 | reserved - Reserved for future use | + | ... | reserved - Reserved for future use | + | 01 1xxxxx | LOWPAN_IPHC - LOWPAN_IPHC compressed IPv6 | + | 10 xxxxxx | MESH - Mesh Header | + | 11 000xxx | FRAG1 - Fragmentation Header (first) | + | 11 001000 | reserved - Reserved for future use | + | ... | reserved - Reserved for future use | + | 11 011111 | reserved - Reserved for future use | + | 11 100xxx | FRAGN - Fragmentation Header (subsequent)| + | 11 101000 | reserved - Reserved for future use | + | ... | reserved - Reserved for future use | + | 11 111111 | reserved - Reserved for future use | + +------------+------------------------------------------------+ + \endverbatim + */ + enum Dispatch_e + { + LOWPAN_NALP = 0x0, + LOWPAN_NALP_N = 0x3F, + LOWPAN_NOTCOMPRESSED = 0x41, + LOWPAN_HC1 = 0x42, + LOWPAN_BC0 = 0x50, + LOWPAN_IPHC = 0x60, + LOWPAN_IPHC_N = 0x7F, + LOWPAN_MESH = 0x80, + LOWPAN_MESH_N = 0xBF, + LOWPAN_FRAG1 = 0xC0, + LOWPAN_FRAG1_N = 0xC7, + LOWPAN_FRAGN = 0xE0, + LOWPAN_FRAGN_N = 0xE7, + LOWPAN_UNSUPPORTED = 0xFF + }; + + /** + * \brief Dispatch values for Next Header compression. + * + * The dispatch values reflect the dispatch use, since + * some dispatch bits carry actual header compression bits. + */ + enum NhcDispatch_e + { + LOWPAN_NHC = 0xE0, + LOWPAN_NHC_N = 0xEF, + LOWPAN_UDPNHC = 0xF0, + LOWPAN_UDPNHC_N = 0xF7, + LOWPAN_NHCUNSUPPORTED = 0xFF + }; + + SixLowPanDispatch (void); + + /** + * \brief Get the Dispatch type. + * \param dispatch the dispatch value + * \return the Dispatch type + */ + static Dispatch_e GetDispatchType (uint8_t dispatch); + + /** + * \brief Get the NhcDispatch type. + * \param dispatch the dispatch value + * \return the NhcDispatch type + */ + static NhcDispatch_e GetNhcDispatchType (uint8_t dispatch); + +}; + +/** + * \ingroup sixlowpan + * \brief 6LoWPAN HC1 header - see RFC 4944 + */ +class SixLowPanHc1 : public Header +{ +public: + /** + * \brief Kind of address compression. + * + * The address compression is handled in 4 bits and might mean: + * PI: Prefix inline, PC: Prefix Compressed, + * II: Interface Identifier, Inline, IC: Interface Identifier Compressed + */ + enum LowPanHc1Addr_e + { + HC1_PIII = 0x00, + HC1_PIIC = 0x01, + HC1_PCII = 0x02, + HC1_PCIC = 0x03 + }; + + /** + * \brief Next header information. + * + * The Next header compression is handled in 4 bits and might mean: + * NC: Not Compressed, UDP, ICMP or TCP. + */ + enum LowPanHc1NextHeader_e + { + HC1_NC = 0x00, + HC1_UDP = 0x01, + HC1_ICMP = 0x02, + HC1_TCP = 0x03 + }; + + SixLowPanHc1 (void); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the Dispatch type. + * \return the Dispatch type + */ + // virtual Dispatch_e GetDispatchType (void) const; + + /** + * \brief Set the "Hop limit" field (TTL). + * \param limit the hop limit value + */ + void SetHopLimit (uint8_t limit); + + /** + * \brief Get the "Hop limit" field (TTL). + * \return the hop limit value + */ + uint8_t GetHopLimit (void) const; + + /** + * \brief Get Destination Compression type + * \returns the kind of address compression + */ + LowPanHc1Addr_e GetDstCompression () const; + + /** + * \brief Get the destination interface + * \returns the destination interface + */ + const uint8_t* GetDstInterface () const; + + /** + * \brief Get the destination prefix + * \returns the destination prefix + */ + const uint8_t* GetDstPrefix () const; + + /** + * \brief Get the Flow Label value + * \returns the Flow Label + */ + uint32_t GetFlowLabel () const; + + /** + * \brief Get the Next Header value + * \returns the Next Header value + */ + uint8_t GetNextHeader () const; + + /** + * \brief Get Source Compression type + * \returns the kind of address compression + */ + LowPanHc1Addr_e GetSrcCompression () const; + + /** + * \brief Get the source interface + * \returns the source interface + */ + const uint8_t* GetSrcInterface () const; + + /** + * \brief Get the source prefix + * \returns the source prefix + */ + const uint8_t* GetSrcPrefix () const; + + /** + * \brief Get the Traffic Class value + * \returns the Traffic Class value + */ + uint8_t GetTrafficClass () const; + + /** + * \brief Check if the Traffic Class and Flow Labels are compressed + * \returns true if TC and FL are compressed + */ + bool IsTcflCompression () const; + + /** + * \brief Check if there is a HC2 compressed header + * \returns true if next header is HC2 copressed + */ + bool IsHc2HeaderPresent () const; + + /** + * \brief Set Destination Compression type + * \param dstCompression the kind of address compression + */ + void SetDstCompression (LowPanHc1Addr_e dstCompression); + + /** + * \brief Set the destination interface + * \param dstInterface the destination interface + */ + void SetDstInterface (const uint8_t* dstInterface); + + /** + * \brief Set the destination prefix + * \param dstPrefix the destination prefix + */ + void SetDstPrefix (const uint8_t* dstPrefix); + + /** + * \brief Set the Flow Label value + * \param flowLabel the Flow Label + */ + void SetFlowLabel (uint32_t flowLabel); + + /** + * \brief Set the Next Header value + * \param nextHeader the Next Header value + */ + void SetNextHeader (uint8_t nextHeader); + + /** + * \brief Set Source Compression type + * \param srcCompression the kind of address compression + */ + void SetSrcCompression (LowPanHc1Addr_e srcCompression); + + /** + * \brief Set the source interface + * \param srcInterface the source interface + */ + void SetSrcInterface (const uint8_t* srcInterface); + + /** + * \brief Set the source prefix + * \param srcPrefix the source prefix + */ + void SetSrcPrefix (const uint8_t* srcPrefix); + + /** + * \brief Set the Traffic Class and Flow Labels as compressed + * \param tcflCompression true if TC and FL are compressed + */ + void SetTcflCompression (bool tcflCompression); + + /** + * \brief Set the next header a HC2 compressed header + * \param hc2HeaderPresent true if next header is HC2 compressed + */ + void SetHc2HeaderPresent (bool hc2HeaderPresent); + + /** + * \brief Set the Traffic Class value + * \param trafficClass the Traffic Class value + */ + void SetTrafficClass (uint8_t trafficClass); + +private: + uint8_t m_hopLimit; //!< Hop Limit + uint8_t m_srcPrefix[8]; //!< Source prefix + uint8_t m_srcInterface[8]; //!< Source interface + uint8_t m_dstPrefix[8]; //!< Destinaiton prefix + uint8_t m_dstInterface[8]; //!< Destination interface + uint8_t m_trafficClass; //!< Traffic Class + uint32_t m_flowLabel; //!< Flow Label + uint8_t m_nextHeader; //!< Next header + LowPanHc1Addr_e m_srcCompression; //!< Source compresison type + LowPanHc1Addr_e m_dstCompression; //!< Destination compresison type + bool m_tcflCompression; //!< is TC and FL compressed + LowPanHc1NextHeader_e m_nextHeaderCompression; //!< next header compression + bool m_hc2HeaderPresent; //!< is next header HC2 compressed +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the HC1 Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanHc1 const &header); + +/** + * \ingroup sixlowpan + * \brief 6LoWPAN FRAG1 header - see RFC 4944 + */ +class SixLowPanFrag1 : public Header +{ +public: + SixLowPanFrag1 (void); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the Dispatch type. + * \return the Dispatch type + */ + // virtual Dispatch_e GetDispatchType (void) const; + + /** + * \brief Set the datagram size + * \param datagramSize the datagram size + */ + void SetDatagramSize (uint16_t datagramSize); + + /** + * \brief Get the datagram size + * \returns the datagram size + */ + uint16_t GetDatagramSize (void) const; + + /** + * \brief Set the datagram tag + * \param datagramTag the datagram tag + */ + void SetDatagramTag (uint16_t datagramTag); + + /** + * \brief Get the datagram tag + * \returns the datagram tag + */ + uint16_t GetDatagramTag (void) const; + +private: + uint16_t m_datagramSize; //!< datagram size + uint16_t m_datagramTag; //!< datagram tag + +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the Frag1 Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanFrag1 const & header); + +/** + * \ingroup sixlowpan + * \brief 6LoWPAN FRAGN header - see RFC 4944 + */ +class SixLowPanFragN : public Header +{ +public: + SixLowPanFragN (void); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the Dispatch type. + * \return the Dispatch type + */ + // virtual Dispatch_e GetDispatchType (void) const; + + /** + * \brief Set the datagram size + * \param datagramSize the datagram size + */ + void SetDatagramSize (uint16_t datagramSize); + + /** + * \brief Get the datagram size + * \returns the datagram size + */ + uint16_t GetDatagramSize (void) const; + + /** + * \brief Set the datagram tag + * \param datagramTag the datagram tag + */ + void SetDatagramTag (uint16_t datagramTag); + + /** + * \brief Get the datagram tag + * \returns the datagram tag + */ + uint16_t GetDatagramTag (void) const; + + /** + * \brief Set the datagram offset + * \param datagramOffset the datagram offset + */ + void SetDatagramOffset (uint8_t datagramOffset); + + /** + * \brief Get the datagram offset + * \returns the datagram offset + */ + uint8_t GetDatagramOffset (void) const; + +private: + uint16_t m_datagramSize; //!< datagram size + uint16_t m_datagramTag; //!< datagram tag + uint8_t m_datagramOffset; //!< datagram offset + +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the FragN Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanFragN const &header); + +/** +* \ingroup sixlowpan +* \brief LOWPAN_IPHC base Encoding - see RFC 6262 + \verbatim + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | 0 | 1 | 1 | TF |NH | HLIM |CID|SAC| SAM | M |DAC| DAM | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + \endverbatim +*/ +class SixLowPanIphc : public Header +{ +public: + /** + * \brief TF: Traffic Class, Flow Label + * + * 00: ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) + * 01: ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided. + * 10: ECN + DSCP (1 byte), Flow Label is elided. + * 11: Traffic Class and Flow Label are elided. + * + */ + enum TrafficClassFlowLabel_e + { + TF_FULL = 0, + TF_DSCP_ELIDED, + TF_FL_ELIDED, + TF_ELIDED + }; + + /** + * \brief HLIM: Hop Limit + * + * 00: The Hop Limit field is carried in-line. + * 01: The Hop Limit field is compressed and the hop limit is 1. + * 10: The Hop Limit field is compressed and the hop limit is 64. + * 11: The Hop Limit field is compressed and the hop limit is 255. + */ + enum Hlim_e + { + HLIM_INLINE = 0, + HLIM_COMPR_1, + HLIM_COMPR_64, + HLIM_COMPR_255 + }; + + /** + * \brief Source or Destination Address Mode + * + * 00: 128 bits. + * 01: 64 bits (or 48 bits if multicast). + * 10: 16 bits (or 32 bits if multicast). + * 11: Fully elided (or 8 bits if multicast). + */ + enum HeaderCompression_e + { + HC_INLINE = 0, + HC_COMPR_64, + HC_COMPR_16, + HC_COMPR_0 + }; + + SixLowPanIphc (void); + /** + * \brief Constructor + * \param dispatch dispatch value + */ + SixLowPanIphc (uint8_t dispatch); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the Dispatch type. + * \return the Dispatch type + */ + // virtual Dispatch_e GetDispatchType (void) const; + + /** + * \brief Set the TF (Traffic Class, Flow Label) compression. + * \param tfField ECN, DSCP, Flow Label compression type + */ + void SetTf (TrafficClassFlowLabel_e tfField); + + /** + * \brief Get the TF (Traffic Class, Flow Label) compression. + * \return the ECN, DSCP, Flow Label compression type + */ + TrafficClassFlowLabel_e GetTf (void) const; + + /** + * \brief Set the NH (Next Header) compression. + * \param nhField false (Next Header carried in-line), true (compressed NH) + */ + void SetNh (bool nhField); + + /** + * \brief Get the NH (Next Header) compression. + * \return false (Next Header carried in-line), true (compressed NH) + */ + bool GetNh (void) const; + + /** + * \brief Set the HLIM (Hop Limit) compression. + * \param hlimField Hop Limit compression type + */ + void SetHlim (Hlim_e hlimField); + + /** + * \brief Get the HLIM (Hop Limit) compression. + * \return Hop Limit compression type + */ + Hlim_e GetHlim (void) const; + + /** + * \brief Set the CID (Context Identifier Extension) compression. + * \param cidField false (no CID present), true (CID follows) + */ + void SetCid (bool cidField); + + /** + * \brief Get the CID (Context Identifier Extension) compression. + * \return false (no CID present), true (CID follows) + */ + bool GetCid (void) const; + + /** + * \brief Set the SAC (Source Address Compression) compression. + * \param sacField false (stateless), true (stateful) + */ + void SetSac (bool sacField); + + /** + * \brief Get the SAC (Source Address Compression) compression. + * \return false (stateless), true (stateful) + */ + bool GetSac (void) const; + + /** + * \brief Set the SAM (Source Address Mode) compression. + * \param samField - depends on the SAC + */ + void SetSam (HeaderCompression_e samField); + + /** + * \brief Get the SAM (Source Address Mode) compression. + * \return depends on the SAC field + */ + HeaderCompression_e GetSam (void) const; + + /** + * \brief Set the M (Multicast) compression. + * \param mField true if destination is multicast + */ + void SetM (bool mField); + + /** + * \brief Get the M (Multicast) compression. + * \return true if destination is multicast + */ + bool GetM (void) const; + + /** + * \brief Set the DAC (Destination Address Compression) compression. + * \param dacField false (stateless), true (stateful) + */ + void SetDac (bool dacField); + + /** + * \brief Get the DAC (Destination Address Compression) compression. + * \return false (stateless), true (stateful) + */ + bool GetDac (void) const; + + /** + * \brief Set the DAM (Destination Address Mode) compression. + * \param damField - depends on the DAC and M fields + */ + void SetDam (HeaderCompression_e damField); + + /** + * \brief Get the DAM (Destination Address Mode) compression. + * \return depends on the DAC and M fields + */ + HeaderCompression_e GetDam (void) const; + + /** + * \brief Set the SrcContextId. + * \param srcContextId - valid values are [0:15] + */ + void SetSrcContextId (uint8_t srcContextId); + + /** + * \brief Get the SrcContextId. + * \return the SrcContextId + */ + uint8_t GetSrcContextId (void) const; + + /** + * \brief Set the DstContextId. + * \param dstContextId - valid values are [0:15] + */ + void SetDstContextId (uint8_t dstContextId); + + /** + * \brief Get the DstContextId. + * \return the DstContextId + */ + uint8_t GetDstContextId (void) const; + + /** + * \brief Set the ECN (2bits). + * \param ecn - valid values are [0:3] + */ + void SetEcn (uint8_t ecn); + + /** + * \brief Get the ECN. + * \return the ECN + */ + uint8_t GetEcn (void) const; + + /** + * \brief Set the DSCP (6bits). + * \param dscp - valid values are [0:63] + */ + void SetDscp (uint8_t dscp); + + /** + * \brief Get the DSCP. + * \return the DSCP + */ + uint8_t GetDscp (void) const; + + /** + * \brief Set the Flow Label (20bits). + * \param flowLabel - valid values are 20 bits long. + */ + void SetFlowLabel (uint32_t flowLabel); + + /** + * \brief Get the Flow Label. + * \return the Flow Label + */ + uint32_t GetFlowLabel (void) const; + + /** + * \brief Set the Next Header field. + * \param nextHeader Next Header field. + */ + void SetNextHeader (uint8_t nextHeader); + + /** + * \brief Get the Next Header field. + * \return the Next Header field. + */ + uint8_t GetNextHeader (void) const; + + /** + * \brief Set the Hop Limit field. + * \param hopLimit Hop Limit field. + */ + void SetHopLimit (uint8_t hopLimit); + + /** + * \brief Get the Hop Limit field. + * \return the Hop Limit field. + */ + uint8_t GetHopLimit (void) const; + + /** + * \brief Set the Source Address. + * \param srcAddress the Source Address. + */ + void SetSrcAddress (Ipv6Address srcAddress); + + /** + * \brief Get the Source Address. + * \return the Source Address. + */ + Ipv6Address GetSrcAddress () const; + + /** + * \brief Set the Destination Address. + * \param dstAddress the Destination Address. + */ + void SetDstAddress (Ipv6Address dstAddress); + + /** + * \brief Get the Destination Address. + * \return the Destination Address. + */ + Ipv6Address GetDstAddress () const; + +private: + uint16_t m_baseFormat; //!< Dispatch + encoding fields + uint8_t m_srcdstContextId; //!< Src and Dst Context ID + uint8_t m_ecn : 2; //!< ECN bits + uint8_t m_dscp : 6; //!< DSCP bits + uint32_t m_flowLabel : 20; //!< Flow Label bits + uint8_t m_nextHeader; //!< Next header + uint8_t m_hopLimit; //!< Hop Limit + Ipv6Address m_srcAddress; //!< Src address + Ipv6Address m_dstAddress; //!< Dst address + + /** + * \brief Post-process the Source address stateful compression + * \note currently unsupported + */ + void PostProcessSac (); + /** + * \brief Post-process the Destination address stateful compression + * \note currently unsupported + */ + void PostProcessDac (); + +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the IPHC Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanIphc const &header); + +/** +* \ingroup sixlowpan +* \brief LOWPAN_NHC Extension Header Encoding - see RFC 6262 + \verbatim + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | 1 | 1 | 1 | 0 | EID |NH | + +---+---+---+---+---+---+---+---+ + \endverbatim +*/ +class SixLowPanNhcExtension : public Header +{ +public: + /** + * \brief EID: IPv6 Extension Header ID + * + * EID: IPv6 Extension Header ID: + * 0: IPv6 Hop-by-Hop Options Header [RFC2460] + * 1: IPv6 Routing Header [RFC2460] + * 2: IPv6 Fragment Header [RFC2460] + * 3: IPv6 Destination Options Header [RFC2460] + * 4: IPv6 Mobility Header [RFC6275] + * 5: Reserved + * 6: Reserved + * 7: IPv6 Header + */ + enum Eid_e + { + EID_HOPBYHOP_OPTIONS_H = 0, + EID_ROUTING_H, + EID_FRAGMENTATION_H, + EID_DESTINATION_OPTIONS_H, + EID_MOBILITY_H, + EID_IPv6_H = 7 + }; + + SixLowPanNhcExtension (void); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the NhcDispatch type. + * \return the NhcDispatch type + */ + virtual SixLowPanDispatch::NhcDispatch_e GetNhcDispatchType (void) const; + + /** + * \brief Set the Extension Header Type. + * \param extensionHeaderType the Extension Header Type + */ + void SetEid (Eid_e extensionHeaderType); + + /** + * \brief Get the Extension Header Type. + * \return the Extension Header Type + */ + Eid_e GetEid (void) const; + + /** + * \brief Set the Next Header field values. + * \param nextHeader the Next Header field value + */ + void SetNextHeader (uint8_t nextHeader); + + /** + * \brief Get the Next Header field value. + * \return the Next Header field value + */ + uint8_t GetNextHeader (void) const; + + /** + * \brief Set the NH field values. + * \param nhField the NH field value + */ + void SetNh (bool nhField); + + /** + * \brief Get the Next Header field value. + * \return the NH field value + */ + bool GetNh (void) const; + + /** + * \brief Set the option header data blob. + * \param blob a buffer holding the blob data + * \param size the data blob size + */ + void SetBlob (const uint8_t* blob, uint32_t size); + + /** + * \brief Get the option header data blob. + * \param blob a buffer to copy the blob data into + * \param size the size of the buffer + * \return the length of the copied data + */ + uint32_t CopyBlob (uint8_t* blob, uint32_t size) const; + +private: + uint8_t m_nhcExtensionHeader; //!< NHC extension header type + uint8_t m_nhcNextHeader; //!< Next header + uint8_t m_nhcBlobLength; //!< Length of the NHC compressed header + uint8_t m_nhcBlob[256]; //!< NHC compressed header +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the NHC Extension Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanNhcExtension const &header); + + +/** +* \ingroup sixlowpan +* \brief UDP LOWPAN_NHC Extension Header Encoding - see RFC 6262 + \verbatim + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | 1 | 1 | 1 | 1 | 0 | C | P | + +---+---+---+---+---+---+---+---+ + \endverbatim +*/ +class SixLowPanUdpNhcExtension : public Header +{ +public: + /** + * \brief Ports: + * + * 00: 16 bits for both Source Port and Destination Port + * 01: 16 bits for Source Port. Last 8 bits for Destination Port + * 10: Last 8 bits for Source Port. All 16 bits for Destination Port + * 11: Last 4 bits of both Source Port and Destination Port + */ + enum Ports_e + { + PORTS_INLINE = 0, + PORTS_ALL_SRC_LAST_DST, + PORTS_LAST_SRC_ALL_DST, + PORTS_LAST_SRC_LAST_DST + }; + + SixLowPanUdpNhcExtension (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + static TypeId GetTypeId (void); + + /** + * \brief Return the instance type identifier. + * \return instance type ID + */ + virtual TypeId GetInstanceTypeId (void) const; + + virtual void Print (std::ostream& os) const; + + /** + * \brief Get the serialized size of the packet. + * \return size + */ + virtual uint32_t GetSerializedSize (void) const; + + /** + * \brief Serialize the packet. + * \param start Buffer iterator + */ + virtual void Serialize (Buffer::Iterator start) const; + + /** + * \brief Deserialize the packet. + * \param start Buffer iterator + * \return size of the packet + */ + virtual uint32_t Deserialize (Buffer::Iterator start); + + /** + * \brief Get the NhcDispatch type. + * \return the NhcDispatch type + */ + virtual SixLowPanDispatch::NhcDispatch_e GetNhcDispatchType (void) const; + + /** + * \brief Set the compressed Src and Dst Ports. + * \param port Src and Dst the Ports + */ + void SetPorts (Ports_e port); + + /** + * \brief Get the compressed Src and Dst Ports. + * \return the Src and Dst Ports + */ + Ports_e GetPorts (void) const; + + /** + * \brief Set the Destination Port. + * \param port the Destination Port. + */ + void SetSrcPort (uint16_t port); + + /** + * \brief Get the Destination Port. + * \return the Destination Port. + */ + uint16_t GetSrcPort () const; + + /** + * \brief Set the Destination Port. + * \param port the Destination Port. + */ + void SetDstPort (uint16_t port); + + /** + * \brief Get the Destination Port. + * \return the Destination Port. + */ + uint16_t GetDstPort () const; + + /** + * \brief Set the C (Checksum). + * \param cField false (All checksum carried in-line), true (Checksum elided) + */ + void SetC (bool cField); + + /** + * \brief Get the C (Checksum). + * \return false (All checksum carried in-line), true (Checksum elided) + */ + bool GetC (void) const; + + /** + * \brief Set the Checksum field values. + * \param checksum the Checksum field value + */ + void SetChecksum (uint16_t checksum); + + /** + * \brief Get the Checksum field value. + * \return the Checksum field value + */ + uint16_t GetChecksum (void) const; + +private: + uint8_t m_baseFormat; //!< Dispatch + encoding fields + uint16_t m_checksum; //!< Checksum + uint16_t m_srcPort; //!< Source port + uint16_t m_dstPort; //!< Destination port +}; + +/** + * \brief Stream insertion operator. + * + * \param os the reference to the output stream + * \param header the UDP NHC Extension Header + * \returns the reference to the output stream + */ +std::ostream & operator<< (std::ostream & os, SixLowPanUdpNhcExtension const &header); + +} + +#endif /* SIXLOWPANHEADER_H_ */ diff --git a/src/sixlowpan/model/sixlowpan-net-device.cc b/src/sixlowpan/model/sixlowpan-net-device.cc new file mode 100644 index 000000000..8b945956a --- /dev/null +++ b/src/sixlowpan/model/sixlowpan-net-device.cc @@ -0,0 +1,2118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + * Michele Muccio + */ + +#include "ns3/node.h" +#include "ns3/channel.h" +#include "ns3/packet.h" +#include "ns3/log.h" +#include "ns3/boolean.h" +#include "ns3/abort.h" +#include "ns3/simulator.h" +#include "ns3/uinteger.h" +#include "ns3/icmpv6-header.h" +#include "ns3/ipv6-header.h" +#include "ns3/random-variable.h" +#include "ns3/mac16-address.h" +#include "ns3/mac48-address.h" +#include "ns3/mac64-address.h" +#include "ns3/unused.h" +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/ipv6-extension-header.h" +#include "ns3/udp-header.h" +#include "ns3/udp-l4-protocol.h" +#include "sixlowpan-net-device.h" +#include "sixlowpan-header.h" + +NS_LOG_COMPONENT_DEFINE ("SixLowPanNetDevice") + ; + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (SixLowPanNetDevice) + ; + +TypeId SixLowPanNetDevice::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SixLowPanNetDevice") + .SetParent () + .AddConstructor () + .AddAttribute ("Rfc6282", "Use RFC6282 (IPHC) if true, RFC4944 (HC1) otherwise.", + BooleanValue (true), + MakeBooleanAccessor (&SixLowPanNetDevice::m_useIphc), + MakeBooleanChecker ()) + .AddAttribute ("OmitUdpChecksum", + "Omit the UDP checksum in IPHC compression.", + BooleanValue (true), + MakeBooleanAccessor (&SixLowPanNetDevice::m_omitUdpChecksum), + MakeBooleanChecker ()) + .AddAttribute ("FragmentReassemblyListSize", "The maximum size of the reassembly buffer (in packets). Zero meaning infinite.", + UintegerValue (0), + MakeUintegerAccessor (&SixLowPanNetDevice::m_fragmentReassemblyListSize), + MakeUintegerChecker ()) + .AddAttribute ("FragmentExpirationTimeout", + "When this timeout expires, the fragments will be cleared from the buffer.", + TimeValue (Seconds (60)), + MakeTimeAccessor (&SixLowPanNetDevice::m_fragmentExpirationTimeout), + MakeTimeChecker ()) + .AddAttribute ("ForceEtherType", + "Force a specific EtherType in L2 frames.", + BooleanValue (false), + MakeBooleanAccessor (&SixLowPanNetDevice::m_forceEtherType), + MakeBooleanChecker ()) + .AddAttribute ("EtherType", + "The specific EtherType to be used in L2 frames.", + UintegerValue (0xFFFF), + MakeUintegerAccessor (&SixLowPanNetDevice::m_etherType), + MakeUintegerChecker ()) + .AddTraceSource ("Tx", "Send - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.", + MakeTraceSourceAccessor (&SixLowPanNetDevice::m_txTrace)) + .AddTraceSource ("Rx", "Receive - packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.", + MakeTraceSourceAccessor (&SixLowPanNetDevice::m_rxTrace)) + .AddTraceSource ("Drop", "Drop - DropReason, packet (including 6LoWPAN header), SixLoWPanNetDevice Ptr, interface index.", + MakeTraceSourceAccessor (&SixLowPanNetDevice::m_dropTrace)) + ; + return tid; +} + +SixLowPanNetDevice::SixLowPanNetDevice () + : m_node (0), + m_netDevice (0), + m_ifIndex (0) +{ + NS_LOG_FUNCTION (this); + m_netDevice = 0; + m_rng = CreateObject (); +} + +Ptr SixLowPanNetDevice::GetNetDevice () const +{ + NS_LOG_FUNCTION (this); + return m_netDevice; +} + +void SixLowPanNetDevice::SetNetDevice (Ptr device) +{ + NS_LOG_FUNCTION (this << device); + m_netDevice = device; + + NS_LOG_DEBUG ("RegisterProtocolHandler for " << device->GetInstanceTypeId ().GetName ()); + + uint16_t protocolType = 0; + if ( m_forceEtherType ) + { + protocolType = m_etherType; + } + m_node->RegisterProtocolHandler (MakeCallback (&SixLowPanNetDevice::ReceiveFromDevice, + this), + protocolType, device, false); +} + +int64_t SixLowPanNetDevice::AssignStreams (int64_t stream) +{ + NS_LOG_FUNCTION (this << stream); + m_rng->SetStream (stream); + return 1; +} + +void SixLowPanNetDevice::DoDispose () +{ + NS_LOG_FUNCTION (this); + + m_netDevice = 0; + m_node = 0; + + for (MapFragmentsTimersI_t iter = m_fragmentsTimers.begin (); iter != m_fragmentsTimers.end (); iter++) + { + iter->second.Cancel (); + } + m_fragmentsTimers.clear (); + + for (MapFragmentsI_t iter = m_fragments.begin (); iter != m_fragments.end (); iter++) + { + iter->second = 0; + } + m_fragments.clear (); + + NetDevice::DoDispose (); +} + +void SixLowPanNetDevice::ReceiveFromDevice (Ptr incomingPort, + Ptr packet, + uint16_t protocol, + Address const &src, + Address const &dst, + PacketType packetType) +{ + NS_LOG_FUNCTION (this << incomingPort << packet << protocol << src << dst); + NS_LOG_DEBUG ("UID is " << packet->GetUid ()); + + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::Dispatch_e dispatchVal; + Ptr copyPkt = packet->Copy (); + + m_rxTrace (copyPkt, m_node->GetObject (), GetIfIndex ()); + + copyPkt->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetDispatchType (dispatchRawVal); + bool isPktDecompressed = false; + bool fragmented = false; + + NS_LOG_DEBUG ( "Packet received: " << *copyPkt ); + NS_LOG_DEBUG ( "Packet length: " << copyPkt->GetSize () ); + NS_LOG_DEBUG ( "Dispatches: " << int(dispatchRawVal) << " - " << int(dispatchVal) ); + + if ( dispatchVal == SixLowPanDispatch::LOWPAN_FRAG1 ) + { + isPktDecompressed = ProcessFragment (copyPkt, src, dst, true); + fragmented = true; + } + else if ( dispatchVal == SixLowPanDispatch::LOWPAN_FRAGN ) + { + isPktDecompressed = ProcessFragment (copyPkt, src, dst, false); + fragmented = true; + } + if ( fragmented ) + { + if ( !isPktDecompressed ) + { + return; + } + else + { + copyPkt->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetDispatchType (dispatchRawVal); + } + } + + switch ( dispatchVal ) + { + case SixLowPanDispatch::LOWPAN_MESH: + NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: MESH, dropping."); + m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); + break; + case SixLowPanDispatch::LOWPAN_BC0: + NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: BC0, dropping."); + m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); + break; + case SixLowPanDispatch::LOWPAN_NOTCOMPRESSED: + NS_LOG_DEBUG ( "Packet without compression:" << *copyPkt ); + NS_LOG_DEBUG ( "Packet length:" << copyPkt->GetSize () ); + m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); + break; + case SixLowPanDispatch::LOWPAN_HC1: + DecompressLowPanHc1 (copyPkt, src, dst); + isPktDecompressed = true; + break; + case SixLowPanDispatch::LOWPAN_IPHC: + DecompressLowPanIphc (copyPkt, src, dst); + isPktDecompressed = true; + break; + default: + NS_LOG_DEBUG ("Unsupported 6LoWPAN encoding: dropping."); + m_dropTrace (DROP_UNKNOWN_EXTENSION, copyPkt, m_node->GetObject (), GetIfIndex ()); + break; + } + + if ( !isPktDecompressed ) + { + return; + } + + NS_LOG_DEBUG ( "Packet decompressed length: " << copyPkt->GetSize () ); + NS_LOG_DEBUG ( "Packet decompressed received: " << *copyPkt ); + + if (!m_promiscRxCallback.IsNull ()) + { + m_promiscRxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, src, dst, packetType); + } + + m_rxCallback (this, copyPkt, Ipv6L3Protocol::PROT_NUMBER, src); + + return; +} + +void SixLowPanNetDevice::SetIfIndex (const uint32_t index) +{ + NS_LOG_FUNCTION (this << index); + // NS_ASSERT_MSG ( m_port != 0, "Sixlowpan: can't find any lower-layer protocol " << m_port ); + m_ifIndex = index; +} + +uint32_t SixLowPanNetDevice::GetIfIndex (void) const +{ + NS_LOG_FUNCTION (this); + // NS_ASSERT_MSG ( m_port != 0, "Sixlowpan: can't find any lower-layer protocol " << m_port ); + return m_netDevice->GetIfIndex (); +} + +Ptr SixLowPanNetDevice::GetChannel (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->GetChannel (); +} + +void SixLowPanNetDevice::SetAddress (Address address) +{ + NS_LOG_FUNCTION (this << address); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + m_netDevice->SetAddress (address); +} + +Address SixLowPanNetDevice::GetAddress (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->GetAddress (); +} + +bool SixLowPanNetDevice::SetMtu (const uint16_t mtu) +{ + NS_LOG_FUNCTION (this << mtu); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->SetMtu (mtu); +} + +uint16_t SixLowPanNetDevice::GetMtu (void) const +{ + NS_LOG_FUNCTION (this); + + uint16_t mtu = m_netDevice->GetMtu (); + + // RFC 4944, section 4. + if (mtu < 1280) + { + mtu = 1280; + } + return mtu; +} + +bool SixLowPanNetDevice::IsLinkUp (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->IsLinkUp (); +} + +void SixLowPanNetDevice::AddLinkChangeCallback (Callback callback) +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->AddLinkChangeCallback (callback); +} + +bool SixLowPanNetDevice::IsBroadcast (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->IsBroadcast (); +} + +Address SixLowPanNetDevice::GetBroadcast (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->GetBroadcast (); +} + +bool SixLowPanNetDevice::IsMulticast (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->IsMulticast (); +} + +Address SixLowPanNetDevice::GetMulticast (Ipv4Address multicastGroup) const +{ + NS_LOG_FUNCTION (this << multicastGroup); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->GetMulticast (multicastGroup); +} + +Address SixLowPanNetDevice::GetMulticast (Ipv6Address addr) const +{ + NS_LOG_FUNCTION (this << addr); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->GetMulticast (addr); +} + +bool SixLowPanNetDevice::IsPointToPoint (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->IsPointToPoint (); +} + +bool SixLowPanNetDevice::IsBridge (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->IsBridge (); +} + +bool SixLowPanNetDevice::Send (Ptr packet, + const Address& dest, + uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (this << *packet << dest << protocolNumber); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + uint32_t origHdrSize = 0; + uint32_t origPacketSize = packet->GetSize (); + bool ret = false; + + if (m_forceEtherType) + { + protocolNumber = m_etherType; + } + + if (m_useIphc) + { + origHdrSize += CompressLowPanIphc (packet, m_netDevice->GetAddress (), dest); + } + else + { + origHdrSize += CompressLowPanHc1 (packet, m_netDevice->GetAddress (), dest); + } + + if ( packet->GetSize () > m_netDevice->GetMtu () ) + { + NS_LOG_LOGIC ("Fragmentation: Packet size " << packet->GetSize () << " - Mtu " << m_netDevice->GetMtu () ); + // fragment + std::list > fragmentList; + DoFragmentation (packet, origPacketSize, origHdrSize, fragmentList); + std::list >::iterator it; + bool success = true; + for ( it = fragmentList.begin (); it != fragmentList.end (); it++ ) + { + NS_LOG_DEBUG ( "SixLowPanNetDevice::Send (Fragment) " << **it ); + m_txTrace (*it, m_node->GetObject (), GetIfIndex ()); + success &= m_netDevice->Send (*it, dest, protocolNumber); + } + ret = success; + } + else + { + NS_LOG_DEBUG ( "SixLowPanNetDevice::Send " << m_node->GetId () << " " << *packet ); + m_txTrace (packet, m_node->GetObject (), GetIfIndex ()); + ret = m_netDevice->Send (packet, dest, protocolNumber); + } + + return ret; +} + +bool SixLowPanNetDevice::SendFrom (Ptr packet, + const Address& src, + const Address& dest, + uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (this << packet << src << dest << protocolNumber); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + uint32_t origHdrSize = 0; + uint32_t origPacketSize = packet->GetSize (); + bool ret = false; + + if (m_forceEtherType) + { + protocolNumber = m_etherType; + } + + if (m_useIphc) + { + origHdrSize += CompressLowPanIphc (packet, m_netDevice->GetAddress (), dest); + } + else + { + origHdrSize += CompressLowPanHc1 (packet, m_netDevice->GetAddress (), dest); + } + + if ( packet->GetSize () > m_netDevice->GetMtu () ) + { + // fragment + std::list > fragmentList; + DoFragmentation (packet, origPacketSize, origHdrSize, fragmentList); + std::list >::iterator it; + bool err = false; + for ( it = fragmentList.begin (); it != fragmentList.end (); it++ ) + { + NS_LOG_DEBUG ( "SixLowPanNetDevice::SendFrom (Fragment) " << **it ); + m_txTrace (*it, m_node->GetObject (), GetIfIndex ()); + err |= !(m_netDevice->SendFrom (*it, src, dest, protocolNumber)); + } + ret = !err; + } + else + { + NS_LOG_DEBUG ( "SixLowPanNetDevice::SendFrom " << *packet ); + m_txTrace (packet, m_node->GetObject (), GetIfIndex ()); + ret = m_netDevice->SendFrom (packet, src, dest, protocolNumber); + } + + return ret; +} + +Ptr SixLowPanNetDevice::GetNode (void) const +{ + NS_LOG_FUNCTION (this); + return m_node; +} + +void SixLowPanNetDevice::SetNode (Ptr node) +{ + NS_LOG_FUNCTION (this << node); + m_node = node; +} + +bool SixLowPanNetDevice::NeedsArp (void) const +{ + NS_LOG_FUNCTION (this); + NS_ASSERT_MSG ( m_netDevice != 0, "Sixlowpan: can't find any lower-layer protocol " << m_netDevice ); + + return m_netDevice->NeedsArp (); +} + +void SixLowPanNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) +{ + NS_LOG_FUNCTION (this << &cb); + m_rxCallback = cb; +} + +void SixLowPanNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb) +{ + NS_LOG_FUNCTION (this << &cb); + m_promiscRxCallback = cb; +} + +bool SixLowPanNetDevice::SupportsSendFrom () const +{ + NS_LOG_FUNCTION (this); + return true; +} + +uint32_t +SixLowPanNetDevice::CompressLowPanHc1 (Ptr packet, Address const &src, Address const &dst) +{ + NS_LOG_FUNCTION (this << *packet << src << dst); + + Ipv6Header ipHeader; + SixLowPanHc1 hc1Header; + uint32_t size = 0; + + if ( packet->PeekHeader (ipHeader) != 0 ) + { + packet->RemoveHeader (ipHeader); + size += ipHeader.GetSerializedSize (); + + hc1Header.SetHopLimit (ipHeader.GetHopLimit ()); + + uint8_t bufOne[16]; + uint8_t bufTwo[16]; + Ipv6Address srcAddr = ipHeader.GetSourceAddress (); + srcAddr.GetBytes (bufOne); + Ipv6Address mySrcAddr = MakeLinkLocalAddressFromMac (src); + + NS_LOG_LOGIC ("Checking source compression: " << mySrcAddr << " - " << srcAddr ); + + mySrcAddr.GetBytes (bufTwo); + bool isSrcSrc = (memcmp (bufOne + 8, bufTwo + 8, 8) == 0); + + if (srcAddr.IsLinkLocal () && isSrcSrc ) + { + hc1Header.SetSrcCompression (SixLowPanHc1::HC1_PCIC); + } + else if (srcAddr.IsLinkLocal () ) + { + hc1Header.SetSrcCompression (SixLowPanHc1::HC1_PCII); + hc1Header.SetSrcInterface (bufOne + 8); + } + else if ( isSrcSrc ) + { + hc1Header.SetSrcCompression (SixLowPanHc1::HC1_PIIC); + hc1Header.SetSrcPrefix (bufOne); + } + else + { + hc1Header.SetSrcCompression (SixLowPanHc1::HC1_PIII); + hc1Header.SetSrcInterface (bufOne + 8); + hc1Header.SetSrcPrefix (bufOne); + } + + Ipv6Address dstAddr = ipHeader.GetDestinationAddress (); + dstAddr.GetBytes (bufOne); + Ipv6Address myDstAddr = MakeLinkLocalAddressFromMac (dst); + + NS_LOG_LOGIC ("Checking destination compression: " << myDstAddr << " - " << dstAddr ); + + myDstAddr.GetBytes (bufTwo); + bool isDstDst = (memcmp (bufOne + 8, bufTwo + 8, 8) == 0); + + if (dstAddr.IsLinkLocal () && isDstDst ) + { + hc1Header.SetDstCompression (SixLowPanHc1::HC1_PCIC); + } + else if (dstAddr.IsLinkLocal () ) + { + hc1Header.SetDstCompression (SixLowPanHc1::HC1_PCII); + hc1Header.SetDstInterface (bufOne + 8); + } + else if ( isDstDst ) + { + hc1Header.SetDstCompression (SixLowPanHc1::HC1_PIIC); + hc1Header.SetDstPrefix (bufOne); + } + else + { + hc1Header.SetDstCompression (SixLowPanHc1::HC1_PIII); + hc1Header.SetDstInterface (bufOne + 8); + hc1Header.SetDstPrefix (bufOne); + } + + if ( (ipHeader.GetFlowLabel () == 0) && (ipHeader.GetTrafficClass () == 0) ) + { + hc1Header.SetTcflCompression (true); + } + else + { + hc1Header.SetTcflCompression (false); + hc1Header.SetTrafficClass (ipHeader.GetTrafficClass ()); + hc1Header.SetFlowLabel (ipHeader.GetFlowLabel ()); + } + + uint8_t nextHeader = ipHeader.GetNextHeader (); + hc1Header.SetNextHeader (nextHeader); + + // \todo implement HC2 compression + hc1Header.SetHc2HeaderPresent (false); + + NS_LOG_DEBUG ("HC1 Compression - HC1 header size = " << hc1Header.GetSerializedSize () ); + NS_LOG_DEBUG ("HC1 Compression - packet size = " << packet->GetSize () ); + + packet->AddHeader (hc1Header); + + return size; + } + + return 0; +} + +void +SixLowPanNetDevice::DecompressLowPanHc1 (Ptr packet, Address const &src, Address const &dst) +{ + NS_LOG_FUNCTION (this << *packet << src << dst); + + Ipv6Header ipHeader; + SixLowPanHc1 encoding; + + uint32_t ret = packet->RemoveHeader (encoding); + NS_LOG_DEBUG ("removed " << ret << " bytes - pkt is " << *packet); + NS_UNUSED (ret); + + ipHeader.SetHopLimit (encoding.GetHopLimit ()); + + switch (encoding.GetSrcCompression ()) + { + const uint8_t* interface; + const uint8_t* prefix; + uint8_t address[16]; + + case SixLowPanHc1::HC1_PIII: + prefix = encoding.GetSrcPrefix (); + interface = encoding.GetSrcInterface (); + for (int j = 0; j < 8; j++) + { + address[j + 8] = interface[j]; + address[j] = prefix[j]; + } + ipHeader.SetSourceAddress ( Ipv6Address (address) ); + break; + case SixLowPanHc1::HC1_PIIC: + prefix = encoding.GetSrcPrefix (); + for (int j = 0; j < 8; j++) + { + address[j + 8] = 0; + address[j] = prefix[j]; + } + ipHeader.SetSourceAddress ( MakeGlobalAddressFromMac (src, Ipv6Address (address))); + break; + case SixLowPanHc1::HC1_PCII: + interface = encoding.GetSrcInterface (); + address[0] = 0xfe; + address[1] = 0x80; + for (int j = 0; j < 8; j++) + { + address[j + 8] = interface[j]; + } + ipHeader.SetSourceAddress ( Ipv6Address (address) ); + break; + case SixLowPanHc1::HC1_PCIC: + ipHeader.SetSourceAddress (MakeLinkLocalAddressFromMac (src)); + break; + } + + switch (encoding.GetDstCompression ()) + { + const uint8_t* interface; + const uint8_t* prefix; + uint8_t address[16]; + + case SixLowPanHc1::HC1_PIII: + prefix = encoding.GetDstPrefix (); + interface = encoding.GetDstInterface (); + for (int j = 0; j < 8; j++) + { + address[j + 8] = interface[j]; + address[j] = prefix[j]; + } + ipHeader.SetDestinationAddress ( Ipv6Address (address) ); + break; + case SixLowPanHc1::HC1_PIIC: + prefix = encoding.GetDstPrefix (); + for (int j = 0; j < 8; j++) + { + address[j + 8] = 0; + address[j] = prefix[j]; + } + ipHeader.SetDestinationAddress ( MakeGlobalAddressFromMac (dst, Ipv6Address (address))); + break; + case SixLowPanHc1::HC1_PCII: + interface = encoding.GetDstInterface (); + address[0] = 0xfe; + address[1] = 0x80; + for (int j = 0; j < 8; j++) + { + address[j + 8] = interface[j]; + } + ipHeader.SetDestinationAddress ( Ipv6Address (address) ); + break; + case SixLowPanHc1::HC1_PCIC: + ipHeader.SetDestinationAddress (MakeLinkLocalAddressFromMac (dst)); + break; + } + + if ( !encoding.IsTcflCompression () ) + { + ipHeader.SetFlowLabel (encoding.GetFlowLabel ()); + ipHeader.SetTrafficClass (encoding.GetTrafficClass ()); + } + else + { + ipHeader.SetFlowLabel (0); + ipHeader.SetTrafficClass (0); + } + + ipHeader.SetNextHeader (encoding.GetNextHeader ()); + + ipHeader.SetPayloadLength (packet->GetSize ()); + + NS_ASSERT_MSG (encoding.IsHc2HeaderPresent () == false, + "6LoWPAN: error in decompressing HC1 encoding, unsupported L4 compressed header present."); + + packet->AddHeader (ipHeader); + + NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () ); +} + +uint32_t +SixLowPanNetDevice::CompressLowPanIphc (Ptr packet, Address const &src, Address const &dst) +{ + NS_LOG_FUNCTION (this << *packet << src << dst); + + Ipv6Header ipHeader; + SixLowPanIphc iphcHeader; + uint32_t size = 0; + + + if ( packet->PeekHeader (ipHeader) != 0 ) + { + packet->RemoveHeader (ipHeader); + size += ipHeader.GetSerializedSize (); + + // Set the TF field + if ( (ipHeader.GetFlowLabel () == 0) && (ipHeader.GetTrafficClass () == 0) ) + { + iphcHeader.SetTf (SixLowPanIphc::TF_ELIDED); + } + else if ( (ipHeader.GetFlowLabel () != 0) && (ipHeader.GetTrafficClass () != 0) ) + { + iphcHeader.SetTf (SixLowPanIphc::TF_FULL); + iphcHeader.SetEcn ( (ipHeader.GetTrafficClass () & 0xC0) >> 6); + iphcHeader.SetDscp ( ipHeader.GetTrafficClass () & 0x3F ); + iphcHeader.SetFlowLabel (ipHeader.GetFlowLabel ()); + } + else if ( (ipHeader.GetFlowLabel () == 0) && (ipHeader.GetTrafficClass () != 0) ) + { + iphcHeader.SetTf (SixLowPanIphc::TF_FL_ELIDED); + iphcHeader.SetEcn ( (ipHeader.GetTrafficClass () & 0xC0) >> 6); + iphcHeader.SetDscp ( ipHeader.GetTrafficClass () & 0x3F ); + } + else + { + iphcHeader.SetTf (SixLowPanIphc::TF_DSCP_ELIDED); + iphcHeader.SetEcn ( (ipHeader.GetTrafficClass () & 0xC0) >> 6); + iphcHeader.SetFlowLabel (ipHeader.GetFlowLabel ()); + } + + // Set the NH field and NextHeader + + uint8_t nextHeader = ipHeader.GetNextHeader (); + if (CanCompressLowPanNhc (nextHeader)) + { + if (nextHeader == Ipv6Header::IPV6_UDP) + { + iphcHeader.SetNh (true); + size += CompressLowPanUdpNhc (packet, m_omitUdpChecksum); + } + else if (nextHeader == Ipv6Header::IPV6_IPV6) + { + iphcHeader.SetNh (true); + size += CompressLowPanIphc (packet, src, dst); + } + else + { + uint32_t sizeNhc = CompressLowPanNhc (packet, nextHeader, src, dst); + // the compression might fail due to Extension header size. + if (sizeNhc) + { + iphcHeader.SetNh (true); + size += sizeNhc; + } + else + { + iphcHeader.SetNh (false); + iphcHeader.SetNextHeader (nextHeader); + } + } + } + else + { + iphcHeader.SetNh (false); + iphcHeader.SetNextHeader (nextHeader); + } + + + // Set the HLIM field + if (ipHeader.GetHopLimit () == 1) + { + iphcHeader.SetHlim (SixLowPanIphc::HLIM_COMPR_1); + } + else if (ipHeader.GetHopLimit () == 0x40) + { + iphcHeader.SetHlim (SixLowPanIphc::HLIM_COMPR_64); + } + else if (ipHeader.GetHopLimit () == 0xFF) + { + iphcHeader.SetHlim (SixLowPanIphc::HLIM_COMPR_255); + } + else + { + iphcHeader.SetHlim (SixLowPanIphc::HLIM_INLINE); + // Set the HopLimit + iphcHeader.SetHopLimit (ipHeader.GetHopLimit ()); + } + + // \todo Add the check of CID if there is context-based compression + // Set the CID field + iphcHeader.SetCid (false); + + // \todo Add the check of SAC if there is context-based compression + // Set the SAC field + iphcHeader.SetSac (false); + + uint8_t addressBuf[16]; + uint8_t unicastAddrCheckerBuf[16]; + Ipv6Address srcAddr = ipHeader.GetSourceAddress (); + srcAddr.GetBytes (addressBuf); + + Ipv6Address checker = Ipv6Address ("fe80:0000:0000:0000:0000:00ff:fe00:1"); + checker.GetBytes (unicastAddrCheckerBuf); + + // \todo Add the check of SAC if there is context-based compression + // Set the Source Address + iphcHeader.SetSrcAddress (srcAddr); + + Ipv6Address mySrcAddr = MakeLinkLocalAddressFromMac (src); + NS_LOG_LOGIC ("Checking source compression: " << mySrcAddr << " - " << srcAddr ); + + if ( mySrcAddr == srcAddr ) + { + iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_0); + } + else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0) + { + iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_16); + } + else if ( srcAddr.IsLinkLocal () ) + { + iphcHeader.SetSam (SixLowPanIphc::HC_COMPR_64); + } + else + { + iphcHeader.SetSam (SixLowPanIphc::HC_INLINE); + } + + // Set the M field + if (ipHeader.GetDestinationAddress ().IsMulticast ()) + { + iphcHeader.SetM (true); + } + else + { + iphcHeader.SetM (false); + } + + // \todo Add the check of DAC if there is context-based compression + // Set the DAC field + iphcHeader.SetDac (false); + + Ipv6Address dstAddr = ipHeader.GetDestinationAddress (); + dstAddr.GetBytes (addressBuf); + + // \todo Add the check of DAC if there is context-based compression + // Set the Destination Address + iphcHeader.SetDstAddress (dstAddr); + + Ipv6Address myDstAddr = MakeLinkLocalAddressFromMac (dst); + NS_LOG_LOGIC ("Checking destination compression: " << myDstAddr << " - " << dstAddr ); + + if ( !iphcHeader.GetM () ) + // Unicast address + { + if ( myDstAddr == dstAddr ) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0); + } + else if (memcmp (addressBuf, unicastAddrCheckerBuf, 14) == 0) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16); + } + else if ( dstAddr.IsLinkLocal () ) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64); + } + else + { + iphcHeader.SetDam (SixLowPanIphc::HC_INLINE); + } + } + else + { + // Multicast address + uint8_t multicastAddrCheckerBuf[16]; + Ipv6Address multicastCheckAddress = Ipv6Address ("ff02::1"); + multicastCheckAddress.GetBytes (multicastAddrCheckerBuf); + + // The address takes the form ff02::00XX. + if ( memcmp (addressBuf, multicastAddrCheckerBuf, 15) == 0 ) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_0); + } + // The address takes the form ffXX::00XX:XXXX. + // ffXX:0000:0000:0000:0000:0000:00XX:XXXX. + else if ( (addressBuf[0] == multicastAddrCheckerBuf[0]) + && (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 11) ) ) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_16); + } + // The address takes the form ffXX::00XX:XXXX:XXXX. + // ffXX:0000:0000:0000:0000:00XX:XXXX:XXXX. + else if ( (addressBuf[0] == multicastAddrCheckerBuf[0]) + && (memcmp (addressBuf + 2, multicastAddrCheckerBuf + 2, 9) ) ) + { + iphcHeader.SetDam (SixLowPanIphc::HC_COMPR_64); + } + else + { + iphcHeader.SetDam (SixLowPanIphc::HC_INLINE); + } + } + + NS_LOG_DEBUG ("IPHC Compression - IPHC header size = " << iphcHeader.GetSerializedSize () ); + NS_LOG_DEBUG ("IPHC Compression - packet size = " << packet->GetSize () ); + + packet->AddHeader (iphcHeader); + + NS_LOG_DEBUG ("Packet after IPHC compression: " << *packet); + + return size; + } + + return 0; +} + +bool +SixLowPanNetDevice::CanCompressLowPanNhc (uint8_t nextHeader) +{ + bool ret = false; + + switch (nextHeader) + { + case Ipv6Header::IPV6_UDP: + case Ipv6Header::IPV6_EXT_HOP_BY_HOP: + case Ipv6Header::IPV6_EXT_ROUTING: + case Ipv6Header::IPV6_EXT_FRAGMENTATION: + case Ipv6Header::IPV6_IPV6: + ret = true; + break; + case Ipv6Header::IPV6_EXT_MOBILITY: + default: + ret = false; + } + return ret; +} + +void +SixLowPanNetDevice::DecompressLowPanIphc (Ptr packet, Address const &src, Address const &dst) +{ + NS_LOG_FUNCTION (this << *packet << src << dst); + + Ipv6Header ipHeader; + SixLowPanIphc encoding; + + uint32_t ret = packet->RemoveHeader (encoding); + NS_LOG_DEBUG ("removed " << ret << " bytes - pkt is " << *packet); + NS_UNUSED (ret); + + // Hop Limit + ipHeader.SetHopLimit (encoding.GetHopLimit ()); + + // Source address + if ( encoding.GetSac () ) + { + if ( encoding.GetSam () == SixLowPanIphc::HC_INLINE ) + { + ipHeader.SetSourceAddress ( Ipv6Address::GetAny () ); + } + else + { + NS_ABORT_MSG ("SAC option not yet implemented"); + } + } + else + { + if ( encoding.GetSam () == SixLowPanIphc::HC_COMPR_0 ) + { + ipHeader.SetSourceAddress (MakeLinkLocalAddressFromMac (src)); + } + else + { + ipHeader.SetSourceAddress ( encoding.GetSrcAddress () ); + } + } + // Destination address + if ( encoding.GetDac () ) + { + if ((encoding.GetDam () == SixLowPanIphc::HC_INLINE && !encoding.GetM ()) + || (encoding.GetDam () == SixLowPanIphc::HC_COMPR_64 && encoding.GetM ()) + || (encoding.GetDam () == SixLowPanIphc::HC_COMPR_16 && encoding.GetM ()) + || (encoding.GetDam () == SixLowPanIphc::HC_COMPR_0 && encoding.GetM ()) ) + { + NS_ABORT_MSG ("Reserved code found"); + } + else + { + NS_ABORT_MSG ("DAC option not yet implemented"); + } + } + else + { + if ( !encoding.GetM () && encoding.GetDam () == SixLowPanIphc::HC_COMPR_0 ) + { + ipHeader.SetDestinationAddress (MakeLinkLocalAddressFromMac (dst)); + } + else + { + ipHeader.SetDestinationAddress ( encoding.GetDstAddress () ); + } + } + + // Traffic class and Flow Label + uint8_t traf = 0x00; + switch (encoding.GetTf ()) + { + case SixLowPanIphc::TF_FULL: + traf |= encoding.GetEcn (); + traf = ( traf << 6 ) | encoding.GetDscp (); + ipHeader.SetTrafficClass (traf); + ipHeader.SetFlowLabel ( encoding.GetFlowLabel () & 0xfff ); //Add 4-bit pad + break; + case SixLowPanIphc::TF_DSCP_ELIDED: + traf |= encoding.GetEcn (); + traf <<= 2; // Add 2-bit pad + ipHeader.SetTrafficClass (traf); + ipHeader.SetFlowLabel (encoding.GetFlowLabel ()); + break; + case SixLowPanIphc::TF_FL_ELIDED: + traf |= encoding.GetEcn (); + traf = ( traf << 6 ) | encoding.GetDscp (); + ipHeader.SetTrafficClass (traf); + ipHeader.SetFlowLabel (0); + break; + case SixLowPanIphc::TF_ELIDED: + ipHeader.SetFlowLabel (0); + ipHeader.SetTrafficClass (0); + break; + } + + if ( encoding.GetNh () ) + { + // Next Header + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::NhcDispatch_e dispatchVal; + + packet->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetNhcDispatchType (dispatchRawVal); + + if (dispatchVal == SixLowPanDispatch::LOWPAN_UDPNHC) + { + ipHeader.SetNextHeader (Ipv6Header::IPV6_UDP); + DecompressLowPanUdpNhc (packet, ipHeader.GetSourceAddress (), ipHeader.GetDestinationAddress ()); + } + else + { + ipHeader.SetNextHeader (DecompressLowPanNhc (packet, src, dst, ipHeader.GetSourceAddress (), ipHeader.GetDestinationAddress ())); + } + } + else + { + ipHeader.SetNextHeader (encoding.GetNextHeader ()); + } + + ipHeader.SetPayloadLength (packet->GetSize ()); + + packet->AddHeader (ipHeader); + + NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () ); + +} + +uint32_t +SixLowPanNetDevice::CompressLowPanNhc (Ptr packet, uint8_t headerType, Address const &src, Address const &dst) +{ + NS_LOG_FUNCTION (this << *packet << int(headerType)); + + SixLowPanNhcExtension nhcHeader; + uint32_t size = 0; + Buffer blob; + + if (headerType == Ipv6Header::IPV6_EXT_HOP_BY_HOP) + { + Ipv6ExtensionHopByHopHeader hopHeader; + packet->PeekHeader (hopHeader); + if (hopHeader.GetLength () >= 0xff) + { + NS_LOG_DEBUG ("LOWPAN_NHC MUST NOT be used to encode IPv6 Extension Headers " + "that have more than 255 octets following the Length field after compression. " + "Packet uncompressed."); + return 0; + } + + size += packet->RemoveHeader (hopHeader); + nhcHeader.SetEid (SixLowPanNhcExtension::EID_HOPBYHOP_OPTIONS_H); + + // recursively compress other headers + uint8_t nextHeader = hopHeader.GetNextHeader (); + if (CanCompressLowPanNhc (nextHeader)) + { + if (nextHeader == Ipv6Header::IPV6_UDP) + { + nhcHeader.SetNh (true); + size += CompressLowPanUdpNhc (packet, m_omitUdpChecksum); + } + else if (nextHeader == Ipv6Header::IPV6_IPV6) + { + nhcHeader.SetNh (true); + size += CompressLowPanIphc (packet, src, dst); + } + else + { + uint32_t sizeNhc = CompressLowPanNhc (packet, nextHeader, src, dst); + // the compression might fail due to Extension header size. + if (sizeNhc) + { + nhcHeader.SetNh (true); + size += sizeNhc; + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + } + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + + uint32_t blobSize = hopHeader.GetSerializedSize (); + blob.AddAtStart (blobSize); + hopHeader.Serialize (blob.Begin ()); + blob.RemoveAtStart (2); + blobSize = blob.GetSize (); + nhcHeader.SetBlob (blob.PeekData (), blobSize); + } + else if (headerType == Ipv6Header::IPV6_EXT_ROUTING) + { + Ipv6ExtensionRoutingHeader routingHeader; + packet->PeekHeader (routingHeader); + if (routingHeader.GetLength () >= 0xff) + { + NS_LOG_DEBUG ("LOWPAN_NHC MUST NOT be used to encode IPv6 Extension Headers " + "that have more than 255 octets following the Length field after compression. " + "Packet uncompressed."); + return 0; + } + + size += packet->RemoveHeader (routingHeader); + nhcHeader.SetEid (SixLowPanNhcExtension::EID_ROUTING_H); + + // recursively compress other headers + uint8_t nextHeader = routingHeader.GetNextHeader (); + if (CanCompressLowPanNhc (nextHeader)) + { + if (nextHeader == Ipv6Header::IPV6_UDP) + { + nhcHeader.SetNh (true); + size += CompressLowPanUdpNhc (packet, m_omitUdpChecksum); + } + else if (nextHeader == Ipv6Header::IPV6_IPV6) + { + nhcHeader.SetNh (true); + size += CompressLowPanIphc (packet, src, dst); + } + else + { + uint32_t sizeNhc = CompressLowPanNhc (packet, nextHeader, src, dst); + // the compression might fail due to Extension header size. + if (sizeNhc) + { + nhcHeader.SetNh (true); + size += sizeNhc; + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + } + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + + uint32_t blobSize = routingHeader.GetSerializedSize (); + blob.AddAtStart (blobSize); + routingHeader.Serialize (blob.Begin ()); + blob.RemoveAtStart (2); + blobSize = blob.GetSize (); + nhcHeader.SetBlob (blob.PeekData (), blobSize); + } + else if (headerType == Ipv6Header::IPV6_EXT_FRAGMENTATION) + { + Ipv6ExtensionFragmentHeader fragHeader; + packet->PeekHeader (fragHeader); + if (fragHeader.GetLength () >= 0xff) + { + NS_LOG_DEBUG ("LOWPAN_NHC MUST NOT be used to encode IPv6 Extension Headers " + "that have more than 255 octets following the Length field after compression. " + "Packet uncompressed."); + return 0; + } + size += packet->RemoveHeader (fragHeader); + nhcHeader.SetEid (SixLowPanNhcExtension::EID_FRAGMENTATION_H); + + // recursively compress other headers + uint8_t nextHeader = fragHeader.GetNextHeader (); + if (CanCompressLowPanNhc (nextHeader)) + { + if (nextHeader == Ipv6Header::IPV6_UDP) + { + nhcHeader.SetNh (true); + size += CompressLowPanUdpNhc (packet, m_omitUdpChecksum); + } + else if (nextHeader == Ipv6Header::IPV6_IPV6) + { + nhcHeader.SetNh (true); + size += CompressLowPanIphc (packet, src, dst); + } + else + { + uint32_t sizeNhc = CompressLowPanNhc (packet, nextHeader, src, dst); + // the compression might fail due to Extension header size. + if (sizeNhc) + { + nhcHeader.SetNh (true); + size += sizeNhc; + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + } + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + + uint32_t blobSize = fragHeader.GetSerializedSize (); + blob.AddAtStart (blobSize); + fragHeader.Serialize (blob.Begin ()); + blob.RemoveAtStart (2); + blobSize = blob.GetSize (); + nhcHeader.SetBlob (blob.PeekData (), blobSize); + } + else if (headerType == Ipv6Header::IPV6_EXT_DESTINATION) + { + Ipv6ExtensionDestinationHeader destHeader; + packet->PeekHeader (destHeader); + if (destHeader.GetLength () >= 0xff) + { + NS_LOG_DEBUG ("LOWPAN_NHC MUST NOT be used to encode IPv6 Extension Headers " + "that have more than 255 octets following the Length field after compression. " + "Packet uncompressed."); + return 0; + } + size += packet->RemoveHeader (destHeader); + nhcHeader.SetEid (SixLowPanNhcExtension::EID_DESTINATION_OPTIONS_H); + + // recursively compress other headers + uint8_t nextHeader = destHeader.GetNextHeader (); + if (CanCompressLowPanNhc (nextHeader)) + { + if (nextHeader == Ipv6Header::IPV6_UDP) + { + nhcHeader.SetNh (true); + size += CompressLowPanUdpNhc (packet, m_omitUdpChecksum); + } + else if (nextHeader == Ipv6Header::IPV6_IPV6) + { + nhcHeader.SetNh (true); + size += CompressLowPanIphc (packet, src, dst); + } + else + { + uint32_t sizeNhc = CompressLowPanNhc (packet, nextHeader, src, dst); + // the compression might fail due to Extension header size. + if (sizeNhc) + { + nhcHeader.SetNh (true); + size += sizeNhc; + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + } + } + else + { + nhcHeader.SetNh (false); + nhcHeader.SetNextHeader (nextHeader); + } + + uint32_t blobSize = destHeader.GetSerializedSize (); + blob.AddAtStart (blobSize); + destHeader.Serialize (blob.Begin ()); + blob.RemoveAtStart (2); + blobSize = blob.GetSize (); + nhcHeader.SetBlob (blob.PeekData (), blobSize); + } + else if (headerType == Ipv6Header::IPV6_EXT_MOBILITY) + { + // \todo: IPv6 Mobility Header is not supported in ns-3 + NS_ABORT_MSG ("IPv6 Mobility Header is not supported in ns-3 yet"); + return 0; + } + else + { + NS_ABORT_MSG ("Unexpected Extension Header"); + } + + NS_LOG_DEBUG ("NHC Compression - NHC header size = " << nhcHeader.GetSerializedSize () ); + NS_LOG_DEBUG ("NHC Compression - packet size = " << packet->GetSize () ); + + packet->AddHeader (nhcHeader); + + NS_LOG_DEBUG ("Packet after NHC compression: " << *packet); + return size; +} + +uint8_t +SixLowPanNetDevice::DecompressLowPanNhc (Ptr packet, Address const &src, Address const &dst, Ipv6Address srcAddress, Ipv6Address dstAddress) +{ + NS_LOG_FUNCTION (this << *packet); + + SixLowPanNhcExtension encoding; + + uint32_t ret = packet->RemoveHeader (encoding); + NS_LOG_DEBUG ("removed " << ret << " bytes - pkt is " << *packet); + NS_UNUSED (ret); + + Ipv6ExtensionHopByHopHeader hopHeader; + Ipv6ExtensionRoutingHeader routingHeader; + Ipv6ExtensionFragmentHeader fragHeader; + Ipv6ExtensionDestinationHeader destHeader; + + uint32_t blobSize; + uint8_t blobData[260]; + blobSize = encoding.CopyBlob (blobData + 2, 260); + uint8_t paddingSize = 0; + + uint8_t actualEncodedHeaderType = encoding.GetEid (); + uint8_t actualHeaderType; + Buffer blob; + + switch (actualEncodedHeaderType) + { + case SixLowPanNhcExtension::EID_HOPBYHOP_OPTIONS_H: + actualHeaderType = Ipv6Header::IPV6_EXT_HOP_BY_HOP; + if ( encoding.GetNh () ) + { + // Next Header + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::NhcDispatch_e dispatchVal; + + packet->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetNhcDispatchType (dispatchRawVal); + + if (dispatchVal == SixLowPanDispatch::LOWPAN_UDPNHC) + { + blobData [0] = Ipv6Header::IPV6_UDP; + DecompressLowPanUdpNhc (packet, srcAddress, dstAddress); + } + else + { + blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress); + } + } + else + { + blobData [0] = encoding.GetNextHeader (); + } + + // manually add some padding if needed + if ((blobSize + 2) % 8 > 0) + { + paddingSize = 8 - (blobSize + 2) % 8; + } + if (paddingSize == 1) + { + blobData[blobSize + 2] = 0; + } + else if (paddingSize > 1) + { + blobData[blobSize + 2] = 1; + blobData[blobSize + 2 + 1] = paddingSize - 2; + for (uint8_t i = 0; i < paddingSize - 2; i++) + { + blobData[blobSize + 2 + 2 + i] = 0; + } + } + blobData [1] = ((blobSize + 2 + paddingSize) >> 3) - 1; + blob.AddAtStart (blobSize + 2 + paddingSize); + blob.Begin ().Write (blobData, blobSize + 2 + paddingSize); + hopHeader.Deserialize (blob.Begin ()); + + packet->AddHeader (hopHeader); + break; + + case SixLowPanNhcExtension::EID_ROUTING_H: + actualHeaderType = Ipv6Header::IPV6_EXT_ROUTING; + if ( encoding.GetNh () ) + { + // Next Header + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::NhcDispatch_e dispatchVal; + + packet->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetNhcDispatchType (dispatchRawVal); + + if (dispatchVal == SixLowPanDispatch::LOWPAN_UDPNHC) + { + blobData [0] = Ipv6Header::IPV6_UDP; + DecompressLowPanUdpNhc (packet, srcAddress, dstAddress); + } + else + { + blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress); + } + } + else + { + blobData [0] = encoding.GetNextHeader (); + } + blobData [1] = ((blobSize + 2) >> 3) - 1; + blob.AddAtStart (blobSize + 2); + blob.Begin ().Write (blobData, blobSize + 2); + routingHeader.Deserialize (blob.Begin ()); + packet->AddHeader (routingHeader); + break; + + case SixLowPanNhcExtension::EID_FRAGMENTATION_H: + actualHeaderType = Ipv6Header::IPV6_EXT_FRAGMENTATION; + if ( encoding.GetNh () ) + { + // Next Header + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::NhcDispatch_e dispatchVal; + + packet->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetNhcDispatchType (dispatchRawVal); + + if (dispatchVal == SixLowPanDispatch::LOWPAN_UDPNHC) + { + blobData [0] = Ipv6Header::IPV6_UDP; + DecompressLowPanUdpNhc (packet, srcAddress, dstAddress); + } + else + { + blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress); + } + } + else + { + blobData [0] = encoding.GetNextHeader (); + } + blobData [1] = 0; + fragHeader.Deserialize (blob.Begin ()); + packet->AddHeader (fragHeader); + break; + + case SixLowPanNhcExtension::EID_DESTINATION_OPTIONS_H: + actualHeaderType = Ipv6Header::IPV6_EXT_DESTINATION; + if ( encoding.GetNh () ) + { + // Next Header + uint8_t dispatchRawVal = 0; + SixLowPanDispatch::NhcDispatch_e dispatchVal; + + packet->CopyData (&dispatchRawVal, sizeof(dispatchRawVal)); + dispatchVal = SixLowPanDispatch::GetNhcDispatchType (dispatchRawVal); + + if (dispatchVal == SixLowPanDispatch::LOWPAN_UDPNHC) + { + blobData [0] = Ipv6Header::IPV6_UDP; + DecompressLowPanUdpNhc (packet, srcAddress, dstAddress); + } + else + { + blobData [0] = DecompressLowPanNhc (packet, src, dst, srcAddress, dstAddress); + } + } + else + { + blobData [0] = encoding.GetNextHeader (); + } + + // manually add some padding if needed + if ((blobSize + 2) % 8 > 0) + { + paddingSize = 8 - (blobSize + 2) % 8; + } + if (paddingSize == 1) + { + blobData[blobSize + 2] = 0; + } + else if (paddingSize > 1) + { + blobData[blobSize + 2] = 1; + blobData[blobSize + 2 + 1] = paddingSize - 2; + for (uint8_t i = 0; i < paddingSize - 2; i++) + { + blobData[blobSize + 2 + 2 + i] = 0; + } + } + blobData [1] = ((blobSize + 2 + paddingSize) >> 3) - 1; + blob.AddAtStart (blobSize + 2 + paddingSize); + blob.Begin ().Write (blobData, blobSize + 2 + paddingSize); + destHeader.Deserialize (blob.Begin ()); + + packet->AddHeader (destHeader); + break; + case SixLowPanNhcExtension::EID_MOBILITY_H: + // \todo: IPv6 Mobility Header is not supported in ns-3 + NS_ABORT_MSG ("IPv6 Mobility Header is not supported in ns-3 yet"); + break; + case SixLowPanNhcExtension::EID_IPv6_H: + actualHeaderType = Ipv6Header::IPV6_IPV6; + DecompressLowPanIphc (packet, src, dst); + break; + default: + NS_ABORT_MSG ("Trying to decode unknown Extension Header"); + break; + } + + NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () ); + return actualHeaderType; +} + +uint32_t +SixLowPanNetDevice::CompressLowPanUdpNhc (Ptr packet, bool omitChecksum) +{ + NS_LOG_FUNCTION (this << *packet << int(omitChecksum)); + + UdpHeader udpHeader; + SixLowPanUdpNhcExtension udpNhcHeader; + uint32_t size = 0; + + NS_ASSERT_MSG (packet->PeekHeader (udpHeader) != 0, "UDP header not found, abort"); + + size += packet->RemoveHeader (udpHeader); + + // Set the C field and checksum + udpNhcHeader.SetC (false); + uint16_t checksum = udpHeader.GetChecksum (); + udpNhcHeader.SetChecksum (checksum); + + if (omitChecksum && udpHeader.IsChecksumOk ()) + { + udpNhcHeader.SetC (true); + } + + // Set the value of the ports + udpNhcHeader.SetSrcPort (udpHeader.GetSourcePort ()); + udpNhcHeader.SetDstPort (udpHeader.GetDestinationPort ()); + + //Set the P field + if ( (udpHeader.GetSourcePort () >> 4 ) == 0xf0b && (udpHeader.GetDestinationPort () >> 4 ) == 0xf0b ) + { + udpNhcHeader.SetPorts (SixLowPanUdpNhcExtension::PORTS_LAST_SRC_LAST_DST); + } + else if ( (udpHeader.GetSourcePort () >> 8 ) == 0xf0 && (udpHeader.GetDestinationPort () >> 8 ) != 0xf0 ) + { + udpNhcHeader.SetPorts (SixLowPanUdpNhcExtension::PORTS_LAST_SRC_ALL_DST); + } + else if ( (udpHeader.GetSourcePort () >> 8 ) != 0xf0 && (udpHeader.GetDestinationPort () >> 8 ) == 0xf0 ) + { + udpNhcHeader.SetPorts (SixLowPanUdpNhcExtension::PORTS_ALL_SRC_LAST_DST); + } + else + { + udpNhcHeader.SetPorts (SixLowPanUdpNhcExtension::PORTS_INLINE); + } + + NS_LOG_DEBUG ("UDP_NHC Compression - UDP_NHC header size = " << udpNhcHeader.GetSerializedSize () ); + NS_LOG_DEBUG ("UDP_NHC Compression - packet size = " << packet->GetSize () ); + + packet->AddHeader (udpNhcHeader); + + NS_LOG_DEBUG ("Packet after UDP_NHC compression: " << *packet); + + return size; +} + +void +SixLowPanNetDevice::DecompressLowPanUdpNhc (Ptr packet, Ipv6Address saddr, Ipv6Address daddr) +{ + NS_LOG_FUNCTION (this << *packet); + + UdpHeader udpHeader; + SixLowPanUdpNhcExtension encoding; + + uint32_t ret = packet->RemoveHeader (encoding); + NS_LOG_DEBUG ("removed " << ret << " bytes - pkt is " << *packet); + NS_UNUSED (ret); + + // Set the value of the ports + switch ( encoding.GetPorts () ) + { + uint16_t temp; + case SixLowPanUdpNhcExtension::PORTS_INLINE: + udpHeader.SetSourcePort (encoding.GetSrcPort ()); + udpHeader.SetDestinationPort (encoding.GetDstPort ()); + break; + case SixLowPanUdpNhcExtension::PORTS_ALL_SRC_LAST_DST: + udpHeader.SetSourcePort (encoding.GetSrcPort ()); + temp = 0xf0; + temp |= (temp << 8) | encoding.GetDstPort (); + udpHeader.SetDestinationPort (temp); + break; + case SixLowPanUdpNhcExtension::PORTS_LAST_SRC_ALL_DST: + temp = 0xf0; + temp |= (temp << 8) | encoding.GetSrcPort (); + udpHeader.SetSourcePort (temp); + udpHeader.SetDestinationPort (encoding.GetDstPort ()); + break; + case SixLowPanUdpNhcExtension::PORTS_LAST_SRC_LAST_DST: + temp = 0xf0b; + temp |= (temp << 4) | encoding.GetSrcPort (); + udpHeader.SetSourcePort (temp); + temp = 0xf0b; + temp |= (temp << 4) | encoding.GetDstPort (); + udpHeader.SetDestinationPort (temp); + break; + } + + // Get the C field and checksum + if (Node::ChecksumEnabled ()) + { + if ( encoding.GetC () ) + { + NS_LOG_LOGIC ("Recalculating UDP Checksum"); + udpHeader.EnableChecksums (); + udpHeader.InitializeChecksum (saddr, + daddr, + UdpL4Protocol::PROT_NUMBER); + packet->AddHeader (udpHeader); + } + else + { + NS_LOG_LOGIC ("Forcing UDP Checksum to " << encoding.GetChecksum ()); + udpHeader.ForceChecksum (encoding.GetChecksum ()); + packet->AddHeader (udpHeader); + NS_LOG_LOGIC ("UDP checksum is ok ? " << udpHeader.IsChecksumOk ()); + } + } + else + { + packet->AddHeader (udpHeader); + } + + NS_LOG_DEBUG ( "Rebuilt packet: " << *packet << " Size " << packet->GetSize () ); +} + +void SixLowPanNetDevice::DoFragmentation (Ptr packet, + uint32_t origPacketSize, + uint32_t origHdrSize, + std::list >& listFragments) +{ + NS_LOG_FUNCTION (this << *packet); + + Ptr p = packet->Copy (); + + uint16_t offsetData = 0; + uint16_t offset = 0; + uint16_t l2Mtu = m_netDevice->GetMtu (); + uint32_t packetSize = packet->GetSize (); + uint32_t compressedHeaderSize = packetSize - (origPacketSize - origHdrSize); + + uint16_t tag = uint16_t (m_rng->GetValue (0, 65535)); + NS_LOG_LOGIC ("random tag " << tag << " - test " << packetSize ); + + // first fragment + SixLowPanFrag1 frag1Hdr; + frag1Hdr.SetDatagramTag (tag); + + uint32_t size; + NS_ASSERT_MSG ( l2Mtu > frag1Hdr.GetSerializedSize (), + "6LoWPAN: can not fragment, 6LoWPAN headers are bigger than MTU"); + + size = l2Mtu - frag1Hdr.GetSerializedSize () - compressedHeaderSize; + size -= size % 8; + size += compressedHeaderSize; + + frag1Hdr.SetDatagramSize (origPacketSize); + + Ptr fragment1 = p->CreateFragment (offsetData, size); + offset += size + origHdrSize - compressedHeaderSize; + offsetData += size; + + fragment1->AddHeader (frag1Hdr); + listFragments.push_back (fragment1); + + bool moreFrag = true; + do + { + SixLowPanFragN fragNHdr; + fragNHdr.SetDatagramTag (tag); + fragNHdr.SetDatagramSize (origPacketSize); + fragNHdr.SetDatagramOffset ((offset) >> 3); + + size = l2Mtu - fragNHdr.GetSerializedSize (); + size -= size % 8; + + if ( (offsetData + size) > packetSize ) + { + size = packetSize - offsetData; + moreFrag = false; + } + + NS_LOG_LOGIC ("Fragment creation - " << offset << ", " << offset ); + Ptr fragment = p->CreateFragment (offsetData, size); + NS_LOG_LOGIC ("Fragment created - " << offset << ", " << fragment->GetSize () ); + + offset += size; + offsetData += size; + + fragment->AddHeader (fragNHdr); + listFragments.push_back (fragment); + + } + while (moreFrag); + + return; +} + +bool SixLowPanNetDevice::ProcessFragment (Ptr& packet, Address const &src, Address const &dst, bool isFirst) +{ + NS_LOG_FUNCTION ( this << *packet ); + SixLowPanFrag1 frag1Header; + SixLowPanFragN fragNHeader; + FragmentKey key; + uint16_t packetSize; + key.first = std::pair (src, dst); + + Ptr p = packet->Copy (); + uint16_t offset = 0; + + /* Implementation note: + * + * The fragment offset is relative to the *uncompressed* packet. + * On the other hand, the packet can not be uncompressed correctly without all + * its fragments, as the UDP checksum can not be computed otherwise. + * + * As a consequence we must uncompress the packet twice, and save its first + * fragment for the final one. + */ + + if ( isFirst ) + { + uint8_t dispatchRawValFrag1 = 0; + SixLowPanDispatch::Dispatch_e dispatchValFrag1; + + p->RemoveHeader (frag1Header); + packetSize = frag1Header.GetDatagramSize (); + p->CopyData (&dispatchRawValFrag1, sizeof(dispatchRawValFrag1)); + dispatchValFrag1 = SixLowPanDispatch::GetDispatchType (dispatchRawValFrag1); + NS_LOG_DEBUG ( "Dispatches: " << int(dispatchRawValFrag1) << " - " << int(dispatchValFrag1) ); + NS_LOG_DEBUG ( "Packet: " << *p ); + + switch ( dispatchValFrag1 ) + { + case SixLowPanDispatch::LOWPAN_NOTCOMPRESSED: + NS_LOG_DEBUG ( "Packet without compression:" << *p ); + NS_LOG_DEBUG ( "Packet length:" << p->GetSize () ); + break; + case SixLowPanDispatch::LOWPAN_HC1: + DecompressLowPanHc1 (p, src, dst); + break; + case SixLowPanDispatch::LOWPAN_IPHC: + DecompressLowPanIphc (p, src, dst); + break; + default: + NS_FATAL_ERROR ("Unsupported 6LoWPAN encoding, exiting."); + break; + } + + key.second = std::pair (frag1Header.GetDatagramSize (), frag1Header.GetDatagramTag ()); + } + else + { + p->RemoveHeader (fragNHeader); + packetSize = fragNHeader.GetDatagramSize (); + offset = fragNHeader.GetDatagramOffset () << 3; + key.second = std::pair (fragNHeader.GetDatagramSize (), fragNHeader.GetDatagramTag ()); + } + + Ptr fragments; + + MapFragments_t::iterator it = m_fragments.find (key); + if (it == m_fragments.end ()) + { + // erase the oldest packet. + if ( m_fragmentReassemblyListSize && (m_fragments.size () >= m_fragmentReassemblyListSize) ) + { + MapFragmentsTimers_t::iterator iter; + MapFragmentsTimers_t::iterator iterFound = m_fragmentsTimers.begin (); + for ( iter = m_fragmentsTimers.begin (); iter != m_fragmentsTimers.end (); iter++) + { + if ( iter->second.GetTs () < iterFound->second.GetTs () ) + { + iterFound = iter; + } + } + FragmentKey oldestKey = iterFound->first; + + std::list< Ptr > storedFragments = m_fragments[oldestKey]->GetFraments (); + for (std::list< Ptr >::iterator fragIter = storedFragments.begin (); + fragIter != storedFragments.end (); fragIter++) + { + m_dropTrace (DROP_FRAGMENT_BUFFER_FULL, *fragIter, m_node->GetObject (), GetIfIndex ()); + } + + m_fragmentsTimers[oldestKey].Cancel (); + m_fragmentsTimers.erase (oldestKey); + m_fragments[oldestKey] = 0; + m_fragments.erase (oldestKey); + + } + fragments = Create (); + fragments->SetPacketSize (packetSize); + m_fragments.insert (std::make_pair (key, fragments)); + uint32_t ifIndex = GetIfIndex (); + m_fragmentsTimers[key] = Simulator::Schedule (m_fragmentExpirationTimeout, + &SixLowPanNetDevice::HandleFragmentsTimeout, this, + key, ifIndex); + } + else + { + fragments = it->second; + } + + fragments->AddFragment (p, offset); + + // add the very first fragment so we can correctly decode the packet once is rebuilt. + // this is needed because otherwise the UDP header length and checksum can not be calculated. + if ( isFirst ) + { + fragments->AddFirstFragment (packet); + } + + if ( fragments->IsEntire () ) + { + packet = fragments->GetPacket (); + NS_LOG_LOGIC ("Reconstructed packet: " << *packet); + + SixLowPanFrag1 frag1Header; + packet->RemoveHeader (frag1Header); + + NS_LOG_LOGIC ("Rebuilt packet. Size " << packet->GetSize () << " - " << *packet); + fragments = 0; + m_fragments.erase (key); + if (m_fragmentsTimers[key].IsRunning ()) + { + NS_LOG_LOGIC ("Stopping 6LoWPAN WaitFragmentsTimer at " << Simulator::Now ().GetSeconds () << " due to complete packet"); + m_fragmentsTimers[key].Cancel (); + } + m_fragmentsTimers.erase (key); + return true; + } + + return false; +} + +SixLowPanNetDevice::Fragments::Fragments () +{ + NS_LOG_FUNCTION (this); + m_packetSize = 0; +} + +SixLowPanNetDevice::Fragments::~Fragments () +{ + NS_LOG_FUNCTION (this); +} + +void SixLowPanNetDevice::Fragments::AddFragment (Ptr fragment, uint16_t fragmentOffset) +{ + NS_LOG_FUNCTION (this << fragmentOffset << *fragment); + + std::list, uint16_t> >::iterator it; + bool duplicate = false; + + for (it = m_fragments.begin (); it != m_fragments.end (); it++) + { + if (it->second > fragmentOffset) + { + break; + } + if (it->second == fragmentOffset) + { + duplicate = true; + NS_ASSERT_MSG (fragment->GetSize () == it->first->GetSize (), "Duplicate fragment size differs. Aborting."); + break; + } + } + if (!duplicate) + { + m_fragments.insert (it, std::make_pair, uint16_t> (fragment, fragmentOffset)); + } +} + +void SixLowPanNetDevice::Fragments::AddFirstFragment (Ptr fragment) +{ + NS_LOG_FUNCTION (this << *fragment); + + m_firstFragment = fragment; +} + +bool SixLowPanNetDevice::Fragments::IsEntire () const +{ + NS_LOG_FUNCTION (this); + + bool ret = m_fragments.size () > 0; + uint16_t lastEndOffset = 0; + + if (ret) + { + for (std::list, uint16_t> >::const_iterator it = m_fragments.begin (); it != m_fragments.end (); it++) + { + // overlapping fragments should not exist + NS_LOG_LOGIC ("Checking overlaps " << lastEndOffset << " - " << it->second ); + + if (lastEndOffset < it->second) + { + ret = false; + break; + } + // fragments might overlap in strange ways + uint16_t fragmentEnd = it->first->GetSize () + it->second; + lastEndOffset = std::max ( lastEndOffset, fragmentEnd ); + } + } + + if ( ret && (lastEndOffset == m_packetSize)) + { + return true; + } + return false; +} + +Ptr SixLowPanNetDevice::Fragments::GetPacket () const +{ + NS_LOG_FUNCTION (this); + + std::list, uint16_t> >::const_iterator it = m_fragments.begin (); + + Ptr p = Create (); + uint16_t lastEndOffset = 0; + + p->AddAtEnd (m_firstFragment); + it = m_fragments.begin (); + lastEndOffset = it->first->GetSize (); + + for ( it++; it != m_fragments.end (); it++) + { + if ( lastEndOffset > it->second ) + { + NS_ABORT_MSG ("Overlapping fragments found, forbidden condition"); + } + else + { + NS_LOG_LOGIC ("Adding: " << *(it->first) ); + p->AddAtEnd (it->first); + } + lastEndOffset += it->first->GetSize (); + } + + return p; +} + +void SixLowPanNetDevice::Fragments::SetPacketSize (uint32_t packetSize) +{ + NS_LOG_FUNCTION (this << packetSize); + m_packetSize = packetSize; +} + +std::list< Ptr > SixLowPanNetDevice::Fragments::GetFraments () const +{ + std::list< Ptr > fragments; + std::list, uint16_t> >::const_iterator iter; + for ( iter = m_fragments.begin (); iter != m_fragments.end (); iter ++) + { + fragments.push_back (iter->first); + } + return fragments; +} + +void SixLowPanNetDevice::HandleFragmentsTimeout (FragmentKey key, uint32_t iif) +{ + NS_LOG_FUNCTION (this); + + MapFragments_t::iterator it = m_fragments.find (key); + std::list< Ptr > storedFragments = it->second->GetFraments (); + for (std::list< Ptr >::iterator fragIter = storedFragments.begin (); + fragIter != storedFragments.end (); fragIter++) + { + m_dropTrace (DROP_FRAGMENT_TIMEOUT, *fragIter, m_node->GetObject (), iif); + } + // clear the buffers + it->second = 0; + + m_fragments.erase (key); + m_fragmentsTimers.erase (key); +} + +Ipv6Address SixLowPanNetDevice::MakeLinkLocalAddressFromMac (Address const &addr) +{ + Ipv6Address ipv6Addr = Ipv6Address::GetAny (); + + if (m_forceEtherType && Mac48Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac48Address::ConvertFrom (addr)); + } + else + { + if (Mac64Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac64Address::ConvertFrom (addr)); + } + else if (Mac16Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac16Address::ConvertFrom (addr)); + } + } + if (ipv6Addr.IsAny ()) + { + NS_ABORT_MSG ("Unknown address type"); + } + return ipv6Addr; +} + +Ipv6Address SixLowPanNetDevice::MakeGlobalAddressFromMac (Address const &addr, Ipv6Address prefix) +{ + Ipv6Address ipv6Addr = Ipv6Address::GetAny (); + + if (m_forceEtherType && Mac48Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress (Mac48Address::ConvertFrom (addr), Ipv6Address (prefix) ); + } + else + { + if (Mac64Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress (Mac64Address::ConvertFrom (addr), Ipv6Address (prefix)); + } + else if (Mac16Address::IsMatchingType (addr)) + { + ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress (Mac16Address::ConvertFrom (addr), Ipv6Address (prefix) ); + } + } + if (ipv6Addr.IsAny ()) + { + NS_ABORT_MSG ("Unknown address type"); + } + return ipv6Addr; +} + +} + +// namespace ns3 diff --git a/src/sixlowpan/model/sixlowpan-net-device.h b/src/sixlowpan/model/sixlowpan-net-device.h new file mode 100644 index 000000000..4b5b069cc --- /dev/null +++ b/src/sixlowpan/model/sixlowpan-net-device.h @@ -0,0 +1,455 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + * Michele Muccio + */ + +#ifndef SIXLOWPAN_NET_DEVICE_H +#define SIXLOWPAN_NET_DEVICE_H + +#include +#include +#include +#include "ns3/traced-callback.h" +#include "ns3/event-id.h" +#include "ns3/nstime.h" +#include "ns3/net-device.h" +#include "ns3/packet.h" +#include "sixlowpan-header.h" +#include "ns3/random-variable-stream.h" + +namespace ns3 { + +class Node; + +/** + * \defgroup sixlowpan 6LoWPAN + * \brief Performs 6LoWPAN compression of IPv6 packets as specified by RFC 4944 and RFC 6262 + * + * This module acts as a shim between IPv6 and a generic NetDevice. + * + * The module implements RFCs 4944 and 6262, with the following exceptions: + *
      + *
    • MESH and LOWPAN_BC0 dispatch types are not supported
    • + *
    • HC2 encoding is not supported
    • + *
    • IPHC's SAC and DAC are not supported
    • + *
    + */ + +/** + * \ingroup sixlowpan + * + * \brief Shim performing 6LoWPAN compression, decompression and fragmentation. + * + * This class implements the shim between IPv6 and a generic NetDevice, + * performing packet compression, decompression and fragmentation in a transparent way. + * To this end, the class pretend to be a normal NetDevice, masquerading some functions + * of the underlying NetDevice. + */ +class SixLowPanNetDevice : public NetDevice +{ +public: + /** + * Enumeration of the dropping reasons in SixLoWPAN. + */ + enum DropReason + { + DROP_FRAGMENT_TIMEOUT = 1, /**< Fragment timeout exceeded */ + DROP_FRAGMENT_BUFFER_FULL, /**< Fragment buffer size exceeded */ + DROP_UNKNOWN_EXTENSION /**< Unsupported compression kind */ + }; + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * Constructor for the SixLowPanNetDevice. + */ + SixLowPanNetDevice (); + + // inherited from NetDevice base class + virtual void SetIfIndex (const uint32_t index); + virtual uint32_t GetIfIndex (void) const; + virtual Ptr GetChannel (void) const; + virtual void SetAddress (Address address); + virtual Address GetAddress (void) const; + virtual bool SetMtu (const uint16_t mtu); + + /** + * \brief Returns the link-layer MTU for this interface. + * If the link-layer MTU is smaller than IPv6's minimum MTU (RFC 4944), + * 1280 will be returned. + * + * \return the link-level MTU in bytes for this interface. + */ + virtual uint16_t GetMtu (void) const; + virtual bool IsLinkUp (void) const; + virtual void AddLinkChangeCallback (Callback callback); + virtual bool IsBroadcast (void) const; + virtual Address GetBroadcast (void) const; + virtual bool IsMulticast (void) const; + virtual Address GetMulticast (Ipv4Address multicastGroup) const; + virtual bool IsPointToPoint (void) const; + virtual bool IsBridge (void) const; + virtual bool Send (Ptr packet, const Address& dest, uint16_t protocolNumber); + virtual bool SendFrom (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + virtual Ptr GetNode (void) const; + virtual void SetNode (Ptr node); + virtual bool NeedsArp (void) const; + virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb); + virtual bool SupportsSendFrom () const; + virtual Address GetMulticast (Ipv6Address addr) const; + + /** + * \brief Returns a smart pointer to the underlying NetDevice. + * + * \return a smart pointer to the underlying NetDevice. + */ + Ptr GetNetDevice () const; + + /** + * \brief Setup SixLowPan to be a proxy for the specified NetDevice. + * All the packets incoming and outgoing from the NetDevice will be + * processed by SixLowPanNetDevice. + * + * \param device a smart pointer to the NetDevice to be proxied. + */ + void SetNetDevice (Ptr device); + + /** + * Assign a fixed random variable stream number to the random variables + * used by this model. Return the number of streams (possibly zero) that + * have been assigned. + * + * \param stream first stream index to use + * \return the number of stream indices assigned by this model + */ + int64_t AssignStreams (int64_t stream); + +protected: + virtual void DoDispose (void); + +private: + /** + * \brief receives all the packets from a NetDevice for further processing. + * \param device the NetDevice the packet ws received from + * \param packet the received packet + * \param protocol the protocol (if known) + * \param source the source address + * \param destination the destination address + * \param packetType the packet kind (e.g., HOST, BROADCAST, etc.) + * \return the IPv6 link-local address + */ + void ReceiveFromDevice (Ptr device, Ptr packet, uint16_t protocol, + Address const &source, Address const &destination, PacketType packetType); + + /** + * The callback used to notify higher layers that a packet has been received. + */ + NetDevice::ReceiveCallback m_rxCallback; + + /** + * The callback used to notify higher layers that a packet has been received in promiscuous mode. + */ + NetDevice::PromiscReceiveCallback m_promiscRxCallback; + + /** + * \brief Callback to trace TX (transmission) packets. + * + * Data passed: + * \li Packet received (including 6LoWPAN header) + * \li Ptr to SixLowPanNetDevice + * \li interface index + */ + TracedCallback, Ptr, uint32_t> m_txTrace; + + /** + * \brief Callback to trace RX (reception) packets. + * + * Data passed: + * \li Packet received (including 6LoWPAN header) + * \li Ptr to SixLowPanNetDevice + * \li interface index + */ + TracedCallback, Ptr, uint32_t> m_rxTrace; + + /** + * \brief Callback to trace drop packets. + * + * Data passed: + * \li DropReason + * \li Packet dropped (including 6LoWPAN header) + * \li Ptr to SixLowPanNetDevice + * \li interface index + */ + TracedCallback, Ptr, uint32_t> m_dropTrace; + + /** + * \brief make a link-local address from a MAC address. + * \param addr the MAC address + * \return the IPv6 link-local address + */ + Ipv6Address MakeLinkLocalAddressFromMac (Address const &addr); + + /** + * \brief make a global address from a MAC address. + * \param addr the MAC address + * \param prefix the address prefix + * \return the IPv6 address + */ + Ipv6Address MakeGlobalAddressFromMac (Address const &addr, Ipv6Address prefix); + + /** + * \brief Compress the headers according to HC1 compression. + * \param packet the packet to be compressed + * \param src the MAC source address + * \param dst the MAC destination address + * \return the size of the removed headers + */ + uint32_t CompressLowPanHc1 (Ptr packet, Address const &src, Address const &dst); + + /** + * \brief Decompress the headers according to HC1 compression. + * \param packet the packet to be compressed + * \param src the MAC source address + * \param dst the MAC destination address + */ + void DecompressLowPanHc1 (Ptr packet, Address const &src, Address const &dst); + + /** + * \brief Compress the headers according to IPHC compression. + * \param packet the packet to be compressed + * \param src the MAC source address + * \param dst the MAC destination address + * \return the size of the removed headers + */ + uint32_t CompressLowPanIphc (Ptr packet, Address const &src, Address const &dst); + + /** + * \brief Checks if the next header can be compressed using NHC. + * \param headerType the header kind to be compressed + * \return true if the header can be compressed + */ + bool CanCompressLowPanNhc (uint8_t headerType); + + /** + * \brief Decompress the headers according to IPHC compression. + * \param packet the packet to be compressed + * \param src the MAC source address + * \param dst the MAC destination address + */ + void DecompressLowPanIphc (Ptr packet, Address const &src, Address const &dst); + + /** + * \brief Compress the headers according to NHC compression. + * \param packet the packet to be compressed + * \param headerType the header type + * \param src the MAC source address + * \param dst the MAC destination address + * \return the size of the removed headers + */ + uint32_t CompressLowPanNhc (Ptr packet, uint8_t headerType, Address const &src, Address const &dst); + + /** + * \brief Decompress the headers according to NHC compression. + * \param packet the packet to be compressed + * \param src the MAC source address + * \param dst the MAC destination address + * \param srcAddress the IPv6 source address + * \param dstAddress the IPv6 destination address + * \return the decompressed header type + */ + uint8_t DecompressLowPanNhc (Ptr packet, Address const &src, Address const &dst, Ipv6Address srcAddress, Ipv6Address dstAddress); + + /** + * \brief Compress the headers according to NHC compression. + * \param packet the packet to be compressed + * \param omitChecksum omit UDP checksum (if true) + * \return the size of the removed headers + */ + uint32_t CompressLowPanUdpNhc (Ptr packet, bool omitChecksum); + + /** + * \brief Decompress the headers according to NHC compression. + * \param packet the packet to be compressed + * \param saddr the IPv6 source address + * \param daddr the IPv6 destination address + */ + void DecompressLowPanUdpNhc (Ptr packet, Ipv6Address saddr, Ipv6Address daddr); + + /** + * Fragment identifier type: src/dst address src/dst port + */ + typedef std::pair< std::pair, std::pair > FragmentKey; + + /** + * \class Fragments + * \brief A Set of Fragment + */ + class Fragments : public SimpleRefCount + { +public: + /** + * \brief Constructor. + */ + Fragments (); + + /** + * \brief Destructor. + */ + ~Fragments (); + + /** + * \brief Add a fragment to the pool. + * \param fragment the fragment + * \param fragmentOffset the offset of the fragment + */ + void AddFragment (Ptr fragment, uint16_t fragmentOffset); + + /** + * \brief Add the first packet fragment. The first fragment is needed to + * allow the post-defragmentation decompression. + * \param fragment the fragment + */ + void AddFirstFragment (Ptr fragment); + + /** + * \brief If all fragments have been added. + * \returns true if the packet is entire + */ + bool IsEntire () const; + + /** + * \brief Get the entire packet. + * \return the entire packet + */ + Ptr GetPacket () const; + + /** + * \brief Set the packet-to-be-defragmented size. + * \param packetSize the packet size (bytes) + */ + void SetPacketSize (uint32_t packetSize); + + /** + * \brief Get a list of the current stored fragments. + */ + std::list< Ptr > GetFraments () const; + +private: + /** + * \brief The size of the reconstructed packet (bytes). + */ + uint32_t m_packetSize; + + /** + * \brief The current fragments. + */ + std::list, uint16_t> > m_fragments; + + /** + * \brief The very first fragment + */ + Ptr m_firstFragment; + + }; + + /** + * \brief Return the instance type identifier. + * \param packet the packet to be fragmented (with headers already compressed with 6LoWPAN) + * \param origPacketSize the size of the IP packet before the 6LoWPAN header compression, including the IP/L4 headers + * \param origHdrSize the size of the IP header before the 6LoWPAN header compression + * \param listFragments a reference to the list of the resulting packets, all with the proper headers in place + */ + void DoFragmentation (Ptr packet, uint32_t origPacketSize, uint32_t origHdrSize, + std::list >& listFragments); + + /** + * \brief Process a packet fragment + * \param packet the packet + * \param src the source MAC address + * \param dst the destination MAC address + * \param isFirst true if it is the first fragment, false otherwise + * \return true is the fragment completed the packet + */ + bool ProcessFragment (Ptr& packet, Address const &src, Address const &dst, bool isFirst); + + /** + * \brief Process the timeout for packet fragments + * \param key representing the packet fragments + * \param iif Input Interface + */ + void HandleFragmentsTimeout ( FragmentKey key, uint32_t iif); + + /** + * \brief Drops the oldest fragment set + */ + void DropOldestFragmentSet (); + + /** + * Container for fragment key -> fragments + */ + typedef std::map< FragmentKey, Ptr > MapFragments_t; + /** + * Container Iterator for fragment key -> fragments + */ + typedef std::map< FragmentKey, Ptr >::iterator MapFragmentsI_t; + /** + * Container for fragment key -> exiration event + */ + typedef std::map< FragmentKey, EventId > MapFragmentsTimers_t; + /** + * Container Iterator for fragment key -> exiration event + */ + typedef std::map< FragmentKey, EventId >::iterator MapFragmentsTimersI_t; + + MapFragments_t m_fragments; /**< Fragments hold to be rebuilt */ + MapFragmentsTimers_t m_fragmentsTimers; /**< Timers related to fragment rebuilding */ + Time m_fragmentExpirationTimeout; /**< Time limit for fragment rebuilding */ + + /** + * \brief How many packets can be rebuilt at the same time. + * Some real implementation do limit this. Zero means no limit. + */ + uint16_t m_fragmentReassemblyListSize; + + bool m_useIphc; /**< Use IPHC or HC1 */ + + Ptr m_node; /**< Smart pointer to the Node */ + Ptr m_netDevice; /**< Smart pointer to the underlying NetDevice */ + uint32_t m_ifIndex; /**< Interface index */ + + /** + * \brief Force the EtherType number. + * Also implying that the underlying NetDevice is using 48-bit Addresses, e.g., Ethernet, WiFi, etc. + */ + bool m_forceEtherType; + + uint16_t m_etherType; /**< EtherType number (used only if m_forceEtherType is true) */ + bool m_omitUdpChecksum; /**< Omit UDP checksum in NC1 encoding */ + + Ptr m_rng; //!< Rng for the fragments tag. +}; + +} // namespace ns3 + +#endif /* SIXLOWPAN_NET_DEVICE_H */ diff --git a/src/sixlowpan/test/error-channel-sixlow.cc b/src/sixlowpan/test/error-channel-sixlow.cc new file mode 100644 index 000000000..6a9084d2d --- /dev/null +++ b/src/sixlowpan/test/error-channel-sixlow.cc @@ -0,0 +1,196 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ +#include "error-channel-sixlow.h" +#include "ns3/simple-net-device.h" +#include "ns3/simulator.h" +#include "ns3/packet.h" +#include "ns3/node.h" +#include "ns3/log.h" + +NS_LOG_COMPONENT_DEFINE ("ErrorChannelSixlow") + ; + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (ErrorChannelSixlow) + ; + +TypeId +ErrorChannelSixlow::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::ErrorChannelSixlow") + .SetParent () + .AddConstructor () + ; + return tid; +} + +ErrorChannelSixlow::ErrorChannelSixlow () +{ + m_jumpingTime = Seconds (0.5); + m_jumping = false; + m_jumpingState = 0; + m_duplicateTime = Seconds (0.1); + m_duplicate = false; +} + +void +ErrorChannelSixlow::SetJumpingTime (Time delay) +{ + m_jumpingTime = delay; +} + +void +ErrorChannelSixlow::SetJumpingMode (bool mode) +{ + m_jumping = mode; + m_jumpingState = 0; +} + +void +ErrorChannelSixlow::SetDuplicateTime (Time delay) +{ + m_duplicateTime = delay; +} + +void +ErrorChannelSixlow::SetDuplicateMode (bool mode) +{ + m_duplicate = mode; + m_duplicateState = 0; +} + + +void +ErrorChannelSixlow::Send (Ptr p, uint16_t protocol, + Mac48Address to, Mac48Address from, + Ptr sender) +{ + NS_LOG_FUNCTION (p << protocol << to << from << sender); + for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) + { + Ptr tmp = *i; + if (tmp == sender) + { + continue; + } + if (m_jumping) + { + if (m_jumpingState % 2) + { + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), Seconds (0), + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + } + else + { + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), m_jumpingTime, + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + } + m_jumpingState++; + } + else if (m_duplicate) + { + if (m_duplicateState % 2) + { + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), Seconds (0), + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + } + else + { + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), Seconds (0), + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), m_duplicateTime, + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + } + m_duplicateState++; + } + else + { + Simulator::ScheduleWithContext (tmp->GetNode ()->GetId (), Seconds (0), + &SimpleNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + } + } +} + +void +ErrorChannelSixlow::Add (Ptr device) +{ + m_devices.push_back (device); +} + +uint32_t +ErrorChannelSixlow::GetNDevices (void) const +{ + return m_devices.size (); +} +Ptr +ErrorChannelSixlow::GetDevice (uint32_t i) const +{ + return m_devices[i]; +} + +NS_OBJECT_ENSURE_REGISTERED (BinaryErrorSixlowModel) + ; + +TypeId BinaryErrorSixlowModel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::BinaryErrorSixlowModel") + .SetParent () + .AddConstructor () + ; + return tid; +} + +BinaryErrorSixlowModel::BinaryErrorSixlowModel () +{ + m_counter = 0; +} + +BinaryErrorSixlowModel::~BinaryErrorSixlowModel () +{ +} + + +bool +BinaryErrorSixlowModel::DoCorrupt (Ptr p) +{ + if (!IsEnabled ()) + { + return false; + } + bool ret = m_counter % 2; + m_counter++; + return ret; +} + +void +BinaryErrorSixlowModel::Reset (void) +{ + DoReset (); +} + +void +BinaryErrorSixlowModel::DoReset (void) +{ + m_counter = 0; +} + + +} // namespace ns3 diff --git a/src/sixlowpan/test/error-channel-sixlow.h b/src/sixlowpan/test/error-channel-sixlow.h new file mode 100644 index 000000000..2a5f13ca0 --- /dev/null +++ b/src/sixlowpan/test/error-channel-sixlow.h @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ +#ifndef ERROR_CHANNEL_SIXLOW_H +#define ERROR_CHANNEL_SIXLOW_H + +#include "ns3/channel.h" +#include "ns3/simple-channel.h" +#include "ns3/error-model.h" +#include "ns3/mac48-address.h" +#include "ns3/nstime.h" +#include + +namespace ns3 { + +class SimpleNetDevice; +class Packet; + +/** + * \ingroup channel + * \brief A Error channel, introducing deterministic delays on even/odd packets. Used for testing + */ +class ErrorChannelSixlow : public SimpleChannel +{ +public: + static TypeId GetTypeId (void); + ErrorChannelSixlow (); + + virtual void Send (Ptr p, uint16_t protocol, Mac48Address to, Mac48Address from, + Ptr sender); + + virtual void Add (Ptr device); + + // inherited from ns3::Channel + virtual uint32_t GetNDevices (void) const; + virtual Ptr GetDevice (uint32_t i) const; + + /** + * \brief Set the delay for the odd packets (even ones are not delayed) + * \param delay Delay for the odd packets. + */ + void SetJumpingTime (Time delay); + + /** + * \brief Set if the odd packets are delayed (even ones are not delayed ever) + * \param mode true if the odd packets should be delayed. + */ + void SetJumpingMode (bool mode); + + /** + * \brief Set the delay for the odd duplicate packets (even ones are not duplicated) + * \param delay Delay for the odd packets. + */ + void SetDuplicateTime (Time delay); + + /** + * \brief Set if the odd packets are duplicated (even ones are not duplicated ever) + * \param mode true if the odd packets should be duplicated. + */ + void SetDuplicateMode (bool mode); + +private: + std::vector > m_devices; + Time m_jumpingTime; + uint8_t m_jumpingState; + bool m_jumping; + Time m_duplicateTime; + bool m_duplicate; + uint8_t m_duplicateState; +}; + +class BinaryErrorSixlowModel : public ErrorModel +{ +public: + static TypeId GetTypeId (void); + + BinaryErrorSixlowModel (); + virtual ~BinaryErrorSixlowModel (); + void Reset (void); + +private: + virtual bool DoCorrupt (Ptr p); + virtual void DoReset (void); + + uint8_t m_counter; + +}; + +} // namespace ns3 + +#endif /* ERROR_CHANNEL_SIXLOW_H */ diff --git a/src/sixlowpan/test/sixlowpan-fragmentation-test.cc b/src/sixlowpan/test/sixlowpan-fragmentation-test.cc new file mode 100644 index 000000000..abaf5dc3e --- /dev/null +++ b/src/sixlowpan/test/sixlowpan-fragmentation-test.cc @@ -0,0 +1,463 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ +#define NS3_LOG_ENABLE 1 + +#include "ns3/test.h" +#include "ns3/config.h" +#include "ns3/uinteger.h" +#include "ns3/socket-factory.h" +#include "ns3/ipv6-raw-socket-factory.h" +#include "ns3/udp-socket-factory.h" +#include "ns3/simulator.h" +#include "error-channel-sixlow.h" +#include "ns3/simple-net-device.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/socket.h" +#include "ns3/udp-socket.h" + +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/inet-socket-address.h" +#include "ns3/boolean.h" + +#include "ns3/ipv6-static-routing.h" +#include "ns3/ipv6-list-routing.h" +#include "ns3/inet6-socket-address.h" +#include "ns3/sixlowpan-net-device.h" + +#include "ns3/udp-l4-protocol.h" + +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/icmpv6-l4-protocol.h" + +#include +#include +#include + +using namespace ns3; + +class UdpSocketImpl; + +static void +AddInternetStack (Ptr node) +{ + //IPV6 + Ptr ipv6 = CreateObject (); + + //Routing for Ipv6 + Ptr ipv6Routing = CreateObject (); + ipv6->SetRoutingProtocol (ipv6Routing); + Ptr ipv6staticRouting = CreateObject (); + ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0); + node->AggregateObject (ipv6); + + //ICMPv6 + Ptr icmp6 = CreateObject (); + node->AggregateObject (icmp6); + + //Ipv6 Extensions + ipv6->RegisterExtensions (); + ipv6->RegisterOptions (); + + //UDP + Ptr udp = CreateObject (); + node->AggregateObject (udp); +} + + +class SixlowpanFragmentationTest : public TestCase +{ + Ptr m_sentPacketClient; + Ptr m_receivedPacketClient; + Ptr m_receivedPacketServer; + + + Ptr m_socketServer; + Ptr m_socketClient; + uint32_t m_dataSize; + uint8_t *m_data; + uint32_t m_size; + uint8_t m_icmpType; + uint8_t m_icmpCode; + +public: + virtual void DoRun (void); + SixlowpanFragmentationTest (); + ~SixlowpanFragmentationTest (); + + // server part + void StartServer (Ptr ServerNode); + void HandleReadServer (Ptr socket); + + // client part + void StartClient (Ptr ClientNode); + void HandleReadClient (Ptr socket); + void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, + uint8_t icmpCode,uint32_t icmpInfo); + + void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize); + Ptr SendClient (void); + +}; + + +SixlowpanFragmentationTest::SixlowpanFragmentationTest () + : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly") +{ + m_socketServer = 0; + m_data = 0; + m_dataSize = 0; +} + +SixlowpanFragmentationTest::~SixlowpanFragmentationTest () +{ + if ( m_data ) + { + delete[] m_data; + } + m_data = 0; + m_dataSize = 0; +} + + +void +SixlowpanFragmentationTest::StartServer (Ptr ServerNode) +{ + + if (m_socketServer == 0) + { + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socketServer = Socket::CreateSocket (ServerNode, tid); + Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9); + m_socketServer->Bind (local); + Ptr udpSocket = DynamicCast (m_socketServer); + } + + m_socketServer->SetRecvCallback (MakeCallback (&SixlowpanFragmentationTest::HandleReadServer, this)); +} + +void +SixlowpanFragmentationTest::HandleReadServer (Ptr socket) +{ + Ptr packet; + Address from; + while ((packet = socket->RecvFrom (from))) + { + if (Inet6SocketAddress::IsMatchingType (from)) + { + packet->RemoveAllPacketTags (); + packet->RemoveAllByteTags (); + + m_receivedPacketServer = packet->Copy (); + } + } +} + +void +SixlowpanFragmentationTest::StartClient (Ptr ClientNode) +{ + + if (m_socketClient == 0) + { + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socketClient = Socket::CreateSocket (ClientNode, tid); + m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9)); + m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9)); + CallbackValue cbValue = MakeCallback (&SixlowpanFragmentationTest::HandleReadIcmpClient, this); + m_socketClient->SetAttribute ("IcmpCallback6", cbValue); + } + + m_socketClient->SetRecvCallback (MakeCallback (&SixlowpanFragmentationTest::HandleReadClient, this)); +} + +void +SixlowpanFragmentationTest::HandleReadClient (Ptr socket) +{ + Ptr packet; + Address from; + while ((packet = socket->RecvFrom (from))) + { + if (Inet6SocketAddress::IsMatchingType (from)) + { + m_receivedPacketClient = packet->Copy (); + } + } +} + +void +SixlowpanFragmentationTest::HandleReadIcmpClient (Ipv6Address icmpSource, + uint8_t icmpTtl, uint8_t icmpType, + uint8_t icmpCode, uint32_t icmpInfo) +{ + m_icmpType = icmpType; + m_icmpCode = icmpCode; +} + +void +SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize) +{ + if (dataSize != m_dataSize) + { + delete [] m_data; + m_data = new uint8_t [dataSize]; + m_dataSize = dataSize; + } + + if (fillSize >= dataSize) + { + memcpy (m_data, fill, dataSize); + return; + } + + uint32_t filled = 0; + while (filled + fillSize < dataSize) + { + memcpy (&m_data[filled], fill, fillSize); + filled += fillSize; + } + + memcpy (&m_data[filled], fill, dataSize - filled); + + m_size = dataSize; +} + +Ptr SixlowpanFragmentationTest::SendClient (void) +{ + Ptr p; + if (m_dataSize) + { + p = Create (m_data, m_dataSize); + } + else + { + p = Create (m_size); + } + m_socketClient->Send (p); + + return p; +} + +void +SixlowpanFragmentationTest::DoRun (void) +{ + // Create topology + + // Receiver Node + Ptr serverNode = CreateObject (); + AddInternetStack (serverNode); + Ptr serverDev; + Ptr serverDevErrorModel = CreateObject (); + { + serverDev = CreateObject (); + serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + serverDev->SetMtu (1500); + serverDev->SetReceiveErrorModel (serverDevErrorModel); + serverDevErrorModel->Disable (); + serverNode->AddDevice (serverDev); + + Ptr serverSix = CreateObject (); + serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + serverNode->AddDevice (serverSix); + serverSix->SetNetDevice (serverDev); + + Ptr ipv6 = serverNode->GetObject (); + ipv6->AddInterface (serverDev); + uint32_t netdev_idx = ipv6->AddInterface (serverSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + + Ptr icmpv6l4 = serverNode->GetObject (); + icmpv6l4->SetAttribute ("DAD", BooleanValue (false)); + } + StartServer (serverNode); + + // Sender Node + Ptr clientNode = CreateObject (); + AddInternetStack (clientNode); + Ptr clientDev; + Ptr clientDevErrorModel = CreateObject (); + { + clientDev = CreateObject (); + clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + clientDev->SetMtu (150); + clientDev->SetReceiveErrorModel (clientDevErrorModel); + clientDevErrorModel->Disable (); + clientNode->AddDevice (clientDev); + + Ptr clientSix = CreateObject (); + clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + serverNode->AddDevice (clientSix); + clientSix->SetNetDevice (clientDev); + + Ptr ipv6 = clientNode->GetObject (); + ipv6->AddInterface (clientDev); + uint32_t netdev_idx = ipv6->AddInterface (clientSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + + Ptr icmpv6l4 = clientNode->GetObject (); + icmpv6l4->SetAttribute ("DAD", BooleanValue (false)); + } + StartClient (clientNode); + + // link the two nodes + Ptr channel = CreateObject (); + serverDev->SetChannel (channel); + clientDev->SetChannel (channel); + + + // some small packets, some rather big ones + uint32_t packetSizes[5] = {200, 300, 400, 500, 600}; + + // using the alphabet + uint8_t fillData[78]; + for ( uint32_t k = 48; k <= 125; k++ ) + { + fillData[k - 48] = k; + } + + // First test: normal channel, no errors, no delays + for ( int i = 0; i < 5; i++) + { + uint32_t packetSize = packetSizes[i]; + + SetFill (fillData, 78, packetSize); + + m_receivedPacketServer = Create (); + Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0), + &SixlowpanFragmentationTest::SendClient, this); + Simulator::Run (); + + uint8_t recvBuffer[65000]; + + uint16_t recvSize = m_receivedPacketServer->GetSize (); + + NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], + "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] ); + + m_receivedPacketServer->CopyData (recvBuffer, 65000); + NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()), + 0, "Packet content differs"); + } + + // Second test: normal channel, no errors, delays each 2 packets. + // Each other fragment will arrive out-of-order. + // The packets should be received correctly since reassembly will reorder the fragments. + channel->SetJumpingMode (true); + for ( int i = 0; i < 5; i++) + { + uint32_t packetSize = packetSizes[i]; + + SetFill (fillData, 78, packetSize); + + m_receivedPacketServer = Create (); + Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0), + &SixlowpanFragmentationTest::SendClient, this); + Simulator::Run (); + + uint8_t recvBuffer[65000]; + + uint16_t recvSize = m_receivedPacketServer->GetSize (); + + NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], + "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] ); + + m_receivedPacketServer->CopyData (recvBuffer, 65000); + NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()), + 0, "Packet content differs"); + } + channel->SetJumpingMode (false); + + + // Third test: normal channel, some packets are duplicate. + // The duplicate fragments should be discarded, so no error should be fired. + channel->SetDuplicateMode (true); + for ( int i = 1; i < 5; i++) + { + uint32_t packetSize = packetSizes[i]; + + SetFill (fillData, 78, packetSize); + + // reset the model, we want to receive the very first fragment. + serverDevErrorModel->Reset (); + + m_receivedPacketServer = Create (); + m_icmpType = 0; + m_icmpCode = 0; + Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0), + &SixlowpanFragmentationTest::SendClient, this); + Simulator::Run (); + + uint8_t recvBuffer[65000]; + + uint16_t recvSize = m_receivedPacketServer->GetSize (); + + NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], + "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] ); + + m_receivedPacketServer->CopyData (recvBuffer, 65000); + NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()), + 0, "Packet content differs"); + } + channel->SetDuplicateMode (false); + + // Fourth test: normal channel, some errors, no delays. + // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the server. + // Client -> Server : errors enabled + // Server -> Client : errors disabled + clientDevErrorModel->Disable (); + serverDevErrorModel->Enable (); + for ( int i = 1; i < 5; i++) + { + uint32_t packetSize = packetSizes[i]; + + SetFill (fillData, 78, packetSize); + + // reset the model, we want to receive the very first fragment. + serverDevErrorModel->Reset (); + + m_receivedPacketServer = Create (); + m_icmpType = 0; + m_icmpCode = 0; + Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0), + &SixlowpanFragmentationTest::SendClient, this); + Simulator::Run (); + + uint16_t recvSize = m_receivedPacketServer->GetSize (); + + NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong"); + // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6. + } + + + + Simulator::Destroy (); +} +//----------------------------------------------------------------------------- +class SixlowpanFragmentationTestSuite : public TestSuite +{ +public: + SixlowpanFragmentationTestSuite () : TestSuite ("sixlowpan-fragmentation", UNIT) + { + AddTestCase (new SixlowpanFragmentationTest, TestCase::QUICK); + } +} g_sixlowpanFragmentationTestSuite; diff --git a/src/sixlowpan/test/sixlowpan-hc1-test.cc b/src/sixlowpan/test/sixlowpan-hc1-test.cc new file mode 100644 index 000000000..9cff7ba2b --- /dev/null +++ b/src/sixlowpan/test/sixlowpan-hc1-test.cc @@ -0,0 +1,216 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ + +#include "ns3/test.h" +#include "ns3/socket-factory.h" +#include "ns3/udp-socket-factory.h" +#include "ns3/simulator.h" +#include "ns3/simple-channel.h" +#include "ns3/simple-net-device.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/socket.h" +#include "ns3/boolean.h" + +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/inet6-socket-address.h" + +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/icmpv6-l4-protocol.h" +#include "ns3/udp-l4-protocol.h" +#include "ns3/ipv6-list-routing.h" +#include "ns3/ipv6-static-routing.h" + +#include "ns3/sixlowpan-net-device.h" + +#include +#include + +using namespace ns3; + +static void +AddInternetStack6 (Ptr node) +{ + //IPV6 + Ptr ipv6 = CreateObject (); + //Routing for Ipv6 + Ptr ipv6Routing = CreateObject (); + ipv6->SetRoutingProtocol (ipv6Routing); + Ptr ipv6staticRouting = CreateObject (); + ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0); + node->AggregateObject (ipv6); + //ICMP + Ptr icmp = CreateObject (); + node->AggregateObject (icmp); + //Ipv6 Extensions + ipv6->RegisterExtensions (); + ipv6->RegisterOptions (); + //UDP + Ptr udp = CreateObject (); + node->AggregateObject (udp); +} + + +class SixlowpanHc1ImplTest : public TestCase +{ + Ptr m_receivedPacket; + void DoSendData (Ptr socket, std::string to); + void SendData (Ptr socket, std::string to); + +public: + virtual void DoRun (void); + SixlowpanHc1ImplTest (); + + void ReceivePacket (Ptr socket, Ptr packet, const Address &from); + void ReceivePkt (Ptr socket); +}; + +SixlowpanHc1ImplTest::SixlowpanHc1ImplTest () + : TestCase ("Sixlowpan implementation") +{ +} + +void SixlowpanHc1ImplTest::ReceivePacket (Ptr socket, Ptr packet, const Address &from) +{ + m_receivedPacket = packet; +} + +void SixlowpanHc1ImplTest::ReceivePkt (Ptr socket) +{ + uint32_t availableData; + availableData = socket->GetRxAvailable (); + m_receivedPacket = socket->Recv (std::numeric_limits::max (), 0); + NS_ASSERT (availableData == m_receivedPacket->GetSize ()); + //cast availableData to void, to suppress 'availableData' set but not used + //compiler warning + (void) availableData; +} + +void +SixlowpanHc1ImplTest::DoSendData (Ptr socket, std::string to) +{ + Address realTo = Inet6SocketAddress (Ipv6Address (to.c_str ()), 1234); + uint8_t buffer [] = "\"Can you tell me where my country lies?\" \\ said the unifaun to his true love's eyes. \\ \"It lies with me!\" cried the Queen of Maybe \\ - for her merchandise, he traded in his prize."; + + Ptr packet = Create (buffer, 180); + NS_TEST_EXPECT_MSG_EQ (socket->SendTo (packet, 0, realTo), + 180, "200"); +} + +void +SixlowpanHc1ImplTest::SendData (Ptr socket, std::string to) +{ + m_receivedPacket = Create (); + Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), + &SixlowpanHc1ImplTest::DoSendData, this, socket, to); + Simulator::Run (); +} + +void +SixlowpanHc1ImplTest::DoRun (void) +{ + // Create topology + + // Receiver Node + Ptr rxNode = CreateObject (); + AddInternetStack6 (rxNode); + Ptr rxDev; + { // first interface + rxDev = CreateObject (); + rxDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + rxNode->AddDevice (rxDev); + + Ptr rxSix = CreateObject (); + rxSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + rxSix->SetAttribute ("Rfc6282", BooleanValue (false) ); + rxNode->AddDevice (rxSix); + rxSix->SetNetDevice (rxDev); + + Ptr ipv6 = rxNode->GetObject (); + ipv6->AddInterface (rxDev); + uint32_t netdev_idx = ipv6->AddInterface (rxSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // Sender Node + Ptr txNode = CreateObject (); + AddInternetStack6 (txNode); + Ptr txDev; + { + txDev = CreateObject (); + txDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + txNode->AddDevice (txDev); + + Ptr txSix = CreateObject (); + txSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + txSix->SetAttribute ("Rfc6282", BooleanValue (false) ); + txNode->AddDevice (txSix); + txSix->SetNetDevice (txDev); + + Ptr ipv6 = txNode->GetObject (); + ipv6->AddInterface (txDev); + uint32_t netdev_idx = ipv6->AddInterface (txSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // link the two nodes + Ptr channel1 = CreateObject (); + rxDev->SetChannel (channel1); + txDev->SetChannel (channel1); + + // Create the UDP sockets + Ptr rxSocketFactory = rxNode->GetObject (); + Ptr rxSocket = rxSocketFactory->CreateSocket (); + NS_TEST_EXPECT_MSG_EQ (rxSocket->Bind (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 1234)), 0, "trivial"); + rxSocket->SetRecvCallback (MakeCallback (&SixlowpanHc1ImplTest::ReceivePkt, this)); + + Ptr txSocketFactory = txNode->GetObject (); + Ptr txSocket = txSocketFactory->CreateSocket (); + txSocket->SetAllowBroadcast (true); + // ------ Now the tests ------------ + + // Unicast test + SendData (txSocket, "2001:0100::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 180, "trivial"); + uint8_t rxBuffer [180]; + uint8_t txBuffer [180] = "\"Can you tell me where my country lies?\" \\ said the unifaun to his true love's eyes. \\ \"It lies with me!\" cried the Queen of Maybe \\ - for her merchandise, he traded in his prize."; + m_receivedPacket->CopyData (rxBuffer, 180); + NS_TEST_EXPECT_MSG_EQ (memcmp (rxBuffer, txBuffer, 180), 0, "trivial"); + + m_receivedPacket->RemoveAllByteTags (); + + Simulator::Destroy (); + +} + + +//----------------------------------------------------------------------------- +class SixlowpanHc1TestSuite : public TestSuite +{ +public: + SixlowpanHc1TestSuite () : TestSuite ("sixlowpan-hc1", UNIT) + { + AddTestCase (new SixlowpanHc1ImplTest, TestCase::QUICK); + } +} g_sixlowpanHc1TestSuite; diff --git a/src/sixlowpan/test/sixlowpan-iphc-test.cc b/src/sixlowpan/test/sixlowpan-iphc-test.cc new file mode 100644 index 000000000..40e975b25 --- /dev/null +++ b/src/sixlowpan/test/sixlowpan-iphc-test.cc @@ -0,0 +1,214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2013 Universita' di Firenze, Italy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Tommaso Pecorella + */ + +#include "ns3/test.h" +#include "ns3/socket-factory.h" +#include "ns3/udp-socket-factory.h" +#include "ns3/simulator.h" +#include "ns3/simple-channel.h" +#include "ns3/simple-net-device.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/socket.h" +#include "ns3/boolean.h" + +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/inet6-socket-address.h" + +#include "ns3/ipv6-l3-protocol.h" +#include "ns3/icmpv6-l4-protocol.h" +#include "ns3/udp-l4-protocol.h" +#include "ns3/ipv6-list-routing.h" +#include "ns3/ipv6-static-routing.h" + +#include "ns3/sixlowpan-net-device.h" + +#include +#include + +using namespace ns3; + +static void +AddInternetStack6 (Ptr node) +{ + //IPV6 + Ptr ipv6 = CreateObject (); + //Routing for Ipv6 + Ptr ipv6Routing = CreateObject (); + ipv6->SetRoutingProtocol (ipv6Routing); + Ptr ipv6staticRouting = CreateObject (); + ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0); + node->AggregateObject (ipv6); + //ICMP + Ptr icmp = CreateObject (); + node->AggregateObject (icmp); + //Ipv6 Extensions + ipv6->RegisterExtensions (); + ipv6->RegisterOptions (); + //UDP + Ptr udp = CreateObject (); + node->AggregateObject (udp); +} + + +class SixlowpanIphcImplTest : public TestCase +{ + Ptr m_receivedPacket; + void DoSendData (Ptr socket, std::string to); + void SendData (Ptr socket, std::string to); + +public: + virtual void DoRun (void); + SixlowpanIphcImplTest (); + + void ReceivePacket (Ptr socket, Ptr packet, const Address &from); + void ReceivePkt (Ptr socket); +}; + +SixlowpanIphcImplTest::SixlowpanIphcImplTest () + : TestCase ("Sixlowpan implementation") +{ +} + +void SixlowpanIphcImplTest::ReceivePacket (Ptr socket, Ptr packet, const Address &from) +{ + m_receivedPacket = packet; +} + +void SixlowpanIphcImplTest::ReceivePkt (Ptr socket) +{ + uint32_t availableData; + availableData = socket->GetRxAvailable (); + m_receivedPacket = socket->Recv (std::numeric_limits::max (), 0); + NS_ASSERT (availableData == m_receivedPacket->GetSize ()); + //cast availableData to void, to suppress 'availableData' set but not used + //compiler warning + (void) availableData; +} + +void +SixlowpanIphcImplTest::DoSendData (Ptr socket, std::string to) +{ + Address realTo = Inet6SocketAddress (Ipv6Address (to.c_str ()), 1234); + uint8_t buffer [] = "\"Can you tell me where my country lies?\" \\ said the unifaun to his true love's eyes. \\ \"It lies with me!\" cried the Queen of Maybe \\ - for her merchandise, he traded in his prize."; + + Ptr packet = Create (buffer, 180); + NS_TEST_EXPECT_MSG_EQ (socket->SendTo (packet, 0, realTo), + 180, "200"); +} + +void +SixlowpanIphcImplTest::SendData (Ptr socket, std::string to) +{ + m_receivedPacket = Create (); + Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (0), + &SixlowpanIphcImplTest::DoSendData, this, socket, to); + Simulator::Run (); +} + +void +SixlowpanIphcImplTest::DoRun (void) +{ + // Create topology + + // Receiver Node + Ptr rxNode = CreateObject (); + AddInternetStack6 (rxNode); + Ptr rxDev; + { // first interface + rxDev = CreateObject (); + rxDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + rxNode->AddDevice (rxDev); + + Ptr rxSix = CreateObject (); + rxSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + rxNode->AddDevice (rxSix); + rxSix->SetNetDevice (rxDev); + + Ptr ipv6 = rxNode->GetObject (); + ipv6->AddInterface (rxDev); + uint32_t netdev_idx = ipv6->AddInterface (rxSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // Sender Node + Ptr txNode = CreateObject (); + AddInternetStack6 (txNode); + Ptr txDev; + { + txDev = CreateObject (); + txDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())); + txNode->AddDevice (txDev); + + Ptr txSix = CreateObject (); + txSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); + txNode->AddDevice (txSix); + txSix->SetNetDevice (txDev); + + Ptr ipv6 = txNode->GetObject (); + ipv6->AddInterface (txDev); + uint32_t netdev_idx = ipv6->AddInterface (txSix); + Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64)); + ipv6->AddAddress (netdev_idx, ipv6Addr); + ipv6->SetUp (netdev_idx); + } + + // link the two nodes + Ptr channel1 = CreateObject (); + rxDev->SetChannel (channel1); + txDev->SetChannel (channel1); + + // Create the UDP sockets + Ptr rxSocketFactory = rxNode->GetObject (); + Ptr rxSocket = rxSocketFactory->CreateSocket (); + NS_TEST_EXPECT_MSG_EQ (rxSocket->Bind (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 1234)), 0, "trivial"); + rxSocket->SetRecvCallback (MakeCallback (&SixlowpanIphcImplTest::ReceivePkt, this)); + + Ptr txSocketFactory = txNode->GetObject (); + Ptr txSocket = txSocketFactory->CreateSocket (); + txSocket->SetAllowBroadcast (true); + // ------ Now the tests ------------ + + // Unicast test + SendData (txSocket, "2001:0100::1"); + NS_TEST_EXPECT_MSG_EQ (m_receivedPacket->GetSize (), 180, "trivial"); + uint8_t rxBuffer [180]; + uint8_t txBuffer [180] = "\"Can you tell me where my country lies?\" \\ said the unifaun to his true love's eyes. \\ \"It lies with me!\" cried the Queen of Maybe \\ - for her merchandise, he traded in his prize."; + m_receivedPacket->CopyData (rxBuffer, 180); + NS_TEST_EXPECT_MSG_EQ (memcmp (rxBuffer, txBuffer, 180), 0, "trivial"); + + m_receivedPacket->RemoveAllByteTags (); + + Simulator::Destroy (); + +} + + +//----------------------------------------------------------------------------- +class SixlowpanIphcTestSuite : public TestSuite +{ +public: + SixlowpanIphcTestSuite () : TestSuite ("sixlowpan-iphc", UNIT) + { + AddTestCase (new SixlowpanIphcImplTest, TestCase::QUICK); + } +} g_sixlowpanIphcTestSuite; diff --git a/src/sixlowpan/wscript b/src/sixlowpan/wscript new file mode 100644 index 000000000..30a97fb21 --- /dev/null +++ b/src/sixlowpan/wscript @@ -0,0 +1,33 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + module = bld.create_ns3_module('sixlowpan', ['internet', 'network', 'core']) + module.includes = '.' + module.source = [ + 'model/sixlowpan-net-device.cc', + 'model/sixlowpan-header.cc', + 'helper/sixlowpan-helper.cc', + ] + + module_test = bld.create_ns3_module_test_library('sixlowpan') + module_test.source = [ + 'test/sixlowpan-hc1-test.cc', + 'test/sixlowpan-iphc-test.cc', + 'test/error-channel-sixlow.cc', + 'test/sixlowpan-fragmentation-test.cc', + + ] + + headers = bld(features=['ns3header']) + headers.module = 'sixlowpan' + headers.source = [ + 'model/sixlowpan-net-device.h', + 'model/sixlowpan-header.h', + 'helper/sixlowpan-helper.h', + ] + + + if (bld.env['ENABLE_EXAMPLES']): + bld.recurse('examples') + + bld.ns3_python_bindings() \ No newline at end of file