src/devices/point-to-point/point-to-point-net-device.cc
author vincent@clarinet.u-strasbg.fr
Fri Nov 07 11:36:15 2008 -0800 (2008-11-07)
changeset 3852 9cf7ad0cac85
parent 3841 1e7abf5fca79
child 3936 e525995ce5dc
permissions -rw-r--r--
Initial IPv6 capability
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2007, 2008 University of Washington
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  */
    18 
    19 #include "ns3/log.h"
    20 #include "ns3/queue.h"
    21 #include "ns3/simulator.h"
    22 #include "ns3/mac48-address.h"
    23 #include "ns3/llc-snap-header.h"
    24 #include "ns3/error-model.h"
    25 #include "ns3/trace-source-accessor.h"
    26 #include "ns3/uinteger.h"
    27 #include "ns3/pointer.h"
    28 #include "point-to-point-net-device.h"
    29 #include "point-to-point-channel.h"
    30 #include "ppp-header.h"
    31 
    32 NS_LOG_COMPONENT_DEFINE ("PointToPointNetDevice");
    33 
    34 namespace ns3 {
    35 
    36 NS_OBJECT_ENSURE_REGISTERED (PointToPointNetDevice);
    37 
    38 TypeId 
    39 PointToPointNetDevice::GetTypeId (void)
    40 {
    41   static TypeId tid = TypeId ("ns3::PointToPointNetDevice")
    42     .SetParent<NetDevice> ()
    43     .AddConstructor<PointToPointNetDevice> ()
    44     .AddAttribute ("Address", 
    45                    "The MAC address of this device.",
    46                    Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
    47                    MakeMac48AddressAccessor (&PointToPointNetDevice::m_address),
    48                    MakeMac48AddressChecker ())
    49     .AddAttribute ("FrameSize", 
    50                    "The maximum size of a packet sent over this device.",
    51                    UintegerValue (DEFAULT_FRAME_SIZE),
    52                    MakeUintegerAccessor (&PointToPointNetDevice::SetFrameSize,
    53                                          &PointToPointNetDevice::GetFrameSize),
    54                    MakeUintegerChecker<uint16_t> ())
    55     .AddAttribute ("DataRate", 
    56                    "The default data rate for point to point links",
    57                    DataRateValue (DataRate ("32768b/s")),
    58                    MakeDataRateAccessor (&PointToPointNetDevice::m_bps),
    59                    MakeDataRateChecker ())
    60     .AddAttribute ("ReceiveErrorModel", 
    61                    "The receiver error model used to simulate packet loss",
    62                    PointerValue (),
    63                    MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
    64                    MakePointerChecker<ErrorModel> ())
    65     .AddAttribute ("TxQueue",
    66                    "A queue to use as the transmit queue in the device.",
    67                    PointerValue (),
    68                    MakePointerAccessor (&PointToPointNetDevice::m_queue),
    69                    MakePointerChecker<Queue> ())
    70     .AddAttribute ("InterframeGap", 
    71                    "The time to wait between packet (frame) transmissions",
    72                    TimeValue (Seconds (0.0)),
    73                    MakeTimeAccessor (&PointToPointNetDevice::m_tInterframeGap),
    74                    MakeTimeChecker ())
    75     .AddTraceSource ("Rx", 
    76                      "Trace source to fire on reception of a MAC packet.",
    77                      MakeTraceSourceAccessor (&PointToPointNetDevice::m_rxTrace))
    78     .AddTraceSource ("Drop",
    79                      "Trace source to fire on when a MAC packet is dropped.",
    80 
    81                      MakeTraceSourceAccessor (&PointToPointNetDevice::m_dropTrace))
    82 
    83     ;
    84   return tid;
    85 }
    86 
    87 
    88 PointToPointNetDevice::PointToPointNetDevice () 
    89 : 
    90   m_txMachineState (READY),
    91   m_channel (0), 
    92   m_name (""),
    93   m_linkUp (false)
    94 {
    95   NS_LOG_FUNCTION (this);
    96 
    97   //
    98   // A quick sanity check to ensure consistent constants.
    99   //
   100   PppHeader ppp;
   101   NS_ASSERT_MSG (PPP_OVERHEAD == ppp.GetSerializedSize (), 
   102                  "PointToPointNetDevice::PointToPointNetDevice(): PPP_OVERHEAD inconsistent");
   103 
   104   m_frameSize = DEFAULT_FRAME_SIZE;
   105   m_mtu = MtuFromFrameSize (m_frameSize);
   106 }
   107 
   108 PointToPointNetDevice::~PointToPointNetDevice ()
   109 {
   110 }
   111 
   112   void 
   113 PointToPointNetDevice::AddHeader(Ptr<Packet> p, uint16_t protocolNumber)
   114 {
   115   NS_LOG_FUNCTION_NOARGS ();
   116   NS_ASSERT_MSG (protocolNumber == 0x800,
   117     "PointToPointNetDevice::AddHeader(): protocolNumber must be 0x800");
   118   PppHeader ppp;
   119   p->AddHeader (ppp);
   120 }
   121 
   122   bool 
   123 PointToPointNetDevice::ProcessHeader(Ptr<Packet> p, uint16_t& param)
   124 {
   125   NS_LOG_FUNCTION_NOARGS ();
   126   PppHeader ppp;
   127   p->RemoveHeader (ppp);
   128   param = 0x800;
   129   return true;
   130 }
   131 
   132   void 
   133 PointToPointNetDevice::DoDispose()
   134 {
   135   NS_LOG_FUNCTION_NOARGS ();
   136   m_node = 0;
   137   m_channel = 0;
   138   m_receiveErrorModel = 0;
   139   NetDevice::DoDispose ();
   140 }
   141 
   142   void 
   143 PointToPointNetDevice::SetDataRate(DataRate bps)
   144 {
   145   NS_LOG_FUNCTION_NOARGS ();
   146   m_bps = bps;
   147 }
   148 
   149   void 
   150 PointToPointNetDevice::SetInterframeGap(Time t)
   151 {
   152   NS_LOG_FUNCTION_NOARGS ();
   153   m_tInterframeGap = t;
   154 }
   155 
   156   bool
   157 PointToPointNetDevice::TransmitStart (Ptr<Packet> p)
   158 {
   159   NS_LOG_FUNCTION (this << p);
   160   NS_LOG_LOGIC ("UID is " << p->GetUid () << ")");
   161 //
   162 // This function is called to start the process of transmitting a packet.
   163 // We need to tell the channel that we've started wiggling the wire and
   164 // schedule an event that will be executed when the transmission is complete.
   165 //
   166   NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
   167   m_txMachineState = BUSY;
   168   Time txTime = Seconds (m_bps.CalculateTxTime(p->GetSize()));
   169   Time txCompleteTime = txTime + m_tInterframeGap;
   170 
   171   NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << 
   172     txCompleteTime.GetSeconds () << "sec");
   173 
   174   Simulator::Schedule (txCompleteTime, 
   175     &PointToPointNetDevice::TransmitComplete, this);
   176 
   177   return m_channel->TransmitStart(p, this, txTime); 
   178 }
   179 
   180   void 
   181 PointToPointNetDevice::TransmitComplete (void)
   182 {
   183   NS_LOG_FUNCTION_NOARGS ();
   184 //
   185 // This function is called to when we're all done transmitting a packet.
   186 // We try and pull another packet off of the transmit queue.  If the queue
   187 // is empty, we are done, otherwise we need to start transmitting the
   188 // next packet.
   189 //
   190   NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
   191   m_txMachineState = READY;
   192   Ptr<Packet> p = m_queue->Dequeue ();
   193   if (p == 0)
   194     {
   195 //
   196 // No packet was on the queue, so we just exit.
   197 //
   198       return;
   199     }
   200 //
   201 // Got another packet off of the queue, so start the transmit process agin.
   202 //
   203   TransmitStart(p);
   204 }
   205 
   206   bool 
   207 PointToPointNetDevice::Attach (Ptr<PointToPointChannel> ch)
   208 {
   209   NS_LOG_FUNCTION (this << &ch);
   210 
   211   m_channel = ch;
   212 
   213   m_channel->Attach(this);
   214 
   215 //
   216 // This device is up whenever it is attached to a channel.  A better plan
   217 // would be to have the link come up when both devices are attached, but this
   218 // is not done for now.
   219 //
   220   NotifyLinkUp ();
   221   return true;
   222 }
   223 
   224   void
   225 PointToPointNetDevice::SetQueue (Ptr<Queue> q)
   226 {
   227   NS_LOG_FUNCTION (this << q);
   228   m_queue = q;
   229 }
   230 
   231   void
   232 PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
   233 {
   234   NS_LOG_FUNCTION (this << em);
   235   m_receiveErrorModel = em;
   236 }
   237 
   238  void
   239 PointToPointNetDevice::Receive (Ptr<Packet> packet)
   240 {
   241   NS_LOG_FUNCTION (this << packet);
   242   uint16_t protocol = 0;
   243 
   244   if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) ) 
   245     {
   246 // 
   247 // If we have an error model and it indicates that it is time to lose a
   248 // corrupted packet, don't forward this packet up, let it go.
   249 //
   250       m_dropTrace (packet);
   251     }
   252   else 
   253     {
   254 // 
   255 // Hit the receive trace hook, strip off the point-to-point protocol header
   256 // and forward this packet up the protocol stack.
   257 //
   258       m_rxTrace (packet);
   259       ProcessHeader(packet, protocol);
   260       m_rxCallback (this, packet, protocol, GetRemote ());
   261       if (!m_promiscCallback.IsNull ())
   262         {
   263           m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
   264         }
   265     }
   266 }
   267 
   268   Ptr<Queue> 
   269 PointToPointNetDevice::GetQueue(void) const 
   270 { 
   271   NS_LOG_FUNCTION_NOARGS ();
   272   return m_queue;
   273 }
   274 
   275   void
   276 PointToPointNetDevice::NotifyLinkUp (void)
   277 {
   278   m_linkUp = true;
   279   if (!m_linkChangeCallback.IsNull ())
   280     {
   281       m_linkChangeCallback ();
   282     }
   283 }
   284 
   285   void 
   286 PointToPointNetDevice::SetName(const std::string name)
   287 {
   288   m_name = name;
   289 }
   290 
   291   std::string 
   292 PointToPointNetDevice::GetName(void) const
   293 {
   294   return m_name;
   295 }
   296 
   297   void 
   298 PointToPointNetDevice::SetIfIndex(const uint32_t index)
   299 {
   300   m_ifIndex = index;
   301 }
   302 
   303   uint32_t 
   304 PointToPointNetDevice::GetIfIndex(void) const
   305 {
   306   return m_ifIndex;
   307 }
   308 
   309   Ptr<Channel> 
   310 PointToPointNetDevice::GetChannel (void) const
   311 {
   312   return m_channel;
   313 }
   314 
   315 //
   316 // This is a point-to-point device, so we really don't need any kind of address
   317 // information.  However, the base class NetDevice wants us to define the
   318 // methods to get and set the address.  Rather than be rude and assert, we let
   319 // clients get and set the address, but simply ignore them.
   320   void 
   321 PointToPointNetDevice::SetAddress (Mac48Address addr)
   322 {
   323   m_address = addr;
   324 }
   325 
   326   Address 
   327 PointToPointNetDevice::GetAddress (void) const
   328 {
   329   return m_address;
   330 }
   331 
   332   bool 
   333 PointToPointNetDevice::IsLinkUp (void) const
   334 {
   335   return m_linkUp;
   336 }
   337 
   338   void 
   339 PointToPointNetDevice::SetLinkChangeCallback (Callback<void> callback)
   340 {
   341   m_linkChangeCallback = callback;
   342 }
   343 
   344 //
   345 // This is a point-to-point device, so every transmission is a broadcast to
   346 // all of the devices on the network.
   347 //
   348   bool 
   349 PointToPointNetDevice::IsBroadcast (void) const
   350 {
   351   return true;
   352 }
   353 
   354 //
   355 // We don't really need any addressing information since this is a 
   356 // point-to-point device.  The base class NetDevice wants us to return a
   357 // broadcast address, so we make up something reasonable.
   358 //
   359   Address
   360 PointToPointNetDevice::GetBroadcast (void) const
   361 {
   362   return Mac48Address ("ff:ff:ff:ff:ff:ff");
   363 }
   364 
   365 //
   366 // We don't deal with multicast here.  It doesn't make sense to include some
   367 // of the one destinations on the network but exclude some of the others.
   368 //
   369   bool 
   370 PointToPointNetDevice::IsMulticast (void) const
   371 {
   372   return false;
   373 }
   374 
   375   Address 
   376 PointToPointNetDevice::GetMulticast (Ipv4Address multicastGroup) const
   377 {
   378   return Mac48Address ("01:00:5e:00:00:00");
   379 }
   380 
   381 Address
   382 PointToPointNetDevice::GetMulticast (Ipv6Address addr) const
   383 {
   384   NS_LOG_FUNCTION(this << addr);
   385   return Mac48Address ("33:33:00:00:00:00");
   386 }
   387 
   388   bool 
   389 PointToPointNetDevice::IsPointToPoint (void) const
   390 {
   391   return true;
   392 }
   393 
   394   bool 
   395 PointToPointNetDevice::Send(
   396   Ptr<Packet> packet, 
   397   const Address &dest, 
   398   uint16_t protocolNumber)
   399 {
   400   NS_LOG_FUNCTION_NOARGS ();
   401   NS_LOG_LOGIC ("p=" << packet << ", dest=" << &dest);
   402   NS_LOG_LOGIC ("UID is " << packet->GetUid ());
   403 
   404 //
   405 // If IsLinkUp() is false it means there is no channel to send any packet 
   406 // over so we just return an error.
   407 //
   408   if (IsLinkUp () == false)
   409     {
   410       return false;
   411     }
   412 
   413 //
   414 // Stick a point to point protocol header on the packet in preparation for
   415 // shoving it out the door.
   416 //
   417   AddHeader(packet, protocolNumber);
   418 
   419 //
   420 // If there's a transmission in progress, we enque the packet for later
   421 // transmission; otherwise we send it now.
   422 //
   423   if (m_txMachineState == READY) 
   424     {
   425 // 
   426 // Even if the transmitter is immediately available, we still enqueue and 
   427 // dequeue the packet to hit the tracing hooks.
   428 //
   429       m_queue->Enqueue (packet);
   430       packet = m_queue->Dequeue ();
   431       return TransmitStart (packet);
   432     }
   433   else
   434     {
   435       return m_queue->Enqueue(packet);
   436     }
   437 }
   438 
   439 bool
   440 PointToPointNetDevice::SendFrom (Ptr<Packet> packet, 
   441                                  const Address &source, 
   442                                  const Address &dest, 
   443                                  uint16_t protocolNumber)
   444 {
   445   return false;
   446 }
   447 
   448   Ptr<Node> 
   449 PointToPointNetDevice::GetNode (void) const
   450 {
   451   return m_node;
   452 }
   453 
   454   void 
   455 PointToPointNetDevice::SetNode (Ptr<Node> node)
   456 {
   457   m_node = node;
   458 }
   459 
   460   bool 
   461 PointToPointNetDevice::NeedsArp (void) const
   462 {
   463   return false;
   464 }
   465 
   466   void 
   467 PointToPointNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
   468 {
   469   m_rxCallback = cb;
   470 }
   471 
   472 void
   473 PointToPointNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
   474 {
   475   NS_FATAL_ERROR ("not implemented");
   476   m_promiscCallback = cb;
   477 }
   478 
   479   bool
   480 PointToPointNetDevice::SupportsSendFrom (void) const
   481 {
   482   return false;
   483 }
   484 
   485 Address 
   486 PointToPointNetDevice::GetRemote (void) const
   487 {
   488   NS_ASSERT (m_channel->GetNDevices () == 2);
   489   for (uint32_t i = 0; i < m_channel->GetNDevices (); ++i)
   490     {
   491       Ptr<NetDevice> tmp = m_channel->GetDevice (i);
   492       if (tmp != this)
   493         {
   494           return tmp->GetAddress ();
   495         }
   496     }
   497   NS_ASSERT (false);
   498   // quiet compiler.
   499   return Address ();
   500 }
   501 
   502   uint32_t
   503 PointToPointNetDevice::MtuFromFrameSize (uint32_t frameSize)
   504 {
   505   NS_LOG_FUNCTION (frameSize);
   506   NS_ASSERT_MSG (frameSize <= std::numeric_limits<uint16_t>::max (), 
   507                  "PointToPointNetDevice::MtuFromFrameSize(): Frame size should be derived from 16-bit quantity: " << 
   508                  frameSize);
   509   PppHeader ppp;
   510   NS_ASSERT_MSG ((uint32_t)frameSize >= ppp.GetSerializedSize (), 
   511                  "PointToPointNetDevice::MtuFromFrameSize(): Given frame size too small to support PPP");
   512   return frameSize - ppp.GetSerializedSize ();
   513 }
   514   
   515   uint32_t
   516 PointToPointNetDevice::FrameSizeFromMtu (uint32_t mtu)
   517 {
   518   NS_LOG_FUNCTION (mtu);
   519 
   520   PppHeader ppp;
   521   return mtu + ppp.GetSerializedSize ();
   522 }
   523 
   524   void 
   525 PointToPointNetDevice::SetFrameSize (uint16_t frameSize)
   526 {
   527   NS_LOG_FUNCTION (frameSize);
   528 
   529   m_frameSize = frameSize;
   530   m_mtu = MtuFromFrameSize (frameSize);
   531 
   532   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   533   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   534 }
   535 
   536   uint16_t
   537 PointToPointNetDevice::GetFrameSize (void) const
   538 {
   539   return m_frameSize;
   540 }
   541 
   542   bool
   543 PointToPointNetDevice::SetMtu (uint16_t mtu)
   544 {
   545   NS_LOG_FUNCTION (mtu);
   546 
   547   uint32_t newFrameSize = FrameSizeFromMtu (mtu);
   548 
   549   if (newFrameSize > std::numeric_limits<uint16_t>::max ())
   550     {
   551       NS_LOG_WARN ("PointToPointNetDevice::SetMtu(): Frame size overflow, MTU not set.");
   552       return false;
   553     }
   554 
   555   m_frameSize = newFrameSize;
   556   m_mtu = mtu;
   557 
   558   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   559   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   560 
   561   return true;
   562 }
   563 
   564   uint16_t
   565 PointToPointNetDevice::GetMtu (void) const
   566 {
   567   NS_LOG_FUNCTION_NOARGS ();
   568   return m_mtu;
   569 }
   570 
   571 
   572 } // namespace ns3