diff -r f6eaede3f93d src/wave/doc/wave.rst --- a/src/wave/doc/wave.rst Tue Mar 01 20:49:37 2016 +0100 +++ b/src/wave/doc/wave.rst Fri Mar 04 23:43:06 2016 +0800 @@ -58,6 +58,10 @@ The source code for the WAVE MAC models lives in the directory ``src/wave``. +Moveover, the part of IEEE 1609.3 [ieee1609dot3]_, called (WAVE Short Message Protocol, WSMP) +is implemented. This is a simple high layer protocol, which will add a WSMP header before +the user's data is transmit over WAVE devices. + For better modeling WAVE and VANET, the WAVE models for high layers (mainly [ieee1609dot3]_ ) are planned for a later patch. @@ -335,6 +339,13 @@ attributes "TxPowerStart", "TxPowerEnd" and "TxPowerLevels" of the YansWifiPhy class by themselves. +High layer +########## + +When users create WaveNetDevice objects by using ``ns3::WaveHelper``, the ``ns3::WsmpProtocol`` will be +added into each Node object automatically. Then, users can use ``ns3::WsmpSocket`` to send and receive data +packet over WSMP header. Here ``ns3::WsmpSocket`` makes references to the UDP design in Internet module. + Scope and Limitations ===================== @@ -785,6 +796,75 @@ the request will be discarded by devices and the method will return false to indicate failure. +High layer +########## + +The APIs of ``ns3::WsmpSocket`` are very similar to that of ``ns3::Socket``, but +``ns3::WsmpSocket`` is not the subclass of ``ns3::Socket``, so users should keep +in mind that "Do Not use Socket when transmiting WSMP packets". + +1. create some Node objects and WaveNetDevice objects by helpers, e.g. one sender and one receiver. + +2. create WsmpSocket objects. + + :: + + TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); + Ptr socket = WsmpSocket::CreateSocket (node, tid); + +3. receiver binds the intertesed WSMP packets by Psid. + + :: + + Psid psid = Psid(0x80, 0x01); + socket->Bind (psid); + +or binds any coming WSMP packets. + + :: + + socket->Bind (); + +4. receiver registers a RecvCallback, then this will be notified when packets come. + + :: + + socket->SetRecvCallback (MakeCallback (&ReceivePacket)); + +5. receiver uses Recv or RecvFrom to read WSMP packets when callback is notified. + + :: + + void ReceivePacket (Ptr socket) + { + while (socket->Recv ()) + { + NS_LOG_UNCOND ("Received one packet!"); + } + } + +6. sender uses Connect to associate with peer host. + + :: + + source->Connect (Mac48Address::GetBroadcast(), psid, WsmpInfo()); + +Note: Although it is named "Connect", the WSMP protocol is only a connectionless service, +thus this method is just a convenient and helpful function for Send method. +Therefor this method is optional if users use SendTo method. + +7. sender uses Send or SendTo to transmit WSMP packets. + + :: + + Simulator::Schedule(Seconds (1.0), &WsmpSocket::Send, socket, Create(100)); + +8. finally sender and receiver close these sockets. + + :: + + Simulator::Schedule(Seconds (1.0), &WsmpSocket::Close, socket); + Attributes ========== diff -r f6eaede3f93d src/wave/examples/wave-simple-wsmp.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/examples/wave-simple-wsmp.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,148 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006,2007 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + * + */ + +#include "ns3/vector.h" +#include "ns3/string.h" +#include "ns3/socket.h" +#include "ns3/double.h" +#include "ns3/config.h" +#include "ns3/log.h" +#include "ns3/command-line.h" +#include "ns3/mobility-model.h" +#include "ns3/yans-wifi-helper.h" +#include "ns3/position-allocator.h" +#include "ns3/mobility-helper.h" +#include + +#include "ns3/ocb-wifi-mac.h" +#include "ns3/wave-mac-helper.h" +#include "ns3/wave-helper.h" +#include "ns3/wsmp-socket.h" +#include "ns3/wsmp-header.h" +#include "ns3/wsmp-protocol.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("WaveWsmp"); + +void ReceivePacket (Ptr socket) +{ + while (socket->Recv ()) + { + NS_LOG_UNCOND ("Received one packet!"); + } +} + +static void GenerateTraffic (Ptr socket, uint32_t pktSize, + uint32_t pktCount, Time pktInterval ) +{ + if (pktCount > 0) + { + socket->Send (Create (pktSize)); + Simulator::Schedule (pktInterval, &GenerateTraffic, + socket, pktSize,pktCount - 1, pktInterval); + } + else + { + socket->Close (); + } +} + +int main (int argc, char *argv[]) +{ + std::string phyMode ("OfdmRate6MbpsBW10MHz"); + uint32_t packetSize = 1000; // bytes + uint32_t numPackets = 1; + double interval = 1.0; // seconds + bool verbose = false; + + CommandLine cmd; + + cmd.AddValue ("phyMode", "Wifi Phy mode", phyMode); + cmd.AddValue ("packetSize", "size of application packet sent", packetSize); + cmd.AddValue ("numPackets", "number of packets generated", numPackets); + cmd.AddValue ("interval", "interval (seconds) between packets", interval); + cmd.AddValue ("verbose", "turn on all WifiNetDevice log components", verbose); + cmd.Parse (argc, argv); + // Convert to time object + Time interPacketInterval = Seconds (interval); + + NodeContainer c; + c.Create (2); + + YansWifiChannelHelper waveChannel = YansWifiChannelHelper::Default (); + YansWavePhyHelper wavePhy = YansWavePhyHelper::Default (); + wavePhy.SetChannel (waveChannel.Create ()); + wavePhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11); + QosWaveMacHelper waveMac = QosWaveMacHelper::Default (); + WaveHelper waveHelper = WaveHelper::Default (); + waveHelper.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode",StringValue (phyMode), + "ControlMode",StringValue (phyMode)); + if (verbose) + { + waveHelper.EnableLogComponents (); // Turn on all WAVE logging + } + NetDeviceContainer devices = waveHelper.Install (wavePhy, waveMac, c); + + // If we do not assign channel access here, the WAVE devices will be assigned + // continuous CCH access by default. + for (uint32_t i = 0; i != devices.GetN(); i++) + { + Ptr device = DynamicCast (devices.Get(i)); + // Alternating access without immediate channel switch + const SchInfo schInfo = SchInfo (SCH1, false, EXTENDED_ALTERNATING); + // An important point is that the receiver should also be assigned channel + // access for the same channel to receive packets. + Simulator::Schedule (Seconds (0.0), &WaveNetDevice::StartSch, device, schInfo); + } + + // Tracing + wavePhy.EnablePcap ("wave-simple-wsmp", devices); + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (5.0, 0.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (c); + + TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); + Ptr recvSink = WsmpSocket::CreateSocket (c.Get (0), tid); + Psid psid = Psid(0x80, 0x01); + recvSink->Bind (psid); + recvSink->SetRecvCallback (MakeCallback (&ReceivePacket)); + + Ptr source = WsmpSocket::CreateSocket (c.Get (1), tid); + source->Connect (Mac48Address::GetBroadcast(), psid); + + Simulator::ScheduleWithContext (c.Get(1)->GetId (), + Seconds (1.0), &GenerateTraffic, + source, packetSize, numPackets, interPacketInterval); + + Simulator::Stop (Seconds (10.0)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff -r f6eaede3f93d src/wave/examples/wscript --- a/src/wave/examples/wscript Tue Mar 01 20:49:37 2016 +0100 +++ b/src/wave/examples/wscript Fri Mar 04 23:43:06 2016 +0800 @@ -9,6 +9,10 @@ ['core', 'applications', 'mobility', 'network', 'wifi','wave']) obj.source = 'wave-simple-device.cc' + obj = bld.create_ns3_program('wave-simple-wsmp', + ['core', 'applications', 'mobility', 'network', 'wifi','wave']) + obj.source = 'wave-simple-wsmp.cc' + obj = bld.create_ns3_program('vanet-routing-compare', ['core', 'aodv', 'applications', 'dsr', 'dsdv', 'flow-monitor', 'mobility', 'network', 'olsr', 'propagation', 'wifi', 'wave']) obj.source = 'vanet-routing-compare.cc' diff -r f6eaede3f93d src/wave/helper/wave-helper.cc --- a/src/wave/helper/wave-helper.cc Tue Mar 01 20:49:37 2016 +0100 +++ b/src/wave/helper/wave-helper.cc Fri Mar 04 23:43:06 2016 +0800 @@ -763,6 +763,17 @@ node->AddDevice (device); devices.Add (device); } + + // Moreover, ns3::WsmpProtocol class which implements IEEE 1609.3 WSMP protocol will be added into ns3::Node. + for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) + { + Ptr node = (*i); + ObjectFactory factory; + factory.SetTypeId ("ns3::WsmpProtocol"); + Ptr protocol = factory.Create (); + node->AggregateObject (protocol); + } + return devices; } diff -r f6eaede3f93d src/wave/model/wsmp-header.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-header.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,312 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ + +#include "wsmp-header.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (WsmpHeader); + +#define WSMP_VERSION_MASK 0x0f + +#define ELEMENT_ID_CHANNEL_NUMBER 0x0f +#define ELEMENT_ID_DATARATE 0x10 +#define ELEMENT_ID_TX_POWER 0x04 +#define ELEMENT_ID_WSMP_N 0x80 +#define ELEMENT_ID_WSMP_S 0x81 +#define ELEMENT_ID_WSMP_I 0x82 + +// The length field of channel number, txpower, datarate is 1. +#define ELEMENT_LENGTH_ONE 0x01 + +const uint16_t WsmpHeader::MAX_HEADER_SIZE = 17; +const uint16_t WsmpHeader::MIN_HEADER_SIZE = 8; + +WsmpHeader::WsmpHeader () + : m_version (0), + m_channel (0), + m_datarate(0), + m_power(0), + m_id(ELEMENT_ID_WSMP_N), + m_length(0) +{ +} + +WsmpHeader::~WsmpHeader () +{ +} + +void +WsmpHeader::SetVersion (uint8_t version) +{ + m_version = version; +} + +uint8_t +WsmpHeader::GetVersion (void) +{ + return m_version; +} + +void +WsmpHeader::SetPsid (Psid psid) +{ + m_psid= psid; +} + +Psid +WsmpHeader::GetPsid (void) +{ + return m_psid; +} + +void +WsmpHeader::SetExtensionChannelNumber (uint8_t channelNumber) +{ + m_channel = channelNumber; +} + +uint8_t +WsmpHeader::GetExtenstionChannelNumber (void) +{ + return m_channel; +} + +void +WsmpHeader::SetExtensionDataRate (uint8_t dataRate) +{ + m_datarate = dataRate; +} + +uint8_t +WsmpHeader::GetExtensionDataRate (void) +{ + return m_datarate; +} + +void +WsmpHeader::SetExtensionTxPower (int8_t txPowerUsed) +{ + m_power = txPowerUsed; +} + +int8_t +WsmpHeader::GetExtensionTxPower (void) +{ + return m_power; +} + +void +WsmpHeader::SetElementId (WsmpElementId id) +{ + switch (id) + { + case WSMP_N: + m_id = ELEMENT_ID_WSMP_N; + break; + case WSMP_S: + m_id = ELEMENT_ID_WSMP_S; + break; + case WSMP_I: + m_id = ELEMENT_ID_WSMP_I; + break; + default: + NS_FATAL_ERROR("Element ID " << id << " cannot be identified"); + break; + } +} + +WsmpElementId +WsmpHeader::GetElementId (void) +{ + switch (m_id) + { + case ELEMENT_ID_WSMP_N: + return WSMP_N; + case ELEMENT_ID_WSMP_S: + return WSMP_S; + case ELEMENT_ID_WSMP_I: + return WSMP_I; + default: + return WSMP_UNKNOW; + } +} + +void +WsmpHeader::SetLength(uint16_t length) +{ + m_length = length; +} + +uint16_t +WsmpHeader::GetLength (void) +{ + return m_length; +} + +void +WsmpHeader::Reset (void) +{ + m_version = 0; + m_psid = Psid (); + m_channel = 0; + m_datarate = 0; + m_power = 0; + m_id = ELEMENT_ID_WSMP_N; + m_length = 0; +} + +TypeId +WsmpHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WsmpHeader") + .SetParent
() + .SetGroupName ("Wave") + .AddConstructor () + ; + return tid; +} + +TypeId +WsmpHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void +WsmpHeader::Print (std::ostream &os) const +{ + os << "m_version=" << m_version << ", "; + + if (m_channel != 0) + os << "m_channel=" << m_channel << ", "; + if (m_datarate != 0) + os << "m_datarate=" << m_datarate << ", "; + if (m_power != 0) + os << "m_power=" << m_power << ", "; + + os << "m_id=" << m_id << ", "; + os << "m_length" << m_length; +} + +uint32_t +WsmpHeader::GetSerializedSize (void) const +{ + return 1 + + m_psid.GetLength() + + (m_channel == 0 ? 0 : 3) + + (m_datarate== 0 ? 0 : 3) + + (m_power == 0 ? 0 : 3) + + 1 + + 2; +} + +void +WsmpHeader::Serialize (Buffer::Iterator start) const +{ + start.WriteU8(m_version & WSMP_VERSION_MASK); + + const uint8_t * data = m_psid.GetData(); + for (uint8_t i = 0; i != m_psid.GetLength(); i++) + start.WriteU8(data[i]); + + if (m_channel) + { + start.WriteU8(ELEMENT_ID_CHANNEL_NUMBER); + start.WriteU8(ELEMENT_LENGTH_ONE); + start.WriteU8(m_channel); + } + if(m_datarate) + { + start.WriteU8(ELEMENT_ID_DATARATE); + start.WriteU8(ELEMENT_LENGTH_ONE); + start.WriteU8(m_datarate); + } + if (m_power) + { + start.WriteU8(ELEMENT_ID_TX_POWER); + start.WriteU8(ELEMENT_LENGTH_ONE); + start.WriteU8((uint8_t)m_power); + } + + start.WriteU8(m_id); + start.WriteHtonU16(m_length); +} + +uint32_t +WsmpHeader::Deserialize (Buffer::Iterator start) +{ +// Reset(); + m_version = start.ReadU8() & WSMP_VERSION_MASK; + + int length = start.PeekU8(); + if (length <= PSID_LENGTH_MASK_ONE) + length = 1; + else if (length <= PSID_LENGTH_MASK_TWO) + length= 2; + else if (length <= PSID_LENGTH_MASK_THREE) + length= 3; + else if (length <= PSID_LENGTH_MASK_FOUR) + length= 4; + else + length = 0; + uint8_t * data = new uint8_t[length]; + for (uint8_t i = 0; i != length; i++) + data[i] = start.ReadU8(); + m_psid = Psid (data, length); + delete[] data; + + for (int times = 0; times < 3; times++) + { + uint8_t extension = start.PeekU8(); + if (extension == ELEMENT_ID_CHANNEL_NUMBER) + { + start.ReadU8(); // discard the extension id + if (start.ReadU8() != ELEMENT_LENGTH_ONE) + NS_FATAL_ERROR("The length field of Channel Number shall be 1"); + m_channel = start.ReadU8(); + } + else if (extension == ELEMENT_ID_DATARATE) + { + start.ReadU8(); // discard the extension id + if (start.ReadU8() != ELEMENT_LENGTH_ONE) + NS_FATAL_ERROR("The length field of DataRate shall be 1"); + m_datarate = start.ReadU8(); + } + else if (extension == ELEMENT_ID_TX_POWER) + { + start.ReadU8(); // discard the extension id + if (start.ReadU8() != ELEMENT_LENGTH_ONE) + NS_FATAL_ERROR("The length field of Tx Power shall be 1"); + m_power = (int8_t)start.ReadU8(); + } + else + { + break; + } + } + + m_id = start.ReadU8 (); + m_length = start.ReadNtohU16 (); + return GetSerializedSize (); +} + +} // namespace ns3 diff -r f6eaede3f93d src/wave/model/wsmp-header.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-header.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,103 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ + +#ifndef WSMP_HEADER_H +#define WSMP_HEADER_H + +#include "ns3/header.h" +#include "wsmp-socket.h" + +namespace ns3 { + +/** + * \ingroup wave + * \brief Packet header for WSMP packets + * + * See IEEE 1609.3 Annex G.2 WSM example + */ +class WsmpHeader : public Header +{ +public: + + /** + * \brief Constructor + * + * Creates a null header + */ + WsmpHeader (); + virtual ~WsmpHeader (); + + /** + * \brief The maximum header size for WSMP header. + */ + static const uint16_t MAX_HEADER_SIZE; + /** + * \brief The minimum header size for WSMP header. + */ + static const uint16_t MIN_HEADER_SIZE; + + void SetVersion(uint8_t version); + uint8_t GetVersion (void); + + void SetPsid (Psid psid); + Psid GetPsid (void); + + void SetExtensionChannelNumber (uint8_t channelNumber); + uint8_t GetExtenstionChannelNumber (void); + + void SetExtensionDataRate (uint8_t dataRate); + uint8_t GetExtensionDataRate (void); + + void SetExtensionTxPower (int8_t txPowerUsed); + int8_t GetExtensionTxPower (void); + + void SetElementId (WsmpElementId id); + WsmpElementId GetElementId (void); + + void SetLength(uint16_t length); + uint16_t GetLength (void); + + void Reset (void); + + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + +private: + uint8_t m_version; + Psid m_psid; + uint8_t m_channel; + uint8_t m_datarate; + int8_t m_power; + uint8_t m_id; + uint16_t m_length; +}; + +} // namespace ns3 + +#endif /* WSMP_HEADER */ diff -r f6eaede3f93d src/wave/model/wsmp-protocol.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-protocol.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,475 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#include "ns3/log.h" +#include "ns3/wsmp-header.h" +#include "ns3/object-vector.h" +#include "ns3/wsmp-socket-impl.h" +#include "ns3/wsmp-socket-factory-impl.h" +#include "wsmp-protocol.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("WsmpProtocol"); + +NS_OBJECT_ENSURE_REGISTERED (WsmpProtocol); + +// see 5.2 of IEEE 1609.3 +const uint16_t WsmpProtocol::PROT_NUMBER = 0x88dc; +// see 8.3.2 of IEEE 1609.3 +const uint8_t WsmpProtocol::VERSION = 0x02; + +TypeId +WsmpProtocol::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WsmpProtocol") + .SetParent () + .SetGroupName("Wave") + .AddConstructor () + .AddAttribute ("SocketList", "The list of sockets associated to this protocol.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&WsmpProtocol::m_sockets), + MakeObjectVectorChecker ()) + .AddAttribute ("WsmMaxLength", "The max length for WSMP header and WSM data.", + UintegerValue (1400), + MakeUintegerAccessor (&WsmpProtocol::m_wsmMaxLength), + MakeUintegerChecker ()); + return tid; +} + +WsmpProtocol::WsmpProtocol() +: m_node(0), + m_wsmMaxLength(0) +{ + NS_LOG_FUNCTION_NOARGS (); +} + +WsmpProtocol::~WsmpProtocol() +{ + NS_LOG_FUNCTION_NOARGS (); +} + +void +WsmpProtocol::DoDispose (void) +{ + for (std::vector >::iterator i = m_sockets.begin (); i != m_sockets.end (); ++i) + { + *i = 0; + } + m_sockets.clear (); + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); ++i) + { + delete (*i); + } + m_endpoints.clear(); + + m_node = 0; + m_downTarget.Nullify (); + Object::DoDispose (); +} + +void +WsmpProtocol::NotifyNewAggregate (void) +{ + NS_LOG_FUNCTION (this); + if (m_node != 0) + return; + + Ptr node = this->GetObject (); + SetNode (node); + Ptr wsmpFactory = CreateObject (); + wsmpFactory->SetWsmp (this); + node->AggregateObject (wsmpFactory); + + Ptr device = DynamicCast(node->GetDevice(0)); + if (device == 0) + NS_FATAL_ERROR_NO_MSG(); + node->RegisterProtocolHandler (MakeCallback (&WsmpProtocol::Receive, this), WsmpProtocol::PROT_NUMBER, device); + m_downTarget = MakeCallback (&WaveNetDevice::SendX, device); + + Object::NotifyNewAggregate (); +} + +void +WsmpProtocol::SetNode (Ptr node) +{ + NS_LOG_FUNCTION (this << node); + m_node = node; +} + +Ptr +WsmpProtocol::GetNode (void) +{ + NS_LOG_FUNCTION (this); + return m_node; +} + +uint16_t +WsmpProtocol::GetProtocolNumber (void) +{ + NS_LOG_FUNCTION (this); + return PROT_NUMBER; +} + +uint8_t +WsmpProtocol::GetVersion (void) +{ + NS_LOG_FUNCTION (this); + return VERSION; +} + +uint32_t +WsmpProtocol::GetWsmMaxLength (void) +{ + NS_LOG_FUNCTION (this); + return m_wsmMaxLength; +} + +uint8_t +WsmpProtocol::GetPowerLevel (int8_t power) +{ + // Currently WsmpProtocol supposes that: + // (1) The Node has only single WaveNetDevice + // (2) and The WaveNetDevice only has single WifiPhy. + Ptr device = DynamicCast(m_node->GetDevice(0)); + Ptr phy = device->GetPhy(0); + double start = phy->GetTxPowerStart(); + double end = phy->GetTxPowerEnd(); + uint32_t levels = phy->GetNTxPower(); + + for (uint32_t level = levels; level != 0; level--) + { + // This implementation refers to YansWifiPhy::GetPowerDbm + double dbm = start + level * (end - start) / (levels - 1); + if (dbm <= power) + return level; + } + + return 0; +} + +WifiMode +WsmpProtocol::GetDataRate (uint8_t datarate) +{ + //Currently WsmpProtocol supposes that: + // (1) The Node has only single WaveNetDevice + // (2) and The WaveNetDevice only has single WifiPhy. + Ptr device = DynamicCast(m_node->GetDevice(0)); + Ptr phy = device->GetPhy(0); + + if (datarate * 0.5 <= 3.0) + return WifiPhy::GetOfdmRate3MbpsBW10MHz (); + if (datarate * 0.5 <= 4.5) + return WifiPhy::GetOfdmRate4_5MbpsBW10MHz (); + if (datarate * 0.5 <= 6.0) + return WifiPhy::GetOfdmRate6MbpsBW10MHz (); + if (datarate * 0.5 <= 9.0) + return WifiPhy::GetOfdmRate9MbpsBW10MHz (); + if (datarate * 0.5 <= 12.0) + return WifiPhy::GetOfdmRate12MbpsBW10MHz (); + if (datarate * 0.5 <= 18.0) + return WifiPhy::GetOfdmRate18MbpsBW10MHz (); + if (datarate * 0.5 <= 24.0) + return WifiPhy::GetOfdmRate24MbpsBW10MHz (); + if (datarate * 0.5 <= 27.0) + return WifiPhy::GetOfdmRate27MbpsBW10MHz (); + + return WifiMode (); +} + +int +WsmpProtocol::Send (Ptr packet, Address peer, Psid psid, WsmpInfo info) +{ + NS_LOG_FUNCTION (this << packet << peer << psid << &info); + uint8_t channel = info.GetChannelNumber(); + uint8_t power = info.GetTxPower(); + uint8_t datarate = info.GetDataRate(); + uint8_t priority = info.GetUserPriority(); + + // create a WSMP header + WsmpHeader header; + header.SetVersion(VERSION); + header.SetPsid(psid); + if (channel != 0 && info.IsChannelNumberExtension()) + { + header.SetExtensionChannelNumber(channel); + } + if (power != 0 && info.IsTxPowerExtension()) + { + header.SetExtensionTxPower(power); + } + if (datarate != 0 && info.IsDatatRateExtension()) + { + header.SetExtensionDataRate(datarate); + } + header.SetElementId(info.GetElementId()); + header.SetLength(packet->GetSize()); + packet->AddHeader (header); + + if (packet->GetSize() > m_wsmMaxLength) + { + NS_LOG_WARN ("The packet size exceeds the allowable maximum size " << m_wsmMaxLength); + return -1; + } + + TxInfo txInfo; + if (channel != 0) + { + txInfo.channelNumber = channel; + } + if (power != 0) + { + uint8_t level = GetPowerLevel (power); + + if (level == 0) + { + NS_LOG_WARN ("cannot find the appropriate TxPowerLevel for request power " << power); + return -2; + } + txInfo.txPowerLevel = level; + } + if (datarate != 0) + { + WifiMode mode = GetDataRate (datarate); + if (mode.GetUid () == 0) + { + NS_LOG_WARN("cannot determine the appropriate DataRate for request datarate " << datarate); + return -3; + } + txInfo.dataRate = mode; + } + txInfo.priority = priority; + + bool result = m_downTarget (packet, peer, PROT_NUMBER, txInfo); + if(!result) + { + NS_LOG_WARN("The WaveNetDevice fails to transmit the packet"); + return -4; + } + + return 0; +} + +Ptr +WsmpProtocol::CreateSocket () +{ + NS_LOG_FUNCTION_NOARGS (); + Ptr socket = CreateObject (); + socket->SetWsmp (this); + m_sockets.push_back(socket); + return socket; +} + +bool +WsmpProtocol::AddIndicationCallback (IndicationCallback callback) +{ + NS_LOG_FUNCTION (this << &callback); + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); ++i) + { + if ((*i)->indication.IsEqual (callback)) + { + NS_LOG_WARN ("The parameter callback is already registered"); + return false; + } + } + + /** + * A special "null" PSID indicates that this is a willcard callback. + * Any coming WSMP packets will notify this registered willcard callback. + */ + Psid nullPsid = Psid (); + + EndPoint * endpoint = new EndPoint(); + endpoint->psid = nullPsid; + endpoint->indication = callback; + m_endpoints.push_back(endpoint); + return true; +} + +bool +WsmpProtocol::AddIndicationCallback (Psid psid, IndicationCallback callback) +{ + NS_LOG_FUNCTION (this << psid << &callback); + + if (psid.IsNull ()) + { + NS_LOG_WARN ("The parameter psid is null"); + return false; + } + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); ++i) + { + if ((*i)->psid == psid) + { + NS_LOG_WARN ("The parameter psid is already registered"); + return false; + } + } + + EndPoint * endpoint = new EndPoint(); + endpoint->psid = psid; + endpoint->indication = callback; + m_endpoints.push_back(endpoint); + return true; +} + +bool +WsmpProtocol::RemoveIndicationCallback (Psid psid) +{ + NS_LOG_FUNCTION (this << psid); + + if (psid.IsNull ()) + { + NS_LOG_WARN ("The parameter psid is null"); + return false; + } + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); i++) + { + if ((*i)->psid == psid) + { + delete (*i); + m_endpoints.erase(i); + return true; + } + } + + return false; +} + +bool +WsmpProtocol::RemoveIndicationCallback (IndicationCallback callback) +{ + NS_LOG_FUNCTION (this << &callback); + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); i++) + { + if ((*i)->indication.IsEqual (callback)) + { + delete (*i); + m_endpoints.erase(i); + return true; + } + } + + return false; +} + +void +WsmpProtocol::RemoveWillcardCallbacks (void) +{ + NS_LOG_FUNCTION (this); + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end();) + { + if ((*i)->psid.IsNull ()) + { + delete (*i); + i = m_endpoints.erase (i); + } + else + { + i++; + } + } +} + +void +WsmpProtocol::RemoveAllCallbacks (void) +{ + NS_LOG_FUNCTION (this); + + for (std::vector::iterator i = m_endpoints.begin (); i != m_endpoints.end (); ++i) + { + delete (*i); + } + m_endpoints.clear (); +} + +void +WsmpProtocol::Receive ( Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType) +{ + NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType); + + Ptr pkt = p->Copy (); // need to pass a non-const packet up + + WsmpHeader header; + pkt->RemoveHeader (header); + + if (header.GetVersion() > VERSION) + { + NS_LOG_WARN ("The version in the WMSP header is not the supported version"); + return; + } + + Psid psid = header.GetPsid (); + if (!psid.IsValid ()) + { + NS_LOG_WARN ("The PSID in the WSMP header is invalid"); + return; + } + + WsmpInfo info; + if (header.GetExtenstionChannelNumber() != 0) + { + info.SetChannelNumber(header.GetExtenstionChannelNumber(), true); + } + if (header.GetExtensionTxPower() != 0) + { + info.SetTxPower(header.GetExtensionTxPower(), true); + } + if (header.GetExtensionDataRate() != 0) + { + info.SetDataRate(header.GetExtensionDataRate(), true); + } + + WsmpElementId id = header.GetElementId(); + if (id != WSMP_N) + { + NS_LOG_WARN ("The WAVE Element ID in the WSMP header is not supported"); + return; + } + + uint16_t length = header.GetLength(); + if (length != pkt->GetSize()) + { + NS_LOG_WARN ("The length in the WSMP header is same with the received data length"); + return; + } + + for (std::vector::iterator i = m_endpoints.begin(); i != m_endpoints.end(); ++i) + { + if ((*i)->psid == psid) + { + IndicationCallback indication = (*i)->indication; + indication(pkt->Copy(), from, psid, info); + return; + } + + if ((*i)->psid.IsNull ()) + { + IndicationCallback indication = (*i)->indication; + indication(pkt->Copy(), from, psid, info); + continue; + } + } +} + +} // namespace ns3 diff -r f6eaede3f93d src/wave/model/wsmp-protocol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-protocol.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,208 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#ifndef WSMP_PROTOCOL_H +#define WSMP_PROTOCOL_H + +#include "ns3/address.h" +#include "ns3/wsmp-socket.h" +#include "ns3/wave-net-device.h" +#include "ns3/wifi-mode.h" +#include + +namespace ns3 { + +class WsmpSocket; + +/** + * \brief Implementation of the WSMP protocol + * \ingroup wave + * +* A few things to keep in mind about this type protocol of WSMP: +* - WSMP is similar, but different from UDP. +* - WSMP uses PSID to identify service rather than port in UDP. +* - WSMP only use single PSID rather than source port and destination ports in UDP +* - WSMP can specify some tx parameters for transmit. +* +* Different from Ipv4L3Protocol class which will internally support add multiple +* NetDevice and UdpL4Protocol class which will bind these devices with IP address and Port, +* currently WsmpProtocol class will only support add and bind the single device. +* +* About WsmpSocket API, IEEE 1609.3 only defines three service primitives: +* - WSM-WaveShortMessage.request +* - WSM-WaveShortMessage.confirm +* - WSM-WaveShortMessage.indication +* Therefore, WsmpProtocol class here provides two methods to support service primitives: +* Send +* IndicationCallback +*/ +class WsmpProtocol : public Object { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + WsmpProtocol(); + virtual ~WsmpProtocol(); + + /** + * \brief The protocol number for WSMP (0x88DC). + */ + static const uint16_t PROT_NUMBER; + /** + * \brief The protocol version for WSMP (2). + */ + static const uint8_t VERSION; + + /** + * Set node associated with this stack + * \param node the node + */ + void SetNode (Ptr node); + + /** + * \return the associated node + */ + Ptr GetNode (void); + + /** + * \return the protocol number (or Ethertype) + */ + uint16_t GetProtocolNumber (void); + + /** + * \return which version of WSMP protocol + */ + uint8_t GetVersion (void); + + /** + * \return the allowable maximum length for WSMP header and WSM data. + */ + uint32_t GetWsmMaxLength (void); + + /** + * \return A smart Socket pointer to a WsmpSocket, allocated by this instance + * of the WSMP protocol + */ + Ptr CreateSocket (void); + + /** + * \param packet packet to send + * \param peer peer address of packet + * \param psid psid of packet + * \param info tx information + * \return + */ + int Send (Ptr packet, Address peer, Psid psid, WsmpInfo info); + + /** + * IndicationCallback signature for packet receipt events. + * + * \param packet the packet. + * \param address the peer adress + * \param psid the psid of this packet + * \param info the extension wsmp information of this packet + * \return the callback result + */ + typedef Callback< bool, Ptr, const Address &, const Psid &, const WsmpInfo & > IndicationCallback; + + /** + * \brief Add a normal IndicationCallback + * \param psid the psid specify which type WSMP packets will be delivered + * \param callback the callback which will be notified + * \return whether succeed or fail + */ + bool AddIndicationCallback (Psid psid, IndicationCallback callback); + /** + * \brief Add a willcard IndicationCallback + * \return whether succeed or fail + * + * Any coming WSMP packets will notify this callback. + */ + bool AddIndicationCallback (IndicationCallback callback); + + /** + * \brief Remove IndicationCallback indicated by PSID + * \param psid the psid + * \return whether succeed or fail + */ + bool RemoveIndicationCallback (Psid psid); + /** + * \brief Remove IndicationCallback indicated by callback + * \param callback the callback + * \return whether succeed or fail + */ + bool RemoveIndicationCallback (IndicationCallback callback); + /** + * \brief Remove all of wildcard IndicationCallback + */ + void RemoveWillcardCallbacks (void); + /** + * \brief Remove all of IndicationCallback + */ + void RemoveAllCallbacks (void); + +protected: + /** + * \brief Allocate a local endpoint for this socket. + * \param address the address to try to allocate + */ + void Receive (Ptr device, Ptr p, uint16_t protocol, const Address &from, + const Address &to, NetDevice::PacketType packetType); + + virtual void DoDispose (void); + /* + * This function will notify other components connected to the node that a new stack member is now connected + */ + virtual void NotifyNewAggregate (void); + + /** + * The IEEE 1609.3 specifies parameter "power", while IEEE 1609.4 specifies parameter "power level". + * Here this function will do convert operation. + */ + uint8_t GetPowerLevel (int8_t power); + /** + * Here this function will do convert operation. + */ + WifiMode GetDataRate (uint8_t datarate); + +private: + Ptr m_node; + uint32_t m_wsmMaxLength; + + /** + * \brief callback to send packets over WaveNetDevice::SendX method + */ + typedef Callback, const Address &, uint32_t, const TxInfo & > SendXCallback; + SendXCallback m_downTarget; + + std::vector > m_sockets; + + struct EndPoint + { + Psid psid; + IndicationCallback indication; + }; + + std::vector m_endpoints; +}; + +} // namespace ns3 + +#endif /* WSMP_PROTOCOL_H */ diff -r f6eaede3f93d src/wave/model/wsmp-socket-factory-impl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-factory-impl.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,55 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ + +#include "wsmp-socket-factory-impl.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (WsmpSocketFactoryImpl); + +WsmpSocketFactoryImpl::WsmpSocketFactoryImpl () +: m_wsmp (0) +{ +} +WsmpSocketFactoryImpl::~WsmpSocketFactoryImpl () +{ +} + +void +WsmpSocketFactoryImpl::SetWsmp (Ptr wsmp) +{ + m_wsmp = wsmp; +} + +Ptr +WsmpSocketFactoryImpl::CreateSocket (void) +{ + return m_wsmp->CreateSocket(); +} + +void +WsmpSocketFactoryImpl::DoDispose (void) +{ + m_wsmp = 0; + WsmpSocketFactory::DoDispose (); +} + +} // namespace ns3 diff -r f6eaede3f93d src/wave/model/wsmp-socket-factory-impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-factory-impl.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ +#ifndef WSMP_SOCKET_FACTORY_IMPL_H +#define WSMP_SOCKET_FACTORY_IMPL_H + +#include "wsmp-socket.h" +#include "wsmp-socket-factory.h" +#include "wsmp-protocol.h" + +namespace ns3 { + +/** + * \ingroup wave + * \brief Object to create WSMP socket instances + * + * This class implements the API for creating WSMP sockets. + * It is a socket factory (deriving from class WsmpSocketFactory). + */ +class WsmpSocketFactoryImpl : public WsmpSocketFactory +{ +public: + WsmpSocketFactoryImpl (); + virtual ~WsmpSocketFactoryImpl (); + + /** + * \brief Set the associated WSMP protocol. + * \param udp the WSMP protocol + */ + void SetWsmp (Ptr wsmp); + + /** + * \brief Implements a method to create a Wsmp-based socket and return + * a base class smart pointer to the socket. + * + * \return smart pointer to Socket + */ + virtual Ptr CreateSocket (void); + +protected: + virtual void DoDispose (void); + +private: + Ptr m_wsmp; +}; + +} // namespace ns3 + +#endif /* WSMP_SOCKET_FACTORY_IMPL_H */ diff -r f6eaede3f93d src/wave/model/wsmp-socket-factory.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-factory.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,48 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ + +#include "wsmp-socket-factory.h" + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (WsmpSocketFactory); + + +TypeId WsmpSocketFactory::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WsmpSocketFactory") + .SetParent () + .SetGroupName ("Wave") + ; + return tid; +} + + +WsmpSocketFactory::WsmpSocketFactory () +{ +} + +WsmpSocketFactory::~WsmpSocketFactory () +{ +} + +} // namespace ns3 + diff -r f6eaede3f93d src/wave/model/wsmp-socket-factory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-factory.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,63 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * 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: Mathieu Lacage + * Author: Junling Bu + */ + +#ifndef WSMP_SOCKET_FACTORY_H +#define WSMP_SOCKET_FACTORY_H + +#include "ns3/wsmp-socket.h" + +namespace ns3 { + +class WsmpSocket; + +/** + * \ingroup wave + * + * \brief API to create WSMP socket instances + * + * This abstract class defines the API for WSMP socket factory. + * All WSMP implementations must provide an implementation of CreateSocket + * below. + * + * \see WsmpSocketFactoryImpl + */ +class WsmpSocketFactory : public Object { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + WsmpSocketFactory (); + virtual ~WsmpSocketFactory(); + + /** + * \return smart pointer to Socket + * + * Base class method for creating socket instances. + */ + virtual Ptr CreateSocket (void) = 0; +}; + +} // namespace ns3 + +#endif /* WSMP_SOCKET_FACTORY_H */ diff -r f6eaede3f93d src/wave/model/wsmp-socket-impl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-impl.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,236 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#include "ns3/log.h" +#include "ns3/wave-net-device.h" +#include "ns3/wsmp-header.h" +#include "wsmp-socket-impl.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("WsmpSocketImpl"); + +NS_OBJECT_ENSURE_REGISTERED (WsmpSocketImpl); + +TypeId +WsmpSocketImpl::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WsmpSocketImpl") + .SetParent () + .SetGroupName("Wave") + .AddAttribute ("RcvBufSize", + "WsmpSocket maximum receive buffer size (bytes)", + UintegerValue (131072), + MakeUintegerAccessor (&WsmpSocketImpl::GetRcvBufSize, + &WsmpSocketImpl::SetRcvBufSize), + MakeUintegerChecker ()); + return tid; +} + +WsmpSocketImpl::WsmpSocketImpl() +: m_node (0), + m_wsmp (0), + m_connected (false), + m_binded (false), + m_rcvBufSize (0), + m_rxAvailable (0) +{ +} + +WsmpSocketImpl::~WsmpSocketImpl() +{ +} + +void +WsmpSocketImpl::SetWsmp(Ptr wsmp) +{ + NS_LOG_FUNCTION (this << wsmp); + m_wsmp = wsmp; +} + +void +WsmpSocketImpl::SetRcvBufSize (uint32_t size) +{ + NS_LOG_FUNCTION (this << size); + m_rcvBufSize = size; +} + +uint32_t +WsmpSocketImpl::GetRcvBufSize (void) const +{ + NS_LOG_FUNCTION (this); + return m_rcvBufSize; +} +int +WsmpSocketImpl::Bind (const Psid &psid) +{ + NS_LOG_FUNCTION (this << psid); + + if (m_binded) + return -1; + + m_callback = MakeCallback (&WsmpSocketImpl::ForwardUp, this); + m_binded = m_wsmp->AddIndicationCallback(psid, m_callback); + if (!m_binded) + return -2; + + return 0; +} + +int +WsmpSocketImpl::Bind (void) +{ + NS_LOG_FUNCTION (this); + + if (m_binded) + return -1; + + m_callback = MakeCallback (&WsmpSocketImpl::ForwardUp, this); + m_binded = m_wsmp->AddIndicationCallback(m_callback); + + if (!m_binded) + return -2; + + return 0; +} + +uint32_t +WsmpSocketImpl::GetTxAvailable (void) const +{ + NS_LOG_FUNCTION (this); + // Since WSMP header is variable, here we choose a conservative way. + return m_wsmp->GetWsmMaxLength () - WsmpHeader::MAX_HEADER_SIZE; +} + +uint32_t +WsmpSocketImpl::GetRxAvailable (void) const +{ + NS_LOG_FUNCTION (this); + // We separately maintain this state to avoid walking the queue + // every time this might be called + return m_rxAvailable; +} + +Ptr +WsmpSocketImpl::Recv () +{ + NS_LOG_FUNCTION (this); + + if (m_deliveryQueue.empty ()) + return 0; + + RecvedPacket* p = m_deliveryQueue.front (); + m_deliveryQueue.pop (); + Ptr pkt = p->packet; + m_rxAvailable -= pkt->GetSize(); + delete p; + return pkt; +} + +Ptr +WsmpSocketImpl::RecvFrom (Address & address, Psid & psid, WsmpInfo & wsmpInfo) +{ + NS_LOG_FUNCTION (this); + if (m_deliveryQueue.empty ()) + return 0; + + RecvedPacket* p = m_deliveryQueue.front (); + m_deliveryQueue.pop (); + Ptr pkt = p->packet; + address = p->peer; + psid = p->psid; + m_rxAvailable -= pkt->GetSize (); + delete p; + return pkt; +} + +int +WsmpSocketImpl::Connect (const Psid &psid) +{ + NS_LOG_FUNCTION (this); + return Connect (Mac48Address::GetBroadcast(), psid); +} +int +WsmpSocketImpl::Connect (const Address &peer, const Psid &psid) +{ + NS_LOG_FUNCTION (this); + return Connect (peer, psid, WsmpInfo ()); +} + +int +WsmpSocketImpl::Connect (const Address &peer, const Psid &psid, const WsmpInfo &wsmpInfo) +{ + NS_LOG_FUNCTION (this); + m_defaultPeer = peer; + m_defaultPsid = psid; + m_defaultWsmpInfo = wsmpInfo; + m_connected = true; + return 0; +} + +int +WsmpSocketImpl::Send (Ptr packet) +{ + NS_LOG_FUNCTION (this << packet); + if (!m_connected) + { + return -1; + } + + return m_wsmp->Send(packet, m_defaultPeer, m_defaultPsid, m_defaultWsmpInfo); +} + +int +WsmpSocketImpl::SendTo (Ptr packet, const Address & peer, const Psid & psid, const WsmpInfo & wsmpInfo) +{ + NS_LOG_FUNCTION (this << packet << peer << psid << &wsmpInfo); + return m_wsmp->Send(packet, peer, psid, wsmpInfo); +} + +bool +WsmpSocketImpl::ForwardUp (Ptr pkt, const Address & sender, const Psid & psid, const WsmpInfo & wsmpInfo) +{ + if ((m_rxAvailable + pkt->GetSize ()) <= m_rcvBufSize) + { + RecvedPacket * recv = new RecvedPacket(); + recv->packet = pkt; + recv->psid =psid; + recv->peer = sender; + m_deliveryQueue.push (recv); + m_rxAvailable += pkt->GetSize (); + NotifyDataRecv (); + return true; + } + + return false; +} + +int +WsmpSocketImpl::Close (void) +{ + NS_LOG_FUNCTION (this); + if (m_binded) + { + m_binded = false; + m_wsmp->RemoveIndicationCallback(m_callback); + } + return 0; +} + + +} // namespace ns3 diff -r f6eaede3f93d src/wave/model/wsmp-socket-impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket-impl.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#ifndef WSMP_SOCKET_IMPL_H +#define WSMP_SOCKET_IMPL_H + +#include "ns3/wsmp-socket.h" +#include "ns3/wsmp-protocol.h" +#include + +namespace ns3 { + +class WsmpProtocol; + +/** + * \ingroup wave + * \brief A sockets interface to WSMP + * + * This class subclasses ns3::WsmpSocket, and provides a socket interface + * to ns3's implementation of WSMP. + * This class refers to the class UdpSocketImpl +*/ +class WsmpSocketImpl : public WsmpSocket { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + WsmpSocketImpl(); + virtual ~WsmpSocketImpl(); + + /** + * \brief Set the associated WSMP protocol. + * \param wsmp the WSMP protocol + */ + void SetWsmp (Ptr wsmp); + + /** + * \brief Set the internal buffer size for Recv.. + * \param size the buffer size. + */ + void SetRcvBufSize (uint32_t size); + /** + * \return the internal buffer size for Recv. + */ + uint32_t GetRcvBufSize (void) const; + + virtual int Bind (void); + virtual int Bind (const Psid &psid); + + virtual int Connect (const Psid &psid); + virtual int Connect (const Address &peer, const Psid &psid); + virtual int Connect (const Address &peer, const Psid &psid, const WsmpInfo &info); + + virtual int Send (Ptr p); + virtual int SendTo (Ptr packet, const Address & peer, const Psid & psid, const WsmpInfo & wsmpInfo); + + virtual Ptr Recv (void); + virtual Ptr RecvFrom (Address & address, Psid & psid, WsmpInfo & wsmpInfo); + + virtual uint32_t GetTxAvailable (void) const; + virtual uint32_t GetRxAvailable (void) const; + + virtual int Close (void); + +private: + bool ForwardUp (Ptr pkt, const Address & sender, const Psid & psid, const WsmpInfo & wsmpInfo); + + Ptr m_node; + Ptr m_wsmp; + + bool m_connected; + Address m_defaultPeer; + Psid m_defaultPsid; + WsmpInfo m_defaultWsmpInfo; + + bool m_binded; + WsmpProtocol::IndicationCallback m_callback; + + uint32_t m_rcvBufSize; + uint32_t m_rxAvailable; + + struct RecvedPacket + { + Psid psid; + Address peer; + Ptr packet; + }; + std::queue m_deliveryQueue; //!< Queue for incoming packets +}; + +} // namespace ns3 + +#endif /* WSMP_SOCKET_IMPL_H */ diff -r f6eaede3f93d src/wave/model/wsmp-socket.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,216 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#include "ns3/log.h" +#include "ns3/packet.h" +#include "wsmp-socket.h" +#include "wsmp-socket-factory.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("WsmpSocket"); + +NS_OBJECT_ENSURE_REGISTERED (WsmpSocket); + +Psid::Psid () + : m_length (0) +{ +} + +Psid::Psid (uint8_t data0) + : m_length (1) +{ + m_data[0] = data0; + Assert (); +} + +Psid::Psid (uint8_t data0, uint8_t data1) + : m_length (2) +{ + m_data[0] = data0; + m_data[1] = data1; + Assert (); +} + +Psid::Psid (uint8_t data0, uint8_t data1, uint8_t data2) + : m_length (3) +{ + m_data[0] = data0; + m_data[1] = data1; + m_data[2] = data2; + Assert (); +} + +Psid::Psid (uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3) + : m_length (4) +{ + m_data[0] = data0; + m_data[1] = data1; + m_data[2] = data2; + m_data[3] = data3; + Assert (); +} + +Psid::Psid (uint8_t * data, uint8_t length) +{ + if (data == 0 || length > 4) + return; + for (int i = 0; i != length; i++) + m_data[i] = data[i]; + m_length = length; + Assert(); +} + + +void +Psid::Assert (void) +{ + if (!IsValid()) + NS_FATAL_ERROR("Invalid PSID"); +} + +bool +Psid::IsValid (void) const +{ + if (m_length == 0) + return false; + + if (m_data[0] <= PSID_LENGTH_MASK_ONE) + return m_length == 1; + if (m_data[0] <= PSID_LENGTH_MASK_TWO) + return m_length == 2; + if (m_data[0] <= PSID_LENGTH_MASK_THREE) + return m_length == 3; + if (m_data[0] <= PSID_LENGTH_MASK_FOUR) + return m_length == 4; + + return false; +} + +bool +Psid::IsNull (void) const +{ + return m_length == 0; +} + +bool +Psid::IsEqualTo (const Psid & psid) const +{ + if (m_length != psid.m_length) + return false; + for (uint8_t i = 0; i != m_length; i++) + { + if (m_data[i] != psid.m_data[i]) + return false; + } + return true; +} + +const uint8_t * +Psid::GetData (void) const +{ + return m_data; +} + +uint8_t +Psid::GetLength (void) const +{ + return m_length; +} + +std::ostream& operator<< (std::ostream& os, const Psid & psid) +{ + for (uint8_t i = 0; i != psid.m_length; i++) + { + os << psid.m_data[i] << " "; + } + return os; +} + +bool operator == (const Psid &a, const Psid &b) +{ + if (a.m_length != b.m_length) + return false; + for (uint8_t i = 0; i != a.m_length; i++) + { + if (a.m_data[i] != b.m_data[i]) + return false; + } + return true; +} + +bool operator != (const Psid &a, const Psid &b) +{ + if (a.m_length != b.m_length) + return true; + for (uint8_t i = 0; i != a.m_length; i++) + { + if (a.m_data[i] != b.m_data[i]) + return true; + } + return false; +} + +TypeId +WsmpSocket::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::WsmpSocket") + .SetParent () + .SetGroupName("Wave"); + return tid; +} + +WsmpSocket::WsmpSocket() +{ +} + +WsmpSocket::~WsmpSocket() +{ +} + +Ptr +WsmpSocket::CreateSocket (Ptr node, TypeId tid) +{ + NS_LOG_FUNCTION (node << tid); + Ptr s; + NS_ASSERT (node != 0); + Ptr socketFactory = node->GetObject (tid); + NS_ASSERT (socketFactory != 0); + s = socketFactory->CreateSocket (); + NS_ASSERT (s != 0); + return s; +} + +void +WsmpSocket::SetRecvCallback (Callback > callback) +{ + NS_LOG_FUNCTION (this << &callback); + m_receivedData = callback; +} + +void +WsmpSocket::NotifyDataRecv (void) +{ + NS_LOG_FUNCTION (this); + if (!m_receivedData.IsNull ()) + { + m_receivedData (this); + } +} + +} // namespace ns3 diff -r f6eaede3f93d src/wave/model/wsmp-socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/model/wsmp-socket.h Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,371 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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: Junling Bu + */ + +#ifndef WSMP_SOCKET_H +#define WSMP_SOCKET_H + +#include "ns3/node.h" + +namespace ns3 { + +#define PSID_LENGTH_MASK_ONE 0x7f +#define PSID_LENGTH_MASK_TWO 0xbf +#define PSID_LENGTH_MASK_THREE 0xdf +#define PSID_LENGTH_MASK_FOUR 0xef + +/** + * The range of PSID is + * 1. 0x00 ~ 0x7f + * 2. 0x8000 ~ 0xbfff + * 3. 0xc00000 ~ 0xdfffff + * 4. 0xe0000000 ~ 0xefffffff + * Other number will be taken as invalid. + * See IEEE 1609.3 section 8.1.3 and Annex H "PSID examples" + * + * Usage: + * Psid validPsid1 = Psid(0x01); + * Psid validPsid2 = Psid(0x80, 0x01); + * Psid validPsid3 = Psid(0xc0, 0x00, 0x01); + * Psid validPsid4 = Psid(0xef, 0x00, 0x00, 0x01); + * Psid invalidPsid1 = Psid(); // this is an invalid PSID which cannot be used for transmit. + * Psid invalidPsid2 = Psid(0x81); // this is an invalid PSID which cannot be used for transmit. + * + * A special "null" Psid is invalid, but here is used internally by class WsmpProtocol. + * Users should not use the "null" Psid for transmit. + */ + +class Psid { +public: + Psid (); + Psid (uint8_t data0); + Psid (uint8_t data0, uint8_t data1); + Psid (uint8_t data0, uint8_t data1, uint8_t data2); + Psid (uint8_t data0, uint8_t data1, uint8_t data2, uint8_t data3); + Psid (uint8_t * data, uint8_t length); + + bool IsValid (void) const; + + bool IsNull (void) const; + + bool IsEqualTo (const Psid & psid) const; + + const uint8_t * GetData (void) const; + uint8_t GetLength (void) const; + +private: + void Assert (void); + + friend std::ostream& operator<< (std::ostream& os, const Psid & psid); + friend bool operator == (const Psid &a, const Psid &b); + friend bool operator != (const Psid &a, const Psid &b); + + uint8_t m_data[4]; + uint8_t m_length; +}; + +std::ostream& operator<< (std::ostream& os, const Psid & psid); +bool operator == (const Psid &a, const Psid &b); +bool operator != (const Psid &a, const Psid &b); + +/** + * WSMP Normal, see 5.5, 7.3.2 + * WSMP Safety supplement, see Annex F + * WSMP Identify supplement, see IEEE 1609.1 + * + */ +enum WsmpElementId { + WSMP_N, + WSMP_S, + WSMP_I, + WSMP_UNKNOW, +}; + +class WsmpInfo { +public: + WsmpInfo () + : m_channel (0), + m_channelExtension (false), + m_datarate (0), + m_datarateExtension (false), + m_power (0), + m_powerExtension (false), + m_id (WSMP_N), + m_priority (7) + { + + } + + void SetChannelNumber (uint8_t channel, bool extensonEnabled) + { + m_channel = channel; + m_channelExtension = extensonEnabled; + } + + uint8_t GetChannelNumber (void) + { + return m_channel; + } + + bool IsChannelNumberExtension (void) + { + return m_channelExtension; + } + + void SetDataRate (uint8_t datarate, bool extensionEnabled) + { + m_datarate = datarate; + m_datarateExtension = extensionEnabled; + } + + uint8_t GetDataRate (void) + { + return m_datarate; + } + + bool IsDatatRateExtension (void) + { + return m_datarateExtension; + } + + void SetTxPower (uint8_t power, bool extensionEnabled) + { + m_power = power; + m_powerExtension = extensionEnabled; + } + + uint8_t GetTxPower (void) + { + return m_power; + } + + bool IsTxPowerExtension (void) + { + return m_powerExtension; + } + + void SetElementId (WsmpElementId id) + { + m_id = id; + } + + WsmpElementId GetElementId (void) + { + return m_id; + } + + void SetUserPriority (uint8_t priority) + { + m_priority = priority; + } + + uint8_t GetUserPriority (void) + { + return m_priority; + } + +private: + uint8_t m_channel; + bool m_channelExtension; + uint8_t m_datarate; + bool m_datarateExtension; + uint8_t m_power; + bool m_powerExtension; + WsmpElementId m_id; + uint8_t m_priority; +}; + +/** + * \brief A low-level Socket API + * \ingroup wave + * + * WsmpSocket API is similar with BSD Socket API, but still differs from BSD Socket API, + * thus this class does not inherit directly from ns3::Socket class. + * +* To satisfy users who are familiar with UDP, here also providers connectionless methods. +* - For transmit: Connect, Send, Close +* - For receipt: Bind, Recv, Close. +* +* Usage: +* TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); +* +* Ptr recv = WsmpSocket::CreateSocket (c.Get (0), tid); +* Psid psid = Psid(0x80, 0x01); +* recv->Bind (psid); +* recv->SetRecvCallback (MakeCallback (&ReceivePacket)); +* +* Ptr source = WsmpSocket::CreateSocket (c.Get (1), tid); +* source->Connect (Mac48Address::GetBroadcast(), psid); +* Simulator::Schedule(Seconds (1.0), &SendPacket, source); +*/ +class WsmpSocket : public Object { +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + WsmpSocket(); + virtual ~WsmpSocket(); + + /** + * This method wraps the creation of sockets that is performed + * on a given node by a WsmpSocketFactory specified by TypeId. + * + * \return A smart pointer to a newly created socket. + * + * \param node The node on which to create the socket + * \param tid The TypeId of a WsmpSocketFactory class to use + */ + static Ptr CreateSocket (Ptr node, TypeId tid); + + /** + * \brief Notify application when new data is available to be read. + * \param callback This callback is intended to notify a socket that would + * have been blocked in a blocking socket model that data is available to be read. + */ + void SetRecvCallback (Callback > callback); + + /** + * \brief Allocate a local endpoint for this socket. + * \returns 0 on success, -1 on failure. + * + * Note: This WsmpSocket::Bind() behavior is different from Socket::Bind(). + * Socket::Bind() will randomly select a unused Port for Recv, + * while WsmpSocket::Bind() will only bind a special "null" Psid, so that + * any incoming WSMP packet will notify the RecvCallback. + */ + virtual int Bind (void) = 0; + /** + * \brief Allocate a local endpoint for this socket. + * \param psid the psid to try to allocate + * \returns 0 on success, -1 on failure. + */ + virtual int Bind (const Psid &psid) = 0; + + /** + * \brief Initiate a connection to all of remote hosts + * \param psid Psid of remote. + * \returns 0 on success, -1 on error (in which case errno is set). + * + * Note: Although it is named "connect", the WSMP protocol is only a + * connectionless service, thus this method is just a convenient and + * helpful function for Send (Packet) method. + */ + virtual int Connect (const Psid &psid) = 0; + /** + * \brief Initiate a connection to a remote host + * \param peer the peer address + * \param psid the psid in the WSMP header of this packet + * \returns 0 on success, -1 on error (in which case errno is set). + * + * Note: Although it is named "connect", the WSMP protocol is only a + * connectionless service, thus this method is just a convenient and + * helpful function for Send (Packet) method. + */ + virtual int Connect (const Address &peer, const Psid &psid) = 0; + /** + * \brief Initiate a connection to a remote host + * \param peer the peer address + * \param psid the psid in the WSMP header of this packet + * \param info the transmit and extension information of this packet + * \returns 0 on success, -1 on error (in which case errno is set). + * + * Note: Although it is named "connect", the WSMP protocol is only a + * connectionless service, thus this method is just a convenient and + * helpful function for Send (Packet) method. + */ + virtual int Connect (const Address &peer, const Psid &psid, const WsmpInfo &info) = 0; + + /** + * \brief Send data (or dummy data) to the remote host + * + * \param packet ns3::Packet to send + * \returns the number of bytes accepted for transmission if no error + * occurs, and negative otherwise. + */ + virtual int Send (Ptr packet) = 0; + /** + * \brief Send data (or dummy data) to the remote host + * + * \param packet ns3::Packet to send + * \param peer the peer address + * \param psid the psid in the WSMP header of this packet + * \param info the transmit and extension information of this packet + * \returns the number of bytes accepted for transmission if no error + * occurs, and negative otherwise. + * + * Note: Although WsmpInfo parameter can determine the transmit channel number, + * Users should assign channel access for request channel by using WaveNetDevice::StartSch, + * otherwise the created WaveNetDevice only assigns default continuous CCH channel access. + */ + virtual int SendTo (Ptr packet, const Address & peer, const Psid & psid, const WsmpInfo & info) = 0; + + /** + * \brief Read a single packet from the socket + * + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + virtual Ptr Recv (void) = 0; + /** + * \brief Recv data from the remote host + * + * \param address the peer address + * \param psid the psid in the WMSP header of coming packet + * \param info the extension information in the WSMP header of coming packet + * \returns Ptr of the next in-sequence packet. Returns + * 0 if the socket cannot return a next in-sequence packet. + */ + virtual Ptr RecvFrom (Address & address, Psid & psid, WsmpInfo & info) = 0; + + /** + * \returns The number of bytes which can be sent in a single Send call. + */ + virtual uint32_t GetTxAvailable (void) const = 0; + /** + * Return number of bytes which can be returned from one or + * multiple calls to Recv. + * Must be possible to call this method from the Recv callback. + * + * \returns the number of bytes which can be returned from one or + * multiple Recv calls. + */ + virtual uint32_t GetRxAvailable (void) const = 0; + + /** + * \brief Close a socket. + * \returns zero on success, -1 on failure. + * + * After the Close call, the socket is no longer valid, and cannot + * safely be used for subsequent operations. + */ + virtual int Close (void) = 0; + +protected: + /** + * \brief Notify through the callback (if set) that some data have been received. + */ + void NotifyDataRecv (void); + +private: + Callback > m_receivedData; +}; + +} // namespace ns3 + +#endif /* WSMP_SOCKET_H */ diff -r f6eaede3f93d src/wave/test/examples-to-run.py --- a/src/wave/test/examples-to-run.py Tue Mar 01 20:49:37 2016 +0100 +++ b/src/wave/test/examples-to-run.py Fri Mar 04 23:43:06 2016 +0800 @@ -10,6 +10,7 @@ cpp_examples = [ ("wave-simple-80211p", "True", "True"), ("wave-simple-device", "True", "True"), + ("wave-simple-wsmp", "True", "True"), ] # A list of Python examples to run in order to ensure that they remain diff -r f6eaede3f93d src/wave/test/wsmp-header-test-suite.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/test/wsmp-header-test-suite.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 Dalian University of Technology + * + * 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: Junling Bu + */ +#include "ns3/test.h" +#include "ns3/vector.h" +#include "ns3/string.h" +#include "ns3/wsmp-protocol.h" +#include "ns3/wsmp-header.h" +#include + +using namespace ns3; + +class WsmpHeaderTestCase : public TestCase +{ +public: + WsmpHeaderTestCase (void); + virtual ~WsmpHeaderTestCase (void); +private: + virtual void DoRun (void); + +}; + +WsmpHeaderTestCase::WsmpHeaderTestCase (void) + : TestCase ("WSMP Header") +{ +} + +WsmpHeaderTestCase::~WsmpHeaderTestCase (void) +{ +} + +void +WsmpHeaderTestCase::DoRun () +{ + Ptr packet = Create (reinterpret_cast ("Hello World!"), 13); + + WsmpHeader wsmpHeader = WsmpHeader (); + wsmpHeader.SetVersion(WsmpProtocol::VERSION); + wsmpHeader.SetPsid(Psid (0xc0, 0x03, 0x05)); + wsmpHeader.SetExtensionChannelNumber(172); + wsmpHeader.SetExtensionDataRate(12); + wsmpHeader.SetExtensionTxPower(30); + wsmpHeader.SetElementId(WSMP_N); + wsmpHeader.SetLength(packet->GetSize()); + packet->AddHeader(wsmpHeader); + + // the data of packet + int dataSize = packet->GetSize(); + uint8_t *data = new uint8_t[dataSize]; + packet->CopyData (data, dataSize); + + // see Annex G.2 "WSM Example" + uint8_t wsmp[] = {0x02, 0xC0, 0x03, 0x05, 0x0F, 0x01, + 0xAC, 0x10, 0x01, 0x0C, 0x04, 0x01, + 0x1E, 0x80, 0x00, 0x0D, 0x48, 0x65, + 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, + 0x72, 0x6C, 0x64, 0x21, 0x00}; + NS_TEST_EXPECT_MSG_EQ (dataSize, 29, ""); + for (int i = 0; i < 29; i++) + NS_TEST_EXPECT_MSG_EQ (data[i], wsmp[i], ""); +} + +class WsmpHeaderTestSuite : public TestSuite +{ +public: + WsmpHeaderTestSuite (); +}; + +WsmpHeaderTestSuite::WsmpHeaderTestSuite () + : TestSuite ("wsmp-header", UNIT) +{ + // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + AddTestCase (new WsmpHeaderTestCase, TestCase::QUICK); +} + +// Do not forget to allocate an instance of this TestSuite +static WsmpHeaderTestSuite wsmpHeaderTestSuite; + diff -r f6eaede3f93d src/wave/test/wsmp-socket-test-suite.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wave/test/wsmp-socket-test-suite.cc Fri Mar 04 23:43:06 2016 +0800 @@ -0,0 +1,203 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 Dalian University of Technology + * + * 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: Junling Bu + */ +#include "ns3/test.h" +#include "ns3/simulator.h" +#include "ns3/config.h" +#include "ns3/data-rate.h" +#include "ns3/vector.h" +#include "ns3/string.h" +#include "ns3/mobility-model.h" +#include "ns3/yans-wifi-helper.h" +#include "ns3/position-allocator.h" +#include "ns3/mobility-helper.h" +#include "ns3/mac48-address.h" +#include "ns3/wave-helper.h" +#include "ns3/wave-mac-helper.h" +#include "ns3/wsmp-socket.h" + +using namespace ns3; + +class WsmpSocketTestCase : public TestCase +{ +public: + WsmpSocketTestCase (void); + virtual ~WsmpSocketTestCase (void); + void CreateDevices (uint32_t num); + void ReceivePacket (Ptr socket); + void SendPacket (Ptr socket); +private: + virtual void DoRun (void); + void TestBroadcast (void); + void TestUnicastSucceed (void); + void TestUnicastFail (void); + + NodeContainer m_nodes; + + uint32_t m_send; + uint32_t m_recv; +}; + +WsmpSocketTestCase::WsmpSocketTestCase (void) + : TestCase ("WSMP Socket"), + m_send (0), + m_recv (0) +{ +} + +WsmpSocketTestCase::~WsmpSocketTestCase (void) +{ +} + +void +WsmpSocketTestCase::CreateDevices (uint32_t num) +{ + m_nodes = NodeContainer (); + m_nodes.Create (num); + + YansWifiChannelHelper waveChannel = YansWifiChannelHelper::Default (); + YansWavePhyHelper wavePhy = YansWavePhyHelper::Default (); + wavePhy.SetChannel (waveChannel.Create ()); + QosWaveMacHelper waveMac = QosWaveMacHelper::Default (); + WaveHelper waveHelper = WaveHelper::Default (); + NetDeviceContainer devices = waveHelper.Install (wavePhy, waveMac, m_nodes); + + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (5.0, 0.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (m_nodes); +} + +void +WsmpSocketTestCase::TestBroadcast (void) +{ + m_recv = 0; + m_send = 0; + CreateDevices (2); + + TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); + // Create a Socket on Node 0 for recv all WSMP packets + Ptr destination = WsmpSocket::CreateSocket (m_nodes.Get (0), tid); + destination->Bind (); + destination->SetRecvCallback (MakeCallback (&WsmpSocketTestCase::ReceivePacket, this)); + // Create a Socket on Node 1 for send + Psid psid = Psid(0x80, 0x01); + Ptr source = WsmpSocket::CreateSocket (m_nodes.Get (1), tid); + source->Connect (Mac48Address::GetBroadcast(), psid); + Simulator::Schedule(Seconds (1.0), &WsmpSocketTestCase::SendPacket, this, source); + Simulator::Stop (Seconds (5.0)); + Simulator::Run (); + Simulator::Destroy (); + + NS_TEST_EXPECT_MSG_EQ (m_send, m_recv, "send " << m_send << ", recv " << m_recv); +} + +void +WsmpSocketTestCase::TestUnicastSucceed (void) +{ + m_recv = 0; + m_send = 0; + CreateDevices (2); + + TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); + // Create a Socket on Node 0 for recv all WSMP packets + Ptr destination = WsmpSocket::CreateSocket (m_nodes.Get (0), tid); + Psid psid1 = Psid(0x80, 0x01); + destination->Bind (psid1); + destination->SetRecvCallback (MakeCallback (&WsmpSocketTestCase::ReceivePacket, this)); + // Create a Socket on Node 1 for send + Psid psid2 = Psid(0x80, 0x01); + Ptr source = WsmpSocket::CreateSocket (m_nodes.Get (1), tid); + source->Connect (Mac48Address::GetBroadcast(), psid2); + Simulator::Schedule(Seconds (1.0), &WsmpSocketTestCase::SendPacket, this, source); + Simulator::Stop (Seconds (5.0)); + Simulator::Run (); + Simulator::Destroy (); + + NS_TEST_EXPECT_MSG_EQ (m_send, m_recv, "send " << m_send << ", recv " << m_recv); +} + +void +WsmpSocketTestCase::TestUnicastFail (void) +{ + m_recv = 0; + m_send = 0; + CreateDevices (2); + + TypeId tid = TypeId::LookupByName ("ns3::WsmpSocketFactory"); + // Create a Socket on Node 0 for recv all WSMP packets + Ptr destination = WsmpSocket::CreateSocket (m_nodes.Get (0), tid); + Psid psid1 = Psid(0x80, 0x01); + destination->Bind (psid1); + destination->SetRecvCallback (MakeCallback (&WsmpSocketTestCase::ReceivePacket, this)); + // Create a Socket on Node 1 for send + Psid psid2 = Psid(0x80, 0x02); + Ptr source = WsmpSocket::CreateSocket (m_nodes.Get (1), tid); + source->Connect (Mac48Address::GetBroadcast(), psid2); + Simulator::Schedule(Seconds (1.0), &WsmpSocketTestCase::SendPacket, this, source); + Simulator::Stop (Seconds (5.0)); + Simulator::Run (); + Simulator::Destroy (); + + NS_TEST_EXPECT_MSG_NE (m_send, m_recv, "send " << m_send << ", recv " << m_recv); +} + +void +WsmpSocketTestCase::ReceivePacket (Ptr socket) +{ + while (socket->Recv ()) + { + m_recv++; + } +} + +void +WsmpSocketTestCase::SendPacket (Ptr socket) +{ + socket->Send (Create (100)); + m_send++; +} + +void +WsmpSocketTestCase::DoRun () +{ + TestBroadcast(); + TestUnicastSucceed(); + TestUnicastFail(); +} + +class WsmpSocketTestSuite : public TestSuite +{ +public: + WsmpSocketTestSuite (); +}; + +WsmpSocketTestSuite::WsmpSocketTestSuite () + : TestSuite ("wsmp-socket", UNIT) +{ + // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER + AddTestCase (new WsmpSocketTestCase, TestCase::QUICK); +} + +// Do not forget to allocate an instance of this TestSuite +static WsmpSocketTestSuite wsmpHeaderTestSuite; + diff -r f6eaede3f93d src/wave/wscript --- a/src/wave/wscript Tue Mar 01 20:49:37 2016 +0100 +++ b/src/wave/wscript Fri Mar 04 23:43:06 2016 +0800 @@ -20,6 +20,12 @@ 'model/bsm-application.cc', 'model/higher-tx-tag.cc', 'model/wave-net-device.cc', + 'model/wsmp-header.cc', + 'model/wsmp-socket.cc', + 'model/wsmp-socket-factory.cc', + 'model/wsmp-socket-factory-impl.cc', + 'model/wsmp-socket-impl.cc', + 'model/wsmp-protocol.cc', 'helper/wave-bsm-stats.cc', 'helper/wave-mac-helper.cc', 'helper/wave-helper.cc', @@ -31,6 +37,8 @@ module_test.source = [ 'test/mac-extension-test-suite.cc', 'test/ocb-test-suite.cc', + 'test/wsmp-header-test-suite.cc', + 'test/wsmp-socket-test-suite.cc', ] headers = bld(features='ns3header') @@ -47,6 +55,12 @@ 'model/higher-tx-tag.h', 'model/wave-net-device.h', 'model/bsm-application.h', + 'model/wsmp-header.h', + 'model/wsmp-socket.h', + 'model/wsmp-socket-factory.h', + 'model/wsmp-socket-factory-impl.h', + 'model/wsmp-socket-impl.h', + 'model/wsmp-protocol.h', 'helper/wave-bsm-stats.h', 'helper/wave-mac-helper.h', 'helper/wave-helper.h',