src/devices/csma/csma-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 3861 dacfd1f07538
permissions -rw-r--r--
Initial IPv6 capability
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2007 Emmanuelle Laprise
     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  * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
    19  */
    20 
    21 #include "ns3/log.h"
    22 #include "ns3/queue.h"
    23 #include "ns3/simulator.h"
    24 #include "ns3/ethernet-header.h"
    25 #include "ns3/ethernet-trailer.h"
    26 #include "ns3/llc-snap-header.h"
    27 #include "ns3/error-model.h"
    28 #include "ns3/enum.h"
    29 #include "ns3/boolean.h"
    30 #include "ns3/uinteger.h"
    31 #include "ns3/pointer.h"
    32 #include "ns3/trace-source-accessor.h"
    33 #include "csma-net-device.h"
    34 #include "csma-channel.h"
    35 
    36 NS_LOG_COMPONENT_DEFINE ("CsmaNetDevice");
    37 
    38 namespace ns3 {
    39 
    40 NS_OBJECT_ENSURE_REGISTERED (CsmaNetDevice);
    41 
    42   TypeId 
    43 CsmaNetDevice::GetTypeId (void)
    44 {
    45   static TypeId tid = TypeId ("ns3::CsmaNetDevice")
    46     .SetParent<NetDevice> ()
    47     .AddConstructor<CsmaNetDevice> ()
    48     .AddAttribute ("Address", 
    49                    "The MAC address of this device.",
    50                    Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
    51                    MakeMac48AddressAccessor (&CsmaNetDevice::m_address),
    52                    MakeMac48AddressChecker ())
    53     .AddAttribute ("FrameSize", 
    54                    "The maximum size of a packet sent over this device.",
    55                    UintegerValue (DEFAULT_FRAME_SIZE),
    56                    MakeUintegerAccessor (&CsmaNetDevice::SetFrameSize,
    57                                          &CsmaNetDevice::GetFrameSize),
    58                    MakeUintegerChecker<uint16_t> ())
    59     .AddAttribute ("EncapsulationMode", 
    60                    "The link-layer encapsulation type to use.",
    61                    EnumValue (DIX),
    62                    MakeEnumAccessor (&CsmaNetDevice::SetEncapsulationMode),
    63                    MakeEnumChecker (DIX, "Dix",
    64                                     LLC, "Llc"))
    65     .AddAttribute ("SendEnable", 
    66                    "Enable or disable the transmitter section of the device.",
    67                    BooleanValue (true),
    68                    MakeBooleanAccessor (&CsmaNetDevice::m_sendEnable),
    69                    MakeBooleanChecker ())
    70     .AddAttribute ("ReceiveEnable",
    71                    "Enable or disable the receiver section of the device.",
    72                    BooleanValue (true),
    73                    MakeBooleanAccessor (&CsmaNetDevice::m_receiveEnable),
    74                    MakeBooleanChecker ())
    75     .AddAttribute ("RxErrorModel", 
    76                    "The receiver error model used to simulate packet loss",
    77                    PointerValue (),
    78                    MakePointerAccessor (&CsmaNetDevice::m_receiveErrorModel),
    79                    MakePointerChecker<ErrorModel> ())
    80     .AddAttribute ("TxQueue", 
    81                    "A queue to use as the transmit queue in the device.",
    82                    PointerValue (),
    83                    MakePointerAccessor (&CsmaNetDevice::m_queue),
    84                    MakePointerChecker<Queue> ())
    85     .AddTraceSource ("Rx", 
    86                      "The trace source to fire on reception of a MAC packet.",
    87                      MakeTraceSourceAccessor (&CsmaNetDevice::m_rxTrace))
    88     .AddTraceSource ("Drop", 
    89                      "Trace source to fire on when a MAC packet is dropped.",
    90                      MakeTraceSourceAccessor (&CsmaNetDevice::m_dropTrace))
    91     ;
    92   return tid;
    93 }
    94 
    95 CsmaNetDevice::CsmaNetDevice ()
    96   : m_name (""),
    97     m_linkUp (false)
    98 {
    99   NS_LOG_FUNCTION (this);
   100   m_txMachineState = READY;
   101   m_tInterframeGap = Seconds (0);
   102   m_channel = 0; 
   103 
   104   // 
   105   // We would like to let the attribute system take care of initializing the packet encapsulation stuff, but we also don't want to
   106   // get caught up in initialization order changes.  So we'll get the three problem variables into a consistent state here before the
   107   // attribute calls, and then depend on the semantics of the setters to preserve a consistent state.  This really doesn't have to be
   108   // the same set of values as the initial values set by the attributes, but it does have to be a consistent set.  That is, you can
   109   // just change the ddfault encapsulation mode above without having to change it here.  We keep it the same for GP.
   110   //
   111   m_encapMode = DIX;
   112   m_frameSize = DEFAULT_FRAME_SIZE;
   113   m_mtu = MtuFromFrameSize (m_frameSize);
   114 }
   115 
   116 CsmaNetDevice::~CsmaNetDevice()
   117 {
   118   NS_LOG_FUNCTION_NOARGS ();
   119   m_queue = 0;
   120 }
   121 
   122   void 
   123 CsmaNetDevice::DoDispose ()
   124 {
   125   NS_LOG_FUNCTION_NOARGS ();
   126   m_channel = 0;
   127   m_node = 0;
   128   NetDevice::DoDispose ();
   129 }
   130 
   131   uint32_t
   132 CsmaNetDevice::MtuFromFrameSize (uint32_t frameSize)
   133 {
   134   NS_LOG_FUNCTION (frameSize);
   135 
   136   NS_ASSERT_MSG (frameSize <= std::numeric_limits<uint16_t>::max (), 
   137                  "CsmaNetDevice::MtuFromFrameSize(): Frame size should be derived from 16-bit quantity: " << frameSize);
   138 
   139   uint32_t newSize;
   140 
   141   switch (m_encapMode) 
   142     {
   143     case DIX:
   144       newSize = frameSize - ETHERNET_OVERHEAD;
   145       break;
   146     case LLC: 
   147       {
   148         LlcSnapHeader llc;
   149 
   150         NS_ASSERT_MSG ((uint32_t)(frameSize - ETHERNET_OVERHEAD) >= llc.GetSerializedSize (), 
   151                        "CsmaNetDevice::MtuFromFrameSize(): Given frame size too small to support LLC mode");
   152         newSize = frameSize - ETHERNET_OVERHEAD - llc.GetSerializedSize ();
   153       }
   154       break;
   155     case ILLEGAL:
   156     default:
   157       NS_FATAL_ERROR ("CsmaNetDevice::MtuFromFrameSize(): Unknown packet encapsulation mode");
   158       return 0;
   159     }
   160 
   161   return newSize;
   162 }
   163   
   164   uint32_t
   165 CsmaNetDevice::FrameSizeFromMtu (uint32_t mtu)
   166 {
   167   NS_LOG_FUNCTION (mtu);
   168 
   169   uint32_t newSize;
   170 
   171   switch (m_encapMode) 
   172     {
   173     case DIX:
   174       newSize = mtu + ETHERNET_OVERHEAD;
   175       break;
   176     case LLC: 
   177       {
   178         LlcSnapHeader llc;
   179         newSize = mtu + ETHERNET_OVERHEAD + llc.GetSerializedSize ();
   180       }
   181       break;
   182     case ILLEGAL:
   183     default:
   184       NS_FATAL_ERROR ("CsmaNetDevice::FrameSizeFromMtu(): Unknown packet encapsulation mode");
   185       return 0;
   186     }
   187 
   188   return newSize;
   189 }
   190 
   191   void 
   192 CsmaNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
   193 {
   194   NS_LOG_FUNCTION (mode);
   195 
   196   m_encapMode = mode;
   197   m_mtu = MtuFromFrameSize (m_frameSize);
   198 
   199   NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
   200   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   201   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   202 }
   203 
   204   CsmaNetDevice::EncapsulationMode
   205 CsmaNetDevice::GetEncapsulationMode (void)
   206 {
   207   NS_LOG_FUNCTION_NOARGS ();
   208   return m_encapMode;
   209 }
   210   
   211   bool
   212 CsmaNetDevice::SetMtu (uint16_t mtu)
   213 {
   214   NS_LOG_FUNCTION (mtu);
   215 
   216   uint32_t newFrameSize = FrameSizeFromMtu (mtu);
   217 
   218   if (newFrameSize > std::numeric_limits<uint16_t>::max ())
   219     {
   220       NS_LOG_WARN ("CsmaNetDevice::SetMtu(): Frame size overflow, MTU not set.");
   221       return false;
   222     }
   223 
   224   m_frameSize = newFrameSize;
   225   m_mtu = mtu;
   226 
   227   NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
   228   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   229   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   230 
   231   return true;
   232 }
   233 
   234   uint16_t
   235 CsmaNetDevice::GetMtu (void) const
   236 {
   237   NS_LOG_FUNCTION_NOARGS ();
   238   return m_mtu;
   239 }
   240 
   241   void 
   242 CsmaNetDevice::SetFrameSize (uint16_t frameSize)
   243 {
   244   NS_LOG_FUNCTION (frameSize);
   245 
   246   m_frameSize = frameSize;
   247   m_mtu = MtuFromFrameSize (frameSize);
   248 
   249   NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
   250   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   251   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   252 }
   253 
   254   uint16_t
   255 CsmaNetDevice::GetFrameSize (void) const
   256 {
   257   return m_frameSize;
   258 }
   259 
   260   void 
   261 CsmaNetDevice::SetAddress (Mac48Address self)
   262 {
   263   NS_LOG_FUNCTION (self);
   264   m_address = self;
   265 }
   266 
   267   void
   268 CsmaNetDevice::SetSendEnable (bool sendEnable)
   269 {
   270   NS_LOG_FUNCTION (sendEnable);
   271   m_sendEnable = sendEnable;
   272 }
   273 
   274   void
   275 CsmaNetDevice::SetReceiveEnable (bool receiveEnable)
   276 {
   277   NS_LOG_FUNCTION (receiveEnable);
   278   m_receiveEnable = receiveEnable;
   279 }
   280 
   281   bool
   282 CsmaNetDevice::IsSendEnabled (void)
   283 {
   284   NS_LOG_FUNCTION_NOARGS ();
   285   return m_sendEnable;
   286 }
   287 
   288   bool
   289 CsmaNetDevice::IsReceiveEnabled (void)
   290 {
   291   NS_LOG_FUNCTION_NOARGS ();
   292   return m_receiveEnable;
   293 }
   294 
   295   void 
   296 CsmaNetDevice::SetInterframeGap (Time t)
   297 {
   298   NS_LOG_FUNCTION (t);
   299   m_tInterframeGap = t;
   300 }
   301 
   302   void 
   303 CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries)
   304 {
   305   NS_LOG_FUNCTION (slotTime << minSlots << maxSlots << ceiling << maxRetries);
   306   m_backoff.m_slotTime = slotTime;
   307   m_backoff.m_minSlots = minSlots;
   308   m_backoff.m_maxSlots = maxSlots;
   309   m_backoff.m_ceiling = ceiling;
   310   m_backoff.m_maxRetries = maxRetries;
   311 }
   312 
   313   void 
   314 CsmaNetDevice::AddHeader (Ptr<Packet> p,   Mac48Address source,  Mac48Address dest,  uint16_t protocolNumber)
   315 {
   316   NS_LOG_FUNCTION (p << source << dest << protocolNumber);
   317 
   318   EthernetHeader header (false);
   319   header.SetSource (source);
   320   header.SetDestination (dest);
   321 
   322   EthernetTrailer trailer;
   323 
   324   NS_LOG_LOGIC ("p->GetSize () = " << p->GetSize ());
   325   NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
   326   NS_LOG_LOGIC ("m_mtu = " << m_mtu);
   327   NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
   328 
   329   uint16_t lengthType = 0;
   330   switch (m_encapMode) 
   331     {
   332     case DIX:
   333       NS_LOG_LOGIC ("Encapsulating packet as DIX (type interpretation)");
   334       //
   335       // This corresponds to the type interpretation of the lengthType field as in the old Ethernet Blue Book.
   336       //
   337       lengthType = protocolNumber;
   338       break;
   339     case LLC: 
   340       {
   341         NS_LOG_LOGIC ("Encapsulating packet as LLC (length interpretation)");
   342 
   343         LlcSnapHeader llc;
   344         llc.SetType (protocolNumber);
   345         p->AddHeader (llc);
   346         //
   347         // This corresponds to the length interpretation of the lengthType field,
   348         // but with an LLC/SNAP header added to the payload as in IEEE 802.2
   349         //      
   350         lengthType = p->GetSize ();
   351         NS_ASSERT_MSG (lengthType <= m_frameSize - 18,
   352           "CsmaNetDevice::AddHeader(): 802.3 Length/Type field with LLC/SNAP: "
   353           "length interpretation must not exceed device frame size minus overhead");
   354       }
   355       break;
   356     case ILLEGAL:
   357     default:
   358       NS_FATAL_ERROR ("CsmaNetDevice::AddHeader(): Unknown packet encapsulation mode");
   359       break;
   360     }
   361 
   362   NS_LOG_LOGIC ("header.SetLengthType (" << lengthType << ")");
   363   header.SetLengthType (lengthType);
   364   p->AddHeader (header);
   365 
   366   trailer.CalcFcs (p);
   367   p->AddTrailer (trailer);
   368 }
   369 
   370   bool 
   371 CsmaNetDevice::ProcessHeader (Ptr<Packet> p, uint16_t & param)
   372 {
   373   NS_LOG_FUNCTION (p << param);
   374 
   375   EthernetTrailer trailer;
   376       
   377   p->RemoveTrailer (trailer);
   378   trailer.CheckFcs (p);
   379 
   380   EthernetHeader header (false);
   381   p->RemoveHeader (header);
   382 
   383   if ((header.GetDestination () != GetBroadcast ()) &&
   384       (header.GetDestination () != GetAddress ()))
   385     {
   386       return false;
   387     }
   388 
   389   switch (m_encapMode)
   390     {
   391     case DIX:
   392       param = header.GetLengthType ();
   393       break;
   394     case LLC: 
   395       {
   396         LlcSnapHeader llc;
   397         p->RemoveHeader (llc);
   398         param = llc.GetType ();
   399       } 
   400       break;
   401     case ILLEGAL:
   402     default:
   403       NS_FATAL_ERROR ("CsmaNetDevice::ProcessHeader(): Unknown packet encapsulation mode");
   404       break;
   405     }
   406   return true;
   407 }
   408 
   409   void
   410 CsmaNetDevice::TransmitStart ()
   411 {
   412   NS_LOG_FUNCTION_NOARGS ();
   413 
   414   NS_LOG_LOGIC ("m_currentPkt=" << m_currentPkt);
   415   NS_LOG_LOGIC ("UID is " << m_currentPkt->GetUid ());
   416   //
   417   // This function is called to start the process of transmitting a packet.
   418   // We need to tell the channel that we've started wiggling the wire and
   419   // schedule an event that will be executed when it's time to tell the 
   420   // channel that we're done wiggling the wire.
   421   //
   422   NS_ASSERT_MSG ((m_txMachineState == READY) || (m_txMachineState == BACKOFF), 
   423                  "Must be READY to transmit. Tx state is: " << m_txMachineState);
   424 
   425   //
   426   // Only transmit if send side of net device is enabled
   427   //
   428   if (IsSendEnabled () == false)
   429     {
   430       return;
   431     }
   432 
   433   if (m_channel->GetState () != IDLE)
   434     {
   435       //
   436       // The channel is busy -- backoff and rechedule TransmitStart ()
   437       //
   438       m_txMachineState = BACKOFF;
   439 
   440       if (m_backoff.MaxRetriesReached ())
   441         { 
   442           //
   443           // Too many retries, abort transmission of packet
   444           //
   445           TransmitAbort ();
   446         } 
   447       else 
   448         {
   449           m_backoff.IncrNumRetries ();
   450           Time backoffTime = m_backoff.GetBackoffTime ();
   451 
   452           NS_LOG_LOGIC ("Channel busy, backing off for " << backoffTime.GetSeconds () << " sec");
   453 
   454           Simulator::Schedule (backoffTime, &CsmaNetDevice::TransmitStart, this);
   455         }
   456     } 
   457   else 
   458     {
   459       //
   460       // The channel is free, transmit the packet
   461       //
   462       m_txMachineState = BUSY;
   463       Time tEvent = Seconds (m_bps.CalculateTxTime (m_currentPkt->GetSize ()));
   464       
   465       NS_LOG_LOGIC ("Schedule TransmitCompleteEvent in " << tEvent.GetSeconds () << "sec");
   466       
   467       Simulator::Schedule (tEvent, &CsmaNetDevice::TransmitCompleteEvent, this);
   468 
   469       if (m_channel->TransmitStart (m_currentPkt, m_deviceId) == false)
   470         {
   471           NS_LOG_WARN ("Channel transmit start did not work at " << tEvent.GetSeconds () << "sec");
   472           m_txMachineState = READY;
   473         } 
   474       else 
   475         {
   476           //
   477           // Transmission succeeded, reset the backoff time parameters.
   478           //
   479           m_backoff.ResetBackoffTime ();
   480         }
   481     }
   482 }
   483 
   484 
   485   void
   486 CsmaNetDevice::TransmitAbort (void)
   487 {
   488   NS_LOG_FUNCTION_NOARGS ();
   489 
   490   NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")");
   491 
   492   //
   493   // Since we were transmitting a packet, that packet had better be on the transmit queue.
   494   //
   495   m_currentPkt = m_queue->Dequeue ();
   496   NS_ASSERT_MSG (m_currentPkt != 0, "No Packet on queue during CsmaNetDevice::TransmitAbort()");
   497 
   498   //
   499   // The last one failed.  Let's try to transmit the next one (if there)
   500   //
   501   m_backoff.ResetBackoffTime ();
   502   m_txMachineState = READY;
   503   TransmitStart ();
   504 }
   505 
   506   void
   507 CsmaNetDevice::TransmitCompleteEvent (void)
   508 {
   509   NS_LOG_FUNCTION_NOARGS ();
   510 
   511   //
   512   // This function is called to finish the  process of transmitting a packet.
   513   // We need to tell the channel that we've stopped wiggling the wire and
   514   // schedule an event that will be executed when it's time to re-enable
   515   // the transmitter after the interframe gap.
   516   //
   517   NS_ASSERT_MSG (m_txMachineState == BUSY, "Must be BUSY if transmitting");
   518   NS_ASSERT (m_channel->GetState () == TRANSMITTING);
   519   m_txMachineState = GAP;
   520 
   521   NS_LOG_LOGIC ("Pkt UID is " << m_currentPkt->GetUid () << ")");
   522   m_channel->TransmitEnd (); 
   523 
   524   NS_LOG_LOGIC ("Schedule TransmitReadyEvent in " << m_tInterframeGap.GetSeconds () << "sec");
   525 
   526   Simulator::Schedule (m_tInterframeGap, &CsmaNetDevice::TransmitReadyEvent, this);
   527 }
   528 
   529   void
   530 CsmaNetDevice::TransmitReadyEvent (void)
   531 {
   532   NS_LOG_FUNCTION_NOARGS ();
   533 
   534   //
   535   // This function is called to enable the transmitter after the interframe
   536   // gap has passed.  If there are pending transmissions, we use this opportunity
   537   // to start the next transmit.
   538   //
   539   NS_ASSERT_MSG (m_txMachineState == GAP, "Must be in interframe gap");
   540   m_txMachineState = READY;
   541 
   542   //
   543   // Get the next packet from the queue for transmitting
   544   //
   545   if (m_queue->IsEmpty ())
   546     {
   547       return;
   548     }
   549   else
   550     {
   551       m_currentPkt = m_queue->Dequeue ();
   552       NS_ASSERT_MSG (m_currentPkt != 0, "CsmaNetDevice::TransmitReadyEvent(): IsEmpty false but no Packet on queue?");
   553       TransmitStart ();
   554     }
   555 }
   556 
   557   bool
   558 CsmaNetDevice::Attach (Ptr<CsmaChannel> ch)
   559 {
   560   NS_LOG_FUNCTION (this << &ch);
   561 
   562   m_channel = ch;
   563 
   564   m_deviceId = m_channel->Attach (this);
   565 
   566   //
   567   // The channel provides us with the transmitter data rate.
   568   //
   569   m_bps = m_channel->GetDataRate ();
   570 
   571   //
   572   // We use the Ethernet interframe gap of 96 bit times.
   573   //
   574   m_tInterframeGap = Seconds (m_bps.CalculateTxTime (96/8));
   575 
   576   //
   577   // This device is up whenever a channel is attached to it.
   578   //
   579   NotifyLinkUp ();
   580   return true;
   581 }
   582 
   583   void
   584 CsmaNetDevice::SetQueue (Ptr<Queue> q)
   585 {
   586   NS_LOG_FUNCTION (q);
   587   m_queue = q;
   588 }
   589 
   590   void
   591 CsmaNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
   592 {
   593   NS_LOG_FUNCTION (em);
   594   m_receiveErrorModel = em; 
   595 }
   596 
   597   void
   598 CsmaNetDevice::Receive (Ptr<Packet> packet, Ptr<CsmaNetDevice> senderDevice)
   599 {
   600   NS_LOG_FUNCTION (packet << senderDevice);
   601   NS_LOG_LOGIC ("UID is " << packet->GetUid ());
   602 
   603   /* IPv6 support*/
   604   uint8_t mac[6];
   605   Mac48Address multicast6AllNodes("33:33:00:00:00:01");
   606   Mac48Address multicast6AllRouters("33:33:00:00:00:02");
   607   Mac48Address multicast6AllHosts("33:33:00:00:00:03");
   608   Mac48Address multicast6Node; /* multicast address addressed to our MAC address */
   609 
   610   /* generate IPv6 multicast ethernet destination that nodes will accept */
   611   GetAddress().CopyTo(mac);
   612   mac[0]=0x33;
   613   mac[1]=0x33;
   614   /* mac[2]=0xff; */
   615   multicast6Node.CopyFrom(mac);
   616 
   617   //
   618   // We never forward up packets that we sent. Real devices don't do this since
   619   // their receivers are disabled during send, so we don't. Drop the packet
   620   // silently (no tracing) since it would really never get here in a real device.
   621   // 
   622   if (senderDevice == this)
   623     {
   624       return;
   625     }
   626 
   627   // 
   628   // Only receive if the send side of net device is enabled
   629   //
   630   if (IsReceiveEnabled () == false)
   631     {
   632       m_dropTrace (packet);
   633       return;
   634     }
   635 
   636   //
   637   // Trace sinks will expect complete packets, not packets without some of the
   638   // headers.
   639   //
   640   Ptr<Packet> originalPacket = packet->Copy ();
   641 
   642   EthernetTrailer trailer;
   643   packet->RemoveTrailer (trailer);
   644   trailer.CheckFcs (packet);
   645 
   646   EthernetHeader header (false);
   647   packet->RemoveHeader (header);
   648 
   649   NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
   650   NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
   651 
   652   if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
   653     {
   654       NS_LOG_LOGIC ("Dropping pkt due to error model ");
   655       m_dropTrace (packet);
   656     }
   657   else
   658     {
   659       //
   660       // variable <protocol> must be initialized to avoid a compiler warning in the RAW case that breaks the optimized build.
   661       //
   662       uint16_t protocol = 0;
   663 
   664       switch (m_encapMode)
   665         {
   666         case DIX:
   667           protocol = header.GetLengthType ();
   668           break;
   669         case LLC: 
   670           {
   671             LlcSnapHeader llc;
   672             packet->RemoveHeader (llc);
   673             protocol = llc.GetType ();
   674           } 
   675           break;
   676         case ILLEGAL:
   677         default:
   678           NS_FATAL_ERROR ("CsmaNetDevice::Receive(): Unknown packet encapsulation mode");
   679           break;
   680         }
   681 
   682       PacketType packetType;
   683       
   684       if (header.GetDestination ().IsBroadcast ())
   685         {
   686           packetType = PACKET_BROADCAST;
   687           m_rxTrace (originalPacket);
   688         }
   689       else if (header.GetDestination ().IsMulticast () ||
   690           header.GetDestination() == multicast6Node ||
   691           header.GetDestination() == multicast6AllNodes ||
   692           header.GetDestination() == multicast6AllRouters ||
   693           header.GetDestination() == multicast6AllHosts)
   694         {
   695           packetType = PACKET_MULTICAST;          
   696           m_rxTrace (originalPacket);
   697         }
   698       else if (header.GetDestination () == m_address)
   699         {
   700           packetType = PACKET_HOST;
   701           m_rxTrace (originalPacket);
   702         }
   703       else
   704         {
   705           packetType = PACKET_OTHERHOST;
   706         }
   707       
   708       if (!m_promiscRxCallback.IsNull ())
   709         {
   710           m_promiscRxCallback (this, packet, protocol, header.GetSource (), header.GetDestination (), packetType);
   711         }
   712 
   713       if (packetType != PACKET_OTHERHOST)
   714         {
   715           m_rxCallback (this, packet, protocol, header.GetSource ());
   716         }
   717     }
   718 }
   719 
   720   Ptr<Queue>
   721 CsmaNetDevice::GetQueue (void) const 
   722 { 
   723   NS_LOG_FUNCTION_NOARGS ();
   724   return m_queue;
   725 }
   726 
   727   void
   728 CsmaNetDevice::NotifyLinkUp (void)
   729 {
   730   NS_LOG_FUNCTION_NOARGS ();
   731 
   732   m_linkUp = true;
   733   if (m_linkChangeCallback.IsNull () == false)
   734     {
   735       m_linkChangeCallback ();
   736     }
   737 }
   738 
   739   void 
   740 CsmaNetDevice::SetName (const std::string name)
   741 {
   742   NS_LOG_FUNCTION (name);
   743   m_name = name;
   744 }
   745 
   746   std::string 
   747 CsmaNetDevice::GetName (void) const
   748 {
   749   NS_LOG_FUNCTION_NOARGS ();
   750   return m_name;
   751 }
   752 
   753   void 
   754 CsmaNetDevice::SetIfIndex (const uint32_t index)
   755 {
   756   NS_LOG_FUNCTION (index);
   757   m_ifIndex = index;
   758 }
   759 
   760   uint32_t 
   761 CsmaNetDevice::GetIfIndex (void) const
   762 {
   763   NS_LOG_FUNCTION_NOARGS ();
   764   return m_ifIndex;
   765 }
   766 
   767   Ptr<Channel> 
   768 CsmaNetDevice::GetChannel (void) const
   769 {
   770   NS_LOG_FUNCTION_NOARGS ();
   771   return m_channel;
   772 }
   773 
   774   Address 
   775 CsmaNetDevice::GetAddress (void) const
   776 {
   777   NS_LOG_FUNCTION_NOARGS ();
   778   return m_address;
   779 }
   780 
   781   bool 
   782 CsmaNetDevice::IsLinkUp (void) const
   783 {
   784   NS_LOG_FUNCTION_NOARGS ();
   785   return m_linkUp;
   786 }
   787 
   788   void 
   789 CsmaNetDevice::SetLinkChangeCallback (Callback<void> callback)
   790 {
   791   NS_LOG_FUNCTION (&callback);
   792   m_linkChangeCallback = callback;
   793 }
   794 
   795   bool 
   796 CsmaNetDevice::IsBroadcast (void) const
   797 {
   798   NS_LOG_FUNCTION_NOARGS ();
   799   return true;
   800 }
   801 
   802   Address
   803 CsmaNetDevice::GetBroadcast (void) const
   804 {
   805   NS_LOG_FUNCTION_NOARGS ();
   806   return Mac48Address ("ff:ff:ff:ff:ff:ff");
   807 }
   808 
   809   bool 
   810 CsmaNetDevice::IsMulticast (void) const
   811 {
   812   NS_LOG_FUNCTION_NOARGS ();
   813   return true;
   814 }
   815 
   816   Address 
   817 CsmaNetDevice::GetMulticast (Ipv4Address multicastGroup) const
   818 {
   819   NS_LOG_FUNCTION (multicastGroup);
   820 
   821   Mac48Address ad = Mac48Address::GetMulticast (multicastGroup);
   822 
   823   //
   824   // Implicit conversion (operator Address ()) is defined for Mac48Address, so
   825   // use it by just returning the EUI-48 address which is automagically converted
   826   // to an Address.
   827   //
   828   NS_LOG_LOGIC ("multicast address is " << ad);
   829 
   830   return ad;
   831 }
   832 
   833   bool 
   834 CsmaNetDevice::IsPointToPoint (void) const
   835 {
   836   NS_LOG_FUNCTION_NOARGS ();
   837   return false;
   838 }
   839 
   840   bool
   841 CsmaNetDevice::Send (Ptr<Packet> packet,const Address& dest, uint16_t protocolNumber)
   842 {
   843   NS_LOG_FUNCTION (packet << dest << protocolNumber);
   844   return SendFrom (packet, m_address, dest, protocolNumber);
   845 }
   846 
   847   bool
   848 CsmaNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
   849 {
   850   NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
   851   NS_LOG_LOGIC ("p=" << packet);
   852   NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")");
   853 
   854   NS_ASSERT (IsLinkUp ());
   855 
   856   //
   857   // Only transmit if send side of net device is enabled
   858   //
   859   if (IsSendEnabled () == false)
   860     {
   861       return false;
   862     }
   863 
   864   Mac48Address destination = Mac48Address::ConvertFrom (dest);
   865   Mac48Address source = Mac48Address::ConvertFrom (src);
   866   AddHeader (packet, source, destination, protocolNumber);
   867 
   868   //
   869   // Place the packet to be sent on the send queue
   870   //
   871   if (m_queue->Enqueue(packet) == false)
   872     {
   873       return false;
   874     }
   875 
   876   //
   877   // If the device is idle, we need to start a transmission. Otherwise,
   878   // the transmission will be started when the current packet finished
   879   // transmission (see TransmitCompleteEvent)
   880   //
   881   if (m_txMachineState == READY) 
   882     {
   883       //
   884       // The next packet to be transmitted goes in m_currentPkt
   885       //
   886       m_currentPkt = m_queue->Dequeue ();
   887       if (m_currentPkt != 0)
   888         {
   889           TransmitStart ();
   890         }
   891     }
   892   return true;
   893 }
   894 
   895   Ptr<Node> 
   896 CsmaNetDevice::GetNode (void) const
   897 {
   898   NS_LOG_FUNCTION_NOARGS ();
   899   return m_node;
   900 }
   901 
   902   void 
   903 CsmaNetDevice::SetNode (Ptr<Node> node)
   904 {
   905   NS_LOG_FUNCTION (node);
   906 
   907   m_node = node;
   908   int count = -1;
   909   if (m_name.size () == 0)
   910     {
   911       for (uint32_t i = 0; i < node->GetNDevices (); i++)
   912         {
   913           Ptr<NetDevice> dev = node->GetDevice (i);
   914           if (dynamic_cast<CsmaNetDevice*> (PeekPointer (dev)))
   915             {
   916               count++;
   917               if (dev == this)
   918                 {
   919                   break;
   920                 }
   921             }
   922         }
   923       std::ostringstream s;
   924       s << "eth" << count;
   925       m_name = s.str ();
   926     }
   927 }
   928 
   929   bool 
   930 CsmaNetDevice::NeedsArp (void) const
   931 {
   932   NS_LOG_FUNCTION_NOARGS ();
   933   return true;
   934 }
   935 
   936   void 
   937 CsmaNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
   938 {
   939   NS_LOG_FUNCTION (&cb);
   940   m_rxCallback = cb;
   941 }
   942 
   943 Address CsmaNetDevice::GetMulticast (Ipv6Address addr) const
   944 {
   945   Mac48Address ad = Mac48Address::GetMulticast (addr);
   946 
   947   NS_LOG_LOGIC("MAC IPv6 multicast address is " << ad);
   948   return ad;
   949 }
   950 
   951   void 
   952 CsmaNetDevice::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
   953 {
   954   NS_LOG_FUNCTION (&cb);
   955   m_promiscRxCallback = cb;
   956 }
   957 
   958   bool 
   959 CsmaNetDevice::SupportsSendFrom () const
   960 {
   961   NS_LOG_FUNCTION_NOARGS ();
   962   return true;
   963 }
   964 
   965 } // namespace ns3