src/devices/emu/emu-net-device.cc
author Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
Tue, 17 Aug 2010 21:28:08 -0700
changeset 6580 ecb0f9a3849a
parent 6576 29512368dd2e
permissions -rw-r--r--
Call StopDevice() in EmuNetDevice::DoDispose()
craigdo@3827
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
craigdo@3827
     2
/*
craigdo@3827
     3
 * Copyright (c) 2008 University of Washington
craigdo@3827
     4
 *
craigdo@3827
     5
 * This program is free software; you can redistribute it and/or modify
craigdo@3827
     6
 * it under the terms of the GNU General Public License version 2 as
craigdo@3827
     7
 * published by the Free Software Foundation;
craigdo@3827
     8
 *
craigdo@3827
     9
 * This program is distributed in the hope that it will be useful,
craigdo@3827
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
craigdo@3827
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
craigdo@3827
    12
 * GNU General Public License for more details.
craigdo@3827
    13
 *
craigdo@3827
    14
 * You should have received a copy of the GNU General Public License
craigdo@3827
    15
 * along with this program; if not, write to the Free Software
craigdo@3827
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
craigdo@3827
    17
 */
craigdo@3827
    18
craigdo@3830
    19
#include "emu-net-device.h"
craigdo@3830
    20
#include "emu-encode-decode.h"
craigdo@3827
    21
craigdo@3827
    22
#include "ns3/log.h"
craigdo@3827
    23
#include "ns3/queue.h"
craigdo@3827
    24
#include "ns3/simulator.h"
craigdo@3827
    25
#include "ns3/ethernet-header.h"
craigdo@3827
    26
#include "ns3/ethernet-trailer.h"
craigdo@3827
    27
#include "ns3/llc-snap-header.h"
craigdo@4263
    28
#include "ns3/boolean.h"
craigdo@4263
    29
#include "ns3/uinteger.h"
craigdo@4263
    30
#include "ns3/pointer.h"
craigdo@4263
    31
#include "ns3/string.h"
craigdo@3827
    32
#include "ns3/trace-source-accessor.h"
craigdo@3827
    33
#include "ns3/channel.h"
craigdo@3827
    34
#include "ns3/system-thread.h"
craigdo@4263
    35
#include "ns3/mac48-address.h"
craigdo@5822
    36
#include "ns3/enum.h"
craigdo@3827
    37
craigdo@3830
    38
#include <sys/wait.h>
craigdo@3830
    39
#include <sys/stat.h>
craigdo@3827
    40
#include <sys/socket.h>
craigdo@3830
    41
#include <sys/un.h>
craigdo@3827
    42
#include <sys/ioctl.h>
craigdo@3827
    43
#include <net/ethernet.h>
craigdo@3827
    44
#include <net/if.h>
craigdo@3827
    45
#include <netinet/in.h>
craigdo@3827
    46
#include <netpacket/packet.h>
craigdo@3827
    47
#include <arpa/inet.h>
craigdo@3830
    48
#include <errno.h>
craigdo@3851
    49
#include <limits>
craigdo@3851
    50
#include <stdlib.h>
gjc@6576
    51
#include <time.h>
craigdo@3827
    52
craigdo@3830
    53
NS_LOG_COMPONENT_DEFINE ("EmuNetDevice");
craigdo@3827
    54
craigdo@3827
    55
namespace ns3 {
craigdo@3827
    56
craigdo@3830
    57
NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice);
craigdo@3827
    58
craigdo@3831
    59
#define EMU_MAGIC 65867
craigdo@3831
    60
craigdo@3827
    61
TypeId 
craigdo@3830
    62
EmuNetDevice::GetTypeId (void)
craigdo@3827
    63
{
craigdo@3830
    64
  static TypeId tid = TypeId ("ns3::EmuNetDevice")
craigdo@3827
    65
    .SetParent<NetDevice> ()
craigdo@3830
    66
    .AddConstructor<EmuNetDevice> ()
mathieu@6183
    67
    .AddAttribute ("Mtu", "The MAC-level Maximum Transmission Unit",
mathieu@6183
    68
                   UintegerValue (0), // arbitrary un-used value because no setter
mathieu@6183
    69
                   MakeUintegerAccessor (&EmuNetDevice::GetMtu),
mathieu@6183
    70
                   MakeUintegerChecker<uint16_t> ())                   
craigdo@3827
    71
    .AddAttribute ("Address", 
craigdo@3827
    72
                   "The ns-3 MAC address of this (virtual) device.",
craigdo@3827
    73
                   Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
craigdo@3830
    74
                   MakeMac48AddressAccessor (&EmuNetDevice::m_address),
craigdo@3827
    75
                   MakeMac48AddressChecker ())
craigdo@4370
    76
    .AddAttribute ("DeviceName", 
craigdo@4370
    77
                   "The name of the underlying real device (e.g. eth1).",
craigdo@4370
    78
                   StringValue ("eth1"),
craigdo@4370
    79
                   MakeStringAccessor (&EmuNetDevice::m_deviceName),
craigdo@4370
    80
                   MakeStringChecker ())
craigdo@3827
    81
    .AddAttribute ("Start", 
craigdo@3827
    82
                   "The simulation time at which to spin up the device thread.",
craigdo@3827
    83
                   TimeValue (Seconds (0.)),
craigdo@3830
    84
                   MakeTimeAccessor (&EmuNetDevice::m_tStart),
craigdo@3827
    85
                   MakeTimeChecker ())
craigdo@3827
    86
    .AddAttribute ("Stop", 
craigdo@3827
    87
                   "The simulation time at which to tear down the device thread.",
craigdo@3827
    88
                   TimeValue (Seconds (0.)),
craigdo@3830
    89
                   MakeTimeAccessor (&EmuNetDevice::m_tStop),
craigdo@3827
    90
                   MakeTimeChecker ())
craigdo@5822
    91
    .AddAttribute ("EncapsulationMode", 
craigdo@5822
    92
                   "The link-layer encapsulation type to use.",
craigdo@5822
    93
                   EnumValue (LLC),
craigdo@5822
    94
                   MakeEnumAccessor (&EmuNetDevice::SetEncapsulationMode),
craigdo@5822
    95
                   MakeEnumChecker (DIX, "Dix",
craigdo@5822
    96
                                    LLC, "Llc"))
craigdo@4263
    97
craigdo@4263
    98
    //
craigdo@4263
    99
    // Transmit queueing discipline for the device which includes its own set
craigdo@4263
   100
    // of trace hooks.  Note that this is really going to run "on top of" the 
craigdo@4263
   101
    // queueing discipline that will most likely be present in the devices of
craigdo@4263
   102
    // the underlying operating system.
craigdo@4263
   103
    //
craigdo@3827
   104
    .AddAttribute ("TxQueue", 
craigdo@3827
   105
                   "A queue to use as the transmit queue in the device.",
craigdo@3827
   106
                   PointerValue (),
craigdo@3830
   107
                   MakePointerAccessor (&EmuNetDevice::m_queue),
craigdo@3827
   108
                   MakePointerChecker<Queue> ())
craigdo@4263
   109
gjc@6576
   110
    .AddAttribute ("RxQueueSize", "Maximum size of the read queue.  "
gjc@6576
   111
                   "This value limits number of packets that have been read "
gjc@6576
   112
                   "from the network into a memory buffer but have not yet "
gjc@6576
   113
                   "been processed by the simulator.",
gjc@6576
   114
                   UintegerValue (1000),
gjc@6576
   115
                   MakeUintegerAccessor (&EmuNetDevice::m_maxPendingReads),
gjc@6576
   116
                   MakeUintegerChecker<uint32_t> ())
gjc@6576
   117
craigdo@4263
   118
    //
craigdo@4263
   119
    // Trace sources at the "top" of the net device, where packets transition
craigdo@4263
   120
    // to/from higher layers.  These points do not really correspond to the 
craigdo@4263
   121
    // MAC layer of the underlying operating system, but exist to provide 
craigdo@4263
   122
    // a consitent tracing environment.  These trace hooks should really be
craigdo@4263
   123
    // interpreted as the points at which a packet leaves the ns-3 environment
craigdo@4263
   124
    // destined for the underlying operating system or vice-versa.
craigdo@4263
   125
    //
craigdo@4263
   126
    .AddTraceSource ("MacTx", 
craigdo@4263
   127
                     "Trace source indicating a packet has arrived for transmission by this device",
craigdo@4263
   128
                     MakeTraceSourceAccessor (&EmuNetDevice::m_macTxTrace))
craigdo@4263
   129
    .AddTraceSource ("MacTxDrop", 
craigdo@4263
   130
                     "Trace source indicating a packet has been dropped by the device before transmission",
craigdo@4263
   131
                     MakeTraceSourceAccessor (&EmuNetDevice::m_macTxDropTrace))
craigdo@4272
   132
    .AddTraceSource ("MacPromiscRx", 
craigdo@4272
   133
                     "A packet has been received by this device, has been passed up from the physical layer "
craigdo@4272
   134
                     "and is being forwarded up the local protocol stack.  This is a promiscuous trace,",
craigdo@4272
   135
                     MakeTraceSourceAccessor (&EmuNetDevice::m_macPromiscRxTrace))
craigdo@4263
   136
    .AddTraceSource ("MacRx", 
craigdo@4272
   137
                     "A packet has been received by this device, has been passed up from the physical layer "
craigdo@4272
   138
                     "and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,",
craigdo@4263
   139
                     MakeTraceSourceAccessor (&EmuNetDevice::m_macRxTrace))
craigdo@4264
   140
#if 0
craigdo@4264
   141
    // Not currently implemented for this device
craigdo@4264
   142
    .AddTraceSource ("MacRxDrop", 
craigdo@4264
   143
                     "Trace source indicating a packet was dropped before being forwarded up the stack",
craigdo@4264
   144
                     MakeTraceSourceAccessor (&EmuNetDevice::m_macRxDropTrace))
craigdo@4264
   145
#endif
craigdo@4263
   146
    //
craigdo@4263
   147
    // In normal ns-3 net devices, these trace souces correspond to the "bottom"
craigdo@4263
   148
    // of the net device, where packets transition to/from the channel.  In 
craigdo@4264
   149
    // the case of the emu device, there is no physical layer access -- all we
craigdo@4264
   150
    // do is to send packets to another device that is really at a "real" MAC
craigdo@4264
   151
    // level.  Since it could be misleading to call anything here PHY, we do not
craigdo@4264
   152
    // implement these trace sources.
craigdo@4263
   153
    //
craigdo@4264
   154
#if 0
craigdo@4264
   155
    .AddTraceSource ("PhyTxBegin", 
craigdo@4263
   156
                     "Trace source indicating a packet has begun transmitting over the channel",
craigdo@4264
   157
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxBeginTrace))
craigdo@4264
   158
    .AddTraceSource ("PhyTxEnd", 
craigdo@4263
   159
                     "Trace source indicating a packet has been completely transmitted over the channel",
craigdo@4264
   160
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxEndTrace))
craigdo@4263
   161
    .AddTraceSource ("PhyTxDrop", 
craigdo@4263
   162
                     "Trace source indicating a packet has been dropped by the device during transmission",
craigdo@4263
   163
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyTxDropTrace))
craigdo@4264
   164
    .AddTraceSource ("PhyRxBegin", 
craigdo@4263
   165
                     "Trace source indicating a packet has begun being received by the device",
craigdo@4264
   166
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxBeginTrace))
craigdo@4264
   167
    .AddTraceSource ("PhyRxEnd", 
craigdo@4263
   168
                     "Trace source indicating a packet has been completely received by the device",
craigdo@4264
   169
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxEndTrace))
craigdo@4263
   170
    .AddTraceSource ("PhyRxDrop", 
craigdo@4263
   171
                     "Trace source indicating a packet has been dropped by the device during reception",
craigdo@4263
   172
                     MakeTraceSourceAccessor (&EmuNetDevice::m_phyRxDropTrace))
craigdo@4264
   173
#endif
craigdo@4263
   174
    //
craigdo@4263
   175
    // Trace sources designed to simulate a packet sniffer facility (tcpdump). 
craigdo@4263
   176
    //
craigdo@4263
   177
    .AddTraceSource ("Sniffer", 
craigdo@4263
   178
                     "Trace source simulating a non-promiscuous packet sniffer attached to the device",
craigdo@4263
   179
                     MakeTraceSourceAccessor (&EmuNetDevice::m_snifferTrace))
craigdo@4263
   180
    .AddTraceSource ("PromiscSniffer", 
craigdo@4263
   181
                     "Trace source simulating a promiscuous packet sniffer attached to the device",
craigdo@4263
   182
                     MakeTraceSourceAccessor (&EmuNetDevice::m_promiscSnifferTrace))
craigdo@3827
   183
    ;
craigdo@3827
   184
  return tid;
craigdo@3827
   185
}
craigdo@3827
   186
craigdo@3830
   187
EmuNetDevice::EmuNetDevice () 
craigdo@3827
   188
: 
craigdo@3827
   189
  m_startEvent (),
craigdo@3827
   190
  m_stopEvent (),
craigdo@3827
   191
  m_sock (-1),
craigdo@3827
   192
  m_readThread (0),
craigdo@3850
   193
  m_ifIndex (std::numeric_limits<uint32_t>::max ()),  // absurdly large value
tomh@4479
   194
  m_sll_ifindex (-1),
tomh@4479
   195
  m_isBroadcast (true),
gjc@6576
   196
  m_isMulticast (false),
gjc@6576
   197
  m_pendingReadCount (0)
craigdo@3827
   198
{
craigdo@3827
   199
  NS_LOG_FUNCTION (this);
craigdo@5822
   200
  m_packetBuffer = new uint8_t[65536];
craigdo@3827
   201
  Start (m_tStart);
craigdo@3827
   202
}
craigdo@3827
   203
craigdo@3830
   204
EmuNetDevice::~EmuNetDevice ()
craigdo@3827
   205
{
craigdo@5829
   206
  delete [] m_packetBuffer;
craigdo@5829
   207
  m_packetBuffer = 0;
craigdo@3827
   208
}
craigdo@3827
   209
craigdo@3827
   210
void 
craigdo@3830
   211
EmuNetDevice::DoDispose()
craigdo@3827
   212
{
craigdo@3827
   213
  NS_LOG_FUNCTION_NOARGS ();
gjc@6580
   214
  if (m_readThread != 0)
gjc@6580
   215
    {
gjc@6580
   216
      StopDevice ();
gjc@6580
   217
    }
craigdo@3827
   218
  m_node = 0;
craigdo@3827
   219
  NetDevice::DoDispose ();
craigdo@3827
   220
}
craigdo@3827
   221
craigdo@5822
   222
void 
craigdo@5822
   223
EmuNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
craigdo@5822
   224
{
craigdo@5822
   225
  NS_LOG_FUNCTION (mode);
craigdo@5822
   226
  m_encapMode = mode;
craigdo@5822
   227
  NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
craigdo@5822
   228
}
craigdo@5822
   229
craigdo@5822
   230
EmuNetDevice::EncapsulationMode
craigdo@5822
   231
EmuNetDevice::GetEncapsulationMode (void) const
craigdo@5822
   232
{
craigdo@5822
   233
  NS_LOG_FUNCTION_NOARGS ();
craigdo@5822
   234
  return m_encapMode;
craigdo@5822
   235
}
craigdo@5822
   236
craigdo@3827
   237
void
craigdo@3830
   238
EmuNetDevice::Start (Time tStart)
craigdo@3827
   239
{
craigdo@3827
   240
  NS_LOG_FUNCTION (tStart);
craigdo@3827
   241
craigdo@3827
   242
  //
craigdo@3827
   243
  // Cancel any pending start event and schedule a new one at some relative time in the future.
craigdo@3827
   244
  //
craigdo@3827
   245
  Simulator::Cancel (m_startEvent);
craigdo@3830
   246
  m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
craigdo@3827
   247
}
craigdo@3827
   248
craigdo@3827
   249
  void
craigdo@3830
   250
EmuNetDevice::Stop (Time tStop)
craigdo@3827
   251
{
craigdo@3827
   252
  NS_LOG_FUNCTION (tStop);
craigdo@3827
   253
  //
craigdo@3827
   254
  // Cancel any pending stop event and schedule a new one at some relative time in the future.
craigdo@3827
   255
  //
craigdo@3827
   256
  Simulator::Cancel (m_stopEvent);
craigdo@3830
   257
  m_startEvent = Simulator::Schedule (tStop, &EmuNetDevice::StopDevice, this);
craigdo@3827
   258
}
craigdo@3827
   259
craigdo@3827
   260
  void
craigdo@3830
   261
EmuNetDevice::StartDevice (void)
craigdo@3827
   262
{
craigdo@3827
   263
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   264
craigdo@3827
   265
  //
craigdo@3830
   266
  // Spin up the emu net device and start receiving packets.
craigdo@3827
   267
  //
craigdo@3847
   268
  if (m_sock != -1)
craigdo@3847
   269
    {
craigdo@3847
   270
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Device is already started");
craigdo@3847
   271
    }
craigdo@3827
   272
craigdo@5829
   273
  //
craigdo@5829
   274
  // We're going to need a pointer to the realtime simulator implementation.
craigdo@5829
   275
  // It's important to remember that access to that implementation may happen 
craigdo@5829
   276
  // in a completely different thread than the simulator is running in (we're 
craigdo@5829
   277
  // going to spin up that thread below).  We are talking about multiple threads
craigdo@5829
   278
  // here, so it is very, very dangerous to do any kind of reference couning on
craigdo@5829
   279
  // a shared object that is unaware of what is happening.  What we are going to 
craigdo@5829
   280
  // do to address that is to get a reference to the realtime simulator here 
craigdo@5829
   281
  // where we are running in the context of a running simulator scheduler --
craigdo@5829
   282
  // recall we did a Simulator::Schedule of this method above.  We get the
craigdo@5829
   283
  // simulator implementation pointer in a single-threaded way and save the
craigdo@5829
   284
  // underlying raw pointer for use by the (other) read thread.  We must not
craigdo@5829
   285
  // free this pointer or we may delete the simulator out from under us an 
craigdo@5829
   286
  // everyone else.  We assume that the simulator implementation cannot be 
craigdo@5829
   287
  // replaced while the emu device is running and so will remain valid through
craigdo@5829
   288
  // the time during which the read thread is running.
craigdo@5829
   289
  //
craigdo@5829
   290
  Ptr<RealtimeSimulatorImpl> impl = DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ());
craigdo@5829
   291
  m_rtImpl = GetPointer (impl);
craigdo@5829
   292
craigdo@6004
   293
  //
craigdo@6004
   294
  // A similar story exists for the node ID.  We can't just naively do a
craigdo@6004
   295
  // GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
craigdo@6004
   296
  // is reference counted.  We need to stash away the node ID for use in the
craigdo@6004
   297
  // read thread.
craigdo@6004
   298
  //
craigdo@6004
   299
  m_nodeId = GetNode ()->GetId ();
craigdo@6004
   300
craigdo@3827
   301
  NS_LOG_LOGIC ("Creating socket");
craigdo@5829
   302
craigdo@3830
   303
  //
craigdo@3830
   304
  // Call out to a separate process running as suid root in order to get a raw 
craigdo@3830
   305
  // socket.  We do this to avoid having the entire simulation running as root.
craigdo@3830
   306
  // If this method returns, we'll have a raw socket waiting for us in m_sock.
craigdo@3830
   307
  //
craigdo@3830
   308
  CreateSocket ();
craigdo@3827
   309
craigdo@3827
   310
  //
craigdo@3827
   311
  // Figure out which interface index corresponds to the device name in the corresponding attribute.
craigdo@3827
   312
  //
craigdo@3827
   313
  struct ifreq ifr;
craigdo@3827
   314
  bzero (&ifr, sizeof(ifr));
craigdo@3827
   315
  strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
craigdo@3827
   316
craigdo@3827
   317
  NS_LOG_LOGIC ("Getting interface index");
craigdo@3827
   318
  int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
craigdo@3847
   319
  if (rc == -1)
craigdo@3847
   320
    {
craigdo@3847
   321
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface index");
craigdo@3847
   322
    }
craigdo@3827
   323
craigdo@3827
   324
  //
craigdo@3827
   325
  // Save the real interface index for later calls to sendto
craigdo@3827
   326
  //
craigdo@3827
   327
  m_sll_ifindex = ifr.ifr_ifindex;
craigdo@3827
   328
craigdo@3827
   329
  //
craigdo@3827
   330
  // Bind the socket to the interface we just found.
craigdo@3827
   331
  //
craigdo@3827
   332
  struct sockaddr_ll ll;
craigdo@3827
   333
  bzero (&ll, sizeof(ll));
craigdo@3827
   334
craigdo@3827
   335
  ll.sll_family = AF_PACKET;
craigdo@3827
   336
  ll.sll_ifindex = m_sll_ifindex;
craigdo@3827
   337
  ll.sll_protocol = htons(ETH_P_ALL); 
craigdo@3827
   338
craigdo@3827
   339
  NS_LOG_LOGIC ("Binding socket to interface");
craigdo@3827
   340
craigdo@3827
   341
  rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
craigdo@3847
   342
  if (rc == -1)
craigdo@3847
   343
    {
craigdo@3847
   344
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't bind to specified interface");
craigdo@3847
   345
    }
craigdo@3827
   346
craigdo@3831
   347
  rc = ioctl(m_sock, SIOCGIFFLAGS, &ifr);
craigdo@3847
   348
  if (rc == -1)
craigdo@3847
   349
    {
craigdo@3847
   350
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface flags");
craigdo@3847
   351
    }
craigdo@3831
   352
  
craigdo@3831
   353
  //
craigdo@3831
   354
  // This device only works if the underlying interface is up in promiscuous 
craigdo@3831
   355
  // mode.  We could have turned it on in the socket creator, but the situation
craigdo@3831
   356
  // is that we expect these devices to be used in conjunction with virtual 
craigdo@3831
   357
  // machines with connected host-only (simulated) networks, or in a testbed.
craigdo@3831
   358
  // There is a lot of setup and configuration happening outside of this one 
craigdo@3831
   359
  // issue, and we expect that configuration to include choosing a valid
craigdo@3831
   360
  // interface (e.g, "ath1"), ensuring that the device supports promiscuous 
craigdo@3831
   361
  // mode, and placing it in promiscuous mode.  We just make sure of the
craigdo@3831
   362
  // end result.
craigdo@3831
   363
  //
craigdo@3831
   364
  if ((ifr.ifr_flags & IFF_PROMISC) == 0)
craigdo@3831
   365
    {
craigdo@3831
   366
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): " << m_deviceName << " is not in promiscuous mode");
craigdo@3831
   367
    }
tomh@4479
   368
  if ((ifr.ifr_flags & IFF_BROADCAST) != IFF_BROADCAST)
tomh@4479
   369
    {
tomh@4479
   370
      // We default m_isBroadcast to true but turn it off here if not
tomh@4479
   371
      // supported, because in the common case, overlying IP code will 
tomh@4479
   372
      // assert during configuration time if this is false, before this
tomh@4479
   373
      // method has a chance to set it during runtime
tomh@4479
   374
      m_isBroadcast = false;
tomh@4479
   375
    }
tomh@4479
   376
  if ((ifr.ifr_flags & IFF_MULTICAST) == IFF_MULTICAST)
tomh@4479
   377
    {
tomh@4479
   378
      // This one is OK to enable at runtime
tomh@4479
   379
      m_isMulticast = true;
tomh@4479
   380
    }
craigdo@5822
   381
craigdo@3827
   382
  //
craigdo@3827
   383
  // Now spin up a read thread to read packets.
craigdo@3827
   384
  //
craigdo@3847
   385
  if (m_readThread != 0)
craigdo@3847
   386
    {
craigdo@3847
   387
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Receive thread is already running");
craigdo@3847
   388
    }
craigdo@3827
   389
craigdo@3827
   390
  NS_LOG_LOGIC ("Spinning up read thread");
craigdo@3827
   391
craigdo@3830
   392
  m_readThread = Create<SystemThread> (MakeCallback (&EmuNetDevice::ReadThread, this));
craigdo@3827
   393
  m_readThread->Start ();
craigdo@3827
   394
craigdo@3827
   395
  NotifyLinkUp ();
craigdo@3827
   396
}
craigdo@3827
   397
craigdo@3827
   398
void
craigdo@3830
   399
EmuNetDevice::CreateSocket (void)
craigdo@3830
   400
{
craigdo@3830
   401
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3830
   402
  //
craigdo@3830
   403
  // We want to create a raw socket for our net device.  Unfortunately for us
craigdo@3830
   404
  // you have to have root privileges to do that.  Instead of running the 
craigdo@3830
   405
  // entire simulation as root, we decided to make a small program who's whole
craigdo@3830
   406
  // reason for being is to run as suid root and create a raw socket.  We're
craigdo@3830
   407
  // going to fork and exec that program soon, but we need to have a socket
craigdo@3830
   408
  // to talk to it with.  So we create a local interprocess (Unix) socket 
craigdo@3830
   409
  // for that purpose.
craigdo@3830
   410
  //
craigdo@3830
   411
  int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
craigdo@3830
   412
  if (sock == -1)
craigdo@3830
   413
    {
craigdo@3830
   414
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Unix socket creation error, errno = " << strerror (errno));
craigdo@3830
   415
    }
craigdo@3830
   416
craigdo@3830
   417
  //
craigdo@3830
   418
  // Bind to that socket and let the kernel allocate an endpoint
craigdo@3830
   419
  //
craigdo@3830
   420
  struct sockaddr_un un;
craigdo@3830
   421
  memset (&un, 0, sizeof (un));
craigdo@3830
   422
  un.sun_family = AF_UNIX;
craigdo@3830
   423
  int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
craigdo@3830
   424
  if (status == -1)
craigdo@3830
   425
    {
craigdo@3830
   426
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << strerror (errno));
craigdo@3830
   427
    }
craigdo@3830
   428
craigdo@3831
   429
  NS_LOG_INFO ("Created Unix socket");
craigdo@3831
   430
  NS_LOG_INFO ("sun_family = " << un.sun_family);
craigdo@3831
   431
  NS_LOG_INFO ("sun_path = " << un.sun_path);
craigdo@3831
   432
craigdo@3830
   433
  //
craigdo@3830
   434
  // We have a socket here, but we want to get it there -- to the program we're
craigdo@3830
   435
  // going to exec.  What we'll do is to do a getsockname and then encode the
craigdo@3830
   436
  // resulting address information as a string, and then send the string to the
craigdo@3830
   437
  // program as an argument.  So we need to get the sock name.
craigdo@3830
   438
  //
craigdo@3830
   439
  socklen_t len = sizeof (un);
craigdo@3830
   440
  status = getsockname (sock, (struct sockaddr*)&un, &len);
craigdo@3830
   441
  if (status == -1)
craigdo@3830
   442
    {
craigdo@3830
   443
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not getsockname(): errno = " << strerror (errno));
craigdo@3830
   444
    }
craigdo@3830
   445
craigdo@3830
   446
  //
craigdo@3831
   447
  // Now encode that socket name (family and path) as a string of hex digits
craigdo@3830
   448
  //
craigdo@3831
   449
  std::string path = EmuBufferToString((uint8_t *)&un, len);
craigdo@3831
   450
  NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
craigdo@3830
   451
  //
craigdo@3830
   452
  // Fork and exec the process to create our socket.  If we're us (the parent)
craigdo@3830
   453
  // we wait for the child (the socket creator) to complete and read the 
craigdo@3830
   454
  // socket it created using the ancillary data mechanism.
craigdo@3830
   455
  //
tgoff@6086
   456
  // Tom Goff reports the possiblility of a deadlock when trying to acquire the
tgoff@6086
   457
  // python GIL here.  He says that this might be due to trying to access Python
tgoff@6086
   458
  // objects after fork() without calling PyOS_AfterFork() to properly reset 
tgoff@6086
   459
  // Python state (including the GIL).  There is no code to cause the problem
tgoff@6086
   460
  // here in emu, but this was visible in similar code in tap-bridge.
tgoff@6086
   461
  //
craigdo@3830
   462
  pid_t pid = ::fork ();
craigdo@3830
   463
  if (pid == 0)
craigdo@3830
   464
    {
craigdo@3830
   465
      NS_LOG_DEBUG ("Child process");
craigdo@3830
   466
craigdo@3830
   467
      //
craigdo@3830
   468
      // build a command line argument from the encoded endpoint string that 
craigdo@3830
   469
      // the socket creation process will use to figure out how to respond to
craigdo@3830
   470
      // the (now) parent process.
craigdo@3830
   471
      //
craigdo@3830
   472
      std::ostringstream oss;
craigdo@3835
   473
      oss << "-p" << path;
craigdo@3831
   474
      NS_LOG_INFO ("Parameters set to \"" << oss.str () << "\"");
craigdo@3830
   475
craigdo@3830
   476
      //
craigdo@3830
   477
      // Execute the socket creation process image.
craigdo@3830
   478
      //
craigdo@5975
   479
      status = ::execlp ("emu-sock-creator", 
craigdo@4417
   480
                        "emu-sock-creator",                             // argv[0] (filename)
craigdo@4417
   481
                        oss.str ().c_str (),                            // argv[1] (-p<path?
craigdo@4417
   482
                        (char *)NULL);
craigdo@3830
   483
craigdo@3830
   484
      //
craigdo@5975
   485
      // If the execlp successfully completes, it never returns.  If it returns it failed or the OS is
craigdo@3830
   486
      // broken.  In either case, we bail.
craigdo@3830
   487
      //
craigdo@5975
   488
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Back from execlp(), errno = " << ::strerror (errno));
craigdo@3830
   489
    }
craigdo@3830
   490
  else
craigdo@3830
   491
    {
craigdo@3830
   492
      NS_LOG_DEBUG ("Parent process");
craigdo@3830
   493
      //
craigdo@3830
   494
      // We're the process running the emu net device.  We need to wait for the
craigdo@3830
   495
      // socket creator process to finish its job.
craigdo@3830
   496
      //
craigdo@3830
   497
      int st;
craigdo@3830
   498
      pid_t waited = waitpid (pid, &st, 0);
craigdo@3830
   499
      if (waited == -1)
craigdo@3830
   500
	{
craigdo@3830
   501
	  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): waitpid() fails, errno = " << strerror (errno));
craigdo@3830
   502
	}
craigdo@3830
   503
      NS_ASSERT_MSG (pid == waited, "EmuNetDevice::CreateSocket(): pid mismatch");
craigdo@3830
   504
craigdo@3830
   505
      //
craigdo@3830
   506
      // Check to see if the socket creator exited normally and then take a 
craigdo@3830
   507
      // look at the exit code.  If it bailed, so should we.  If it didn't
craigdo@3830
   508
      // even exit normally, we bail too.
craigdo@3830
   509
      //
craigdo@3830
   510
      if (WIFEXITED (st))
craigdo@3830
   511
	{
craigdo@3830
   512
          int exitStatus = WEXITSTATUS (st);
craigdo@3830
   513
          if (exitStatus != 0)
craigdo@3830
   514
            {
craigdo@3830
   515
              NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited normally with status " << exitStatus);
craigdo@3830
   516
            }
craigdo@3830
   517
	}
craigdo@3830
   518
      else 
craigdo@3830
   519
	{
craigdo@3830
   520
          NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited abnormally");
craigdo@3830
   521
	}
craigdo@3830
   522
craigdo@3830
   523
      //
craigdo@3830
   524
      // At this point, the socket creator has run successfully and should 
craigdo@3830
   525
      // have created our raw socket and sent it back to the socket address
craigdo@3830
   526
      // we provided.  Our socket should be waiting on the Unix socket.  We've
craigdo@3830
   527
      // got to do a bunch of grunto work to get at it, though.
craigdo@3830
   528
      //
craigdo@3830
   529
      // The struct iovec below is part of a scatter-gather list.  It describes a
craigdo@3830
   530
      // buffer.  In this case, it describes a buffer (an integer) that will
craigdo@3830
   531
      // get the data that comes back from the socket creator process.  It will
craigdo@3830
   532
      // be a magic number that we use as a consistency/sanity check.
craigdo@3830
   533
      // 
craigdo@3830
   534
      struct iovec iov;
craigdo@3830
   535
      uint32_t magic;
craigdo@3830
   536
      iov.iov_base = &magic;
craigdo@3830
   537
      iov.iov_len = sizeof(magic);
craigdo@3830
   538
craigdo@3830
   539
      //
craigdo@3830
   540
      // The CMSG macros you'll see below are used to create and access control 
craigdo@3830
   541
      // messages (which is another name for ancillary data).  The ancillary 
craigdo@3830
   542
      // data is made up of pairs of struct cmsghdr structures and associated
craigdo@3830
   543
      // data arrays.
craigdo@3830
   544
      //
craigdo@3830
   545
      // First, we're going to allocate a buffer on the stack to receive our 
craigdo@3830
   546
      // data array (that contains the socket).  Sometimes you'll see this called
craigdo@3830
   547
      // an "ancillary element" but the msghdr uses the control message termimology
craigdo@3830
   548
      // so we call it "control."
craigdo@3830
   549
      //
craigdo@3830
   550
      size_t msg_size = sizeof(int);
craigdo@3830
   551
      char control[CMSG_SPACE(msg_size)];
craigdo@3830
   552
craigdo@3830
   553
      //
craigdo@3830
   554
      // There is a msghdr that is used to minimize the number of parameters
craigdo@3830
   555
      // passed to recvmsg (which we will use to receive our ancillary data).  
craigdo@3830
   556
      // This structure uses terminology corresponding to control messages, so
craigdo@3830
   557
      // you'll see msg_control, which is the pointer to the ancillary data and 
craigdo@3830
   558
      // controllen which is the size of the ancillary data array.
craigdo@3830
   559
      //
craigdo@3830
   560
      // So, initialize the message header that describes the ancillary/control
craigdo@3830
   561
      // data we expect to receive and point it to buffer.
craigdo@3830
   562
      //
craigdo@3830
   563
      struct msghdr msg;
craigdo@3830
   564
      msg.msg_name = 0;
craigdo@3830
   565
      msg.msg_namelen = 0;
craigdo@3830
   566
      msg.msg_iov = &iov;
craigdo@3830
   567
      msg.msg_iovlen = 1;
craigdo@3830
   568
      msg.msg_control = control;
craigdo@3830
   569
      msg.msg_controllen = sizeof (control);
craigdo@3830
   570
      msg.msg_flags = 0;
craigdo@3830
   571
craigdo@3830
   572
      //
craigdo@3830
   573
      // Now we can actually receive the interesting bits from the socket
craigdo@3830
   574
      // creator process.
craigdo@3830
   575
      //
craigdo@3830
   576
      ssize_t bytesRead = recvmsg (sock, &msg, 0);
craigdo@3830
   577
      if (bytesRead != sizeof(int))
craigdo@3830
   578
	{
craigdo@3830
   579
          NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Wrong byte count from socket creator");
craigdo@3830
   580
	}
craigdo@3830
   581
craigdo@3830
   582
      //
craigdo@3830
   583
      // There may be a number of message headers/ancillary data arrays coming in.
craigdo@3830
   584
      // Let's look for the one with a type SCM_RIGHTS which indicates it' the
craigdo@3830
   585
      // one we're interested in.
craigdo@3830
   586
      //
craigdo@3830
   587
      struct cmsghdr *cmsg;
craigdo@3830
   588
      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) 
craigdo@3830
   589
	{
craigdo@3830
   590
	  if (cmsg->cmsg_level == SOL_SOCKET &&
craigdo@3830
   591
	      cmsg->cmsg_type == SCM_RIGHTS)
craigdo@3830
   592
	    {
craigdo@3831
   593
              //
craigdo@3831
   594
              // This is the type of message we want.  Check to see if the magic 
craigdo@3831
   595
              // number is correct and then pull out the socket we care about if
craigdo@3831
   596
              // it matches
craigdo@3831
   597
              //
craigdo@3831
   598
              if (magic == EMU_MAGIC)
craigdo@3831
   599
                {
craigdo@3831
   600
                  NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
craigdo@3831
   601
                  int *rawSocket = (int*)CMSG_DATA (cmsg);
craigdo@3831
   602
                  NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
craigdo@3831
   603
                  m_sock = *rawSocket;
craigdo@3831
   604
                  return;
craigdo@3831
   605
                }
craigdo@3831
   606
              else
craigdo@3831
   607
                {
craigdo@3831
   608
                  NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);                  
craigdo@3831
   609
                }
craigdo@3830
   610
	    }
craigdo@3830
   611
	}
craigdo@3830
   612
      NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
craigdo@3830
   613
    }
craigdo@3830
   614
}
craigdo@3830
   615
craigdo@3830
   616
void
craigdo@3830
   617
EmuNetDevice::StopDevice (void)
craigdo@3827
   618
{
craigdo@3827
   619
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   620
craigdo@3827
   621
  close (m_sock);
craigdo@3827
   622
  m_sock = -1;
craigdo@3827
   623
craigdo@3830
   624
  NS_ASSERT_MSG (m_readThread != 0, "EmuNetDevice::StopDevice(): Receive thread is not running");
craigdo@3827
   625
craigdo@3827
   626
  NS_LOG_LOGIC ("Joining read thread");
craigdo@3827
   627
  m_readThread->Join ();
craigdo@3827
   628
  m_readThread = 0;
craigdo@3827
   629
}
craigdo@3827
   630
craigdo@3827
   631
void
craigdo@3830
   632
EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
craigdo@3827
   633
{
craigdo@3827
   634
  NS_LOG_FUNCTION (buf << len);
craigdo@3827
   635
craigdo@3827
   636
  //
craigdo@3827
   637
  // Create a packet out of the buffer we received and free that buffer.
craigdo@3827
   638
  //
craigdo@3827
   639
  Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
craigdo@3827
   640
  free (buf);
craigdo@3827
   641
  buf = 0;
craigdo@3827
   642
gjc@6576
   643
  {
gjc@6576
   644
    CriticalSection cs (m_pendingReadMutex);
gjc@6576
   645
    //std::cerr << std::endl << "EmuNetDevice main thread: m_pendingReadCount is " << m_pendingReadCount << std::endl;
gjc@6576
   646
    --m_pendingReadCount;
gjc@6576
   647
  }
gjc@6576
   648
craigdo@3827
   649
  //
craigdo@3827
   650
  // Trace sinks will expect complete packets, not packets without some of the
craigdo@3827
   651
  // headers.
craigdo@3827
   652
  //
craigdo@3827
   653
  Ptr<Packet> originalPacket = packet->Copy ();
craigdo@3827
   654
craigdo@3827
   655
  EthernetHeader header (false);
craigdo@4676
   656
craigdo@4676
   657
  //
craigdo@4676
   658
  // This device could be running in an environment where completely unexpected
craigdo@4676
   659
  // kinds of packets are flying around, so we need to harden things a bit and
craigdo@4676
   660
  // filter out packets we think are completely bogus, so we always check to see
craigdo@4676
   661
  // that the packet is long enough to contain the header we want to remove.
craigdo@4676
   662
  //
craigdo@4676
   663
  if (packet->GetSize() < header.GetSerializedSize())
craigdo@4676
   664
    {
craigdo@4676
   665
      m_phyRxDropTrace (originalPacket);
craigdo@4676
   666
      return;
craigdo@4676
   667
    }
craigdo@4676
   668
craigdo@3827
   669
  packet->RemoveHeader (header);
craigdo@3827
   670
craigdo@3827
   671
  NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
craigdo@3827
   672
  NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
craigdo@3827
   673
craigdo@4263
   674
  uint16_t protocol;
craigdo@4263
   675
  
craigdo@5822
   676
  switch (m_encapMode)
craigdo@4263
   677
    {
craigdo@5822
   678
    case LLC:
craigdo@4676
   679
      //
craigdo@5822
   680
      // If the length/type is less than 1500, it corresponds to a length 
craigdo@5822
   681
      // interpretation packet.  In this case, it is an 802.3 packet and 
craigdo@5822
   682
      // will also have an 802.2 LLC header.  If greater than 1500, we
craigdo@5822
   683
      // find the protocol number (Ethernet type) directly.
craigdo@4676
   684
      //
craigdo@5822
   685
      if (header.GetLengthType () <= 1500)
craigdo@4676
   686
        {
craigdo@5822
   687
          LlcSnapHeader llc;
craigdo@5822
   688
          //
craigdo@5822
   689
          // Check to see that the packet is long enough to possibly contain the
craigdo@5822
   690
          // header we want to remove before just naively calling.
craigdo@5822
   691
          //
craigdo@5822
   692
          if (packet->GetSize() < llc.GetSerializedSize())
craigdo@5822
   693
            {
craigdo@5822
   694
              m_phyRxDropTrace (originalPacket);
craigdo@5822
   695
              return;
craigdo@5822
   696
            }
craigdo@5822
   697
craigdo@5822
   698
          packet->RemoveHeader (llc);
craigdo@5822
   699
          protocol = llc.GetType ();
craigdo@4676
   700
        }
craigdo@5822
   701
      else
craigdo@5822
   702
        {
craigdo@5822
   703
          protocol = header.GetLengthType ();
craigdo@5822
   704
        }
craigdo@5822
   705
      break;
craigdo@4676
   706
craigdo@5822
   707
    case DIX:
craigdo@4263
   708
      protocol = header.GetLengthType ();
craigdo@5822
   709
      break;
craigdo@5822
   710
craigdo@5822
   711
    default:
craigdo@5822
   712
      NS_FATAL_ERROR ("invalid encapsulation mode");
mazo@5834
   713
      protocol = 0; /* quiet compiler */
craigdo@4263
   714
    }
craigdo@3827
   715
craigdo@3827
   716
  PacketType packetType;
f1mauchl@4424
   717
vincent@3842
   718
  if (header.GetDestination ().IsBroadcast ())
craigdo@3827
   719
    {
craigdo@3827
   720
      packetType = NS3_PACKET_BROADCAST;
craigdo@3827
   721
    }
f1mauchl@4424
   722
  else if (header.GetDestination ().IsGroup ())
craigdo@3827
   723
    {
craigdo@4263
   724
      packetType = NS3_PACKET_MULTICAST;          
craigdo@3827
   725
    }
vincent@3842
   726
  else if (header.GetDestination () == m_address)
craigdo@3827
   727
    {
craigdo@3827
   728
      packetType = NS3_PACKET_HOST;
craigdo@3827
   729
    }
craigdo@3827
   730
  else
craigdo@3827
   731
    {
craigdo@3827
   732
      packetType = NS3_PACKET_OTHERHOST;
craigdo@3827
   733
    }
craigdo@3827
   734
craigdo@4263
   735
  // 
craigdo@4263
   736
  // For all kinds of packetType we receive, we hit the promiscuous sniffer
craigdo@4263
   737
  // hook and pass a copy up to the promiscuous callback.  Pass a copy to 
craigdo@4263
   738
  // make sure that nobody messes with our packet.
craigdo@4263
   739
  //
craigdo@4263
   740
  m_promiscSnifferTrace (originalPacket);
craigdo@4264
   741
craigdo@3827
   742
  if (!m_promiscRxCallback.IsNull ())
craigdo@3827
   743
    {
craigdo@4272
   744
      m_macPromiscRxTrace (originalPacket);
craigdo@4265
   745
      m_promiscRxCallback (this, packet, protocol, header.GetSource (), header.GetDestination (), packetType);
craigdo@3827
   746
    }
craigdo@3827
   747
craigdo@4263
   748
  //
craigdo@4263
   749
  // If this packet is not destined for some other host, it must be for us
craigdo@4263
   750
  // as either a broadcast, multicast or unicast.  We need to hit the mac
craigdo@4263
   751
  // packet received trace hook and forward the packet up the stack.
craigdo@4263
   752
  //
craigdo@3827
   753
  if (packetType != NS3_PACKET_OTHERHOST)
craigdo@3827
   754
    {
craigdo@4263
   755
      m_snifferTrace (originalPacket);
craigdo@4263
   756
      m_macRxTrace (originalPacket);
craigdo@3827
   757
      m_rxCallback (this, packet, protocol, header.GetSource ());
craigdo@3827
   758
    }
craigdo@3827
   759
}
craigdo@3827
   760
craigdo@3827
   761
void
craigdo@3830
   762
EmuNetDevice::ReadThread (void)
craigdo@3827
   763
{
craigdo@3827
   764
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   765
craigdo@5822
   766
  // It's important to remember that we're in a completely different thread than the simulator is running in.
craigdo@5822
   767
  // We are talking about multiple threads here, so it is very, very dangerous to do any kind of reference couning
craigdo@5822
   768
  // on a shared object.
craigdo@3827
   769
  //
craigdo@3827
   770
craigdo@3827
   771
  int32_t len = -1;
craigdo@3827
   772
  struct sockaddr_ll addr;
craigdo@3827
   773
  socklen_t addrSize = sizeof (addr);
craigdo@3827
   774
craigdo@3827
   775
  for (;;) 
craigdo@3827
   776
    {
craigdo@5822
   777
      //
gjc@6576
   778
      // Too many pending reads at the same time leads to excessive memory allocations.  This counter prevents it.
gjc@6576
   779
      // 
gjc@6576
   780
      bool skip = false;
gjc@6576
   781
      
gjc@6576
   782
      {
gjc@6576
   783
        CriticalSection cs (m_pendingReadMutex);            
gjc@6576
   784
        //std::cerr << std::endl << "EmuNetDevice read thread: m_pendingReadCount is " << m_pendingReadCount << std::endl;
gjc@6576
   785
        if (m_pendingReadCount >= m_maxPendingReads)
gjc@6576
   786
          {
gjc@6576
   787
            skip = true;
gjc@6576
   788
          }
gjc@6576
   789
        else
gjc@6576
   790
          {
gjc@6576
   791
            ++m_pendingReadCount;
gjc@6576
   792
          }
gjc@6576
   793
      }
gjc@6576
   794
gjc@6576
   795
      if (skip)  
gjc@6576
   796
        {           
gjc@6576
   797
          struct timespec time = { 0, 100000000L }; // 100 ms
gjc@6576
   798
          nanosleep (&time, NULL);
gjc@6576
   799
          continue;
gjc@6576
   800
        }
gjc@6576
   801
gjc@6576
   802
      //
craigdo@5822
   803
      // to avoid any issues with a shared reference counted packet, we allocate a buffer on the heap and pass that
craigdo@5822
   804
      // buffer into the ns-3 context thread where it will create the packet, copy the buffer and then free it.
craigdo@5822
   805
      //
craigdo@3827
   806
      uint32_t bufferSize = 65536;
craigdo@3827
   807
      uint8_t *buf = (uint8_t *)malloc (bufferSize);
craigdo@3847
   808
      if (buf == 0)
craigdo@3847
   809
        {
craigdo@3847
   810
          NS_FATAL_ERROR ("EmuNetDevice::ReadThread(): malloc packet buffer failed");
craigdo@3847
   811
        }
craigdo@3847
   812
craigdo@3827
   813
      NS_LOG_LOGIC ("Calling recvfrom");
craigdo@3827
   814
      len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
craigdo@3827
   815
craigdo@3827
   816
      if (len == -1)
craigdo@3827
   817
        {
craigdo@3827
   818
          free (buf);
craigdo@3827
   819
          buf = 0;
craigdo@3827
   820
          return;
craigdo@3827
   821
        }
craigdo@3827
   822
craigdo@6004
   823
      NS_LOG_INFO ("EmuNetDevice::EmuNetDevice(): Received packet on node " << m_nodeId);
craigdo@3830
   824
      NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
craigdo@5822
   825
      NS_ASSERT_MSG (m_rtImpl, "EmuNetDevice::ReadThread(): Realtime simulator implementation pointer not set");
craigdo@6004
   826
      m_rtImpl->ScheduleRealtimeNowWithContext (m_nodeId, MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
craigdo@3827
   827
      buf = 0;
craigdo@3827
   828
    }
craigdo@3827
   829
}
craigdo@3827
   830
craigdo@3827
   831
bool 
craigdo@3830
   832
EmuNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
craigdo@3827
   833
{
craigdo@3827
   834
  NS_LOG_FUNCTION (packet << dest << protocolNumber);
craigdo@3827
   835
  //
craigdo@3827
   836
  // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and 
craigdo@3827
   837
  // destination (hardware) addresses?
craigdo@3827
   838
  //
craigdo@3830
   839
  // If we return false from EmuNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the 
craigdo@3830
   840
  // hardware (Ethernet) destination by default.  If we return true from EmuNetDevice::NeedsArp, then the hardware
craigdo@3827
   841
  // destination is actually meaningful, but we'll have an ns-3 ARP running on this device.  There can also be an ARP
craigdo@3827
   842
  // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
craigdo@3827
   843
  //
craigdo@3827
   844
  // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the 
craigdo@3827
   845
  // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses.  We don't actually have
craigdo@3827
   846
  // to use the real hardware addresses and IP addresses of the underlying system.  We can completely use MAC-spoofing to
craigdo@3827
   847
  // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses).  Ns-3 starts its 
craigdo@3827
   848
  // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
craigdo@3827
   849
  // administered address, so there shouldn't be any collisions with real hardware.
craigdo@3827
   850
  //
craigdo@3830
   851
  // So what we do is we return true from EmuNetDevice::NeedsArp which tells ns-3 to use its own ARP.  We spoof the 
craigdo@3827
   852
  // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
craigdo@3827
   853
  //
craigdo@3827
   854
  return SendFrom (packet, m_address, dest, protocolNumber);
craigdo@3827
   855
}
craigdo@3827
   856
craigdo@3827
   857
bool 
craigdo@3830
   858
EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
craigdo@3827
   859
{
craigdo@3827
   860
  NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
craigdo@4263
   861
  NS_LOG_LOGIC ("packet =" << packet);
craigdo@4263
   862
  NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")");
craigdo@3827
   863
craigdo@3827
   864
  if (IsLinkUp () == false)
craigdo@3827
   865
    {
craigdo@4263
   866
      m_macTxDropTrace (packet);
craigdo@3827
   867
      return false;
craigdo@3827
   868
    }
craigdo@3827
   869
craigdo@3827
   870
  Mac48Address destination = Mac48Address::ConvertFrom (dest);
craigdo@3827
   871
  Mac48Address source = Mac48Address::ConvertFrom (src);
craigdo@3827
   872
craigdo@3827
   873
  NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
craigdo@3827
   874
  NS_LOG_LOGIC ("Transmit packet from " << source);
craigdo@3827
   875
  NS_LOG_LOGIC ("Transmit packet to " << destination);
craigdo@3827
   876
craigdo@3827
   877
  EthernetHeader header (false);
craigdo@3827
   878
  header.SetSource (source);
craigdo@3827
   879
  header.SetDestination (destination);
craigdo@5822
   880
craigdo@5822
   881
  switch (m_encapMode)
craigdo@5822
   882
    {
craigdo@5822
   883
    case LLC:
craigdo@5822
   884
      {
craigdo@5822
   885
        LlcSnapHeader llc;
craigdo@5822
   886
        llc.SetType (protocolNumber);
craigdo@5822
   887
        packet->AddHeader (llc);
craigdo@5822
   888
craigdo@5822
   889
        header.SetLengthType (packet->GetSize ());
craigdo@5822
   890
      }
craigdo@5822
   891
      break;
craigdo@5822
   892
      
craigdo@5822
   893
    case DIX:
craigdo@5822
   894
      header.SetLengthType (protocolNumber);
craigdo@5822
   895
      break;
craigdo@5822
   896
      
craigdo@5822
   897
    default:
craigdo@5822
   898
      NS_FATAL_ERROR ("invalid encapsulation mode");
craigdo@5822
   899
    }
craigdo@5822
   900
  
craigdo@3827
   901
  packet->AddHeader (header);
craigdo@3827
   902
craigdo@4263
   903
  //
craigdo@4263
   904
  // there's not much meaning associated with the different layers in this
craigdo@4263
   905
  // device, so don't be surprised when they're all stacked together in 
craigdo@4263
   906
  // essentially one place.  We do this for trace consistency across devices.
craigdo@4263
   907
  //
craigdo@4263
   908
  m_macTxTrace (packet);
craigdo@4263
   909
craigdo@3827
   910
  // 
craigdo@4263
   911
  // Enqueue and dequeue the packet to hit the queue tracing hooks.
craigdo@3827
   912
  //
craigdo@3827
   913
  m_queue->Enqueue (packet);
craigdo@3827
   914
  packet = m_queue->Dequeue ();
craigdo@4263
   915
  NS_ASSERT_MSG (packet, "EmuNetDevice::SendFrom(): packet zero from queue");
craigdo@4263
   916
craigdo@4263
   917
  m_promiscSnifferTrace (packet);
craigdo@4263
   918
  m_snifferTrace (packet);
craigdo@4263
   919
craigdo@3827
   920
  struct sockaddr_ll ll;
craigdo@3827
   921
  bzero (&ll, sizeof (ll));
craigdo@3827
   922
craigdo@3827
   923
  ll.sll_family = AF_PACKET;
craigdo@3827
   924
  ll.sll_ifindex = m_sll_ifindex;
craigdo@3827
   925
  ll.sll_protocol = htons(ETH_P_ALL); 
craigdo@3827
   926
craigdo@3827
   927
  NS_LOG_LOGIC ("calling sendto");
craigdo@3827
   928
craigdo@5822
   929
  NS_ASSERT_MSG (packet->GetSize () <= 65536, "EmuNetDevice::SendFrom(): Packet too big " << packet->GetSize ());
craigdo@5822
   930
  packet->CopyData (m_packetBuffer, packet->GetSize ());
craigdo@5822
   931
craigdo@5822
   932
  int32_t rc = sendto (m_sock, m_packetBuffer, packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
craigdo@4263
   933
  NS_LOG_LOGIC ("sendto returns " << rc);
craigdo@3827
   934
craigdo@3827
   935
  return rc == -1 ? false : true;
craigdo@3827
   936
}
craigdo@3827
   937
craigdo@3827
   938
void 
craigdo@3830
   939
EmuNetDevice::SetDataRate(DataRate bps)
craigdo@3827
   940
{
craigdo@3827
   941
  NS_LOG_FUNCTION (this << bps);
craigdo@3847
   942
  NS_FATAL_ERROR ("EmuNetDevice::SetDataRate():  Unable."); 
craigdo@3827
   943
}
craigdo@3827
   944
craigdo@3827
   945
void
craigdo@3830
   946
EmuNetDevice::SetQueue (Ptr<Queue> q)
craigdo@3827
   947
{
craigdo@3827
   948
  NS_LOG_FUNCTION (this << q);
craigdo@3827
   949
  m_queue = q;
craigdo@3827
   950
}
craigdo@3827
   951
craigdo@3827
   952
Ptr<Queue> 
craigdo@3830
   953
EmuNetDevice::GetQueue(void) const 
craigdo@3827
   954
{ 
craigdo@3827
   955
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   956
  return m_queue;
craigdo@3827
   957
}
craigdo@3827
   958
craigdo@3827
   959
void
craigdo@3830
   960
EmuNetDevice::NotifyLinkUp (void)
craigdo@3827
   961
{
craigdo@3827
   962
  m_linkUp = true;
vincent@4764
   963
  m_linkChangeCallbacks ();
craigdo@3827
   964
}
craigdo@3827
   965
craigdo@3827
   966
void 
craigdo@3830
   967
EmuNetDevice::SetIfIndex(const uint32_t index)
craigdo@3827
   968
{
craigdo@3827
   969
  m_ifIndex = index;
craigdo@3827
   970
}
craigdo@3827
   971
craigdo@3827
   972
uint32_t 
craigdo@3830
   973
EmuNetDevice::GetIfIndex(void) const
craigdo@3827
   974
{
craigdo@3827
   975
  return m_ifIndex;
craigdo@3827
   976
}
craigdo@3827
   977
craigdo@3827
   978
Ptr<Channel> 
craigdo@3830
   979
EmuNetDevice::GetChannel (void) const
craigdo@3827
   980
{
craigdo@3847
   981
  NS_FATAL_ERROR ("EmuNetDevice::GetChannel():  Unable."); 
craigdo@3827
   982
  return 0;
craigdo@3827
   983
}
craigdo@3827
   984
craigdo@3827
   985
void 
craigdo@4578
   986
EmuNetDevice::SetAddress (Address address)
craigdo@3827
   987
{
craigdo@4578
   988
  NS_LOG_FUNCTION (address);
craigdo@4578
   989
  m_address = Mac48Address::ConvertFrom (address);
craigdo@3827
   990
}
craigdo@3827
   991
craigdo@3827
   992
Address 
craigdo@3830
   993
EmuNetDevice::GetAddress (void) const
craigdo@3827
   994
{
craigdo@3827
   995
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   996
  return m_address;
craigdo@3827
   997
}
craigdo@3827
   998
craigdo@3827
   999
bool 
craigdo@3830
  1000
EmuNetDevice::SetMtu (const uint16_t mtu)
craigdo@3827
  1001
{
craigdo@3847
  1002
  NS_FATAL_ERROR ("EmuNetDevice::SetMtu():  Unable."); 
craigdo@3827
  1003
  return false;
craigdo@3827
  1004
}
craigdo@3827
  1005
craigdo@3827
  1006
uint16_t 
craigdo@3830
  1007
EmuNetDevice::GetMtu (void) const
craigdo@3827
  1008
{
craigdo@3827
  1009
  struct ifreq ifr;
craigdo@3827
  1010
  bzero (&ifr, sizeof (ifr));
craigdo@3827
  1011
  strcpy(ifr.ifr_name, m_deviceName.c_str ());
craigdo@3827
  1012
craigdo@3827
  1013
  int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
craigdo@3827
  1014
craigdo@3847
  1015
craigdo@3827
  1016
  int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
craigdo@3847
  1017
  if (rc == -1)
craigdo@3847
  1018
    {
craigdo@3847
  1019
      NS_FATAL_ERROR ("EmuNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
craigdo@3847
  1020
    }
craigdo@3827
  1021
craigdo@3827
  1022
  close (fd);
craigdo@3827
  1023
craigdo@3827
  1024
  return ifr.ifr_mtu;
craigdo@3827
  1025
}
craigdo@3827
  1026
craigdo@3827
  1027
bool 
craigdo@3830
  1028
EmuNetDevice::IsLinkUp (void) const
craigdo@3827
  1029
{
craigdo@3827
  1030
  return m_linkUp;
craigdo@3827
  1031
}
craigdo@3827
  1032
craigdo@3827
  1033
void 
vincent@4764
  1034
EmuNetDevice::AddLinkChangeCallback (Callback<void> callback)
craigdo@3827
  1035
{
vincent@4764
  1036
  m_linkChangeCallbacks.ConnectWithoutContext (callback);
craigdo@3827
  1037
}
craigdo@3827
  1038
craigdo@3827
  1039
bool 
craigdo@3830
  1040
EmuNetDevice::IsBroadcast (void) const
craigdo@3827
  1041
{
tomh@4479
  1042
  return m_isBroadcast;
craigdo@3827
  1043
}
craigdo@3827
  1044
craigdo@3827
  1045
Address
craigdo@3830
  1046
EmuNetDevice::GetBroadcast (void) const
craigdo@3827
  1047
{
craigdo@3827
  1048
  return Mac48Address ("ff:ff:ff:ff:ff:ff");
craigdo@3827
  1049
}
craigdo@3827
  1050
craigdo@3827
  1051
bool 
craigdo@3830
  1052
EmuNetDevice::IsMulticast (void) const
craigdo@3827
  1053
{
tomh@4479
  1054
  return m_isMulticast;
craigdo@3827
  1055
}
craigdo@3827
  1056
vincent@3842
  1057
  Address 
vincent@3842
  1058
EmuNetDevice::GetMulticast (Ipv4Address multicastGroup) const
craigdo@3827
  1059
{
craigdo@3836
  1060
  NS_LOG_FUNCTION (multicastGroup);
craigdo@3836
  1061
vincent@3842
  1062
  Mac48Address ad = Mac48Address::GetMulticast (multicastGroup);
craigdo@3836
  1063
craigdo@3836
  1064
  //
craigdo@3836
  1065
  // Implicit conversion (operator Address ()) is defined for Mac48Address, so
craigdo@3836
  1066
  // use it by just returning the EUI-48 address which is automagically converted
craigdo@3836
  1067
  // to an Address.
craigdo@3836
  1068
  //
vincent@3842
  1069
  NS_LOG_LOGIC ("multicast address is " << ad);
vincent@3842
  1070
vincent@3842
  1071
  return ad;
craigdo@3827
  1072
}
craigdo@3827
  1073
vincent@3852
  1074
Address
vincent@3852
  1075
EmuNetDevice::GetMulticast (Ipv6Address addr) const
vincent@3852
  1076
{
vincent@3852
  1077
  NS_LOG_FUNCTION(this << addr);
vincent@3852
  1078
vincent@3852
  1079
  Mac48Address ad = Mac48Address::GetMulticast (addr);
vincent@3852
  1080
  NS_LOG_LOGIC("MAC IPv6 multicast address is " << ad);
vincent@3852
  1081
vincent@3852
  1082
  return ad;
vincent@3852
  1083
}
vincent@3852
  1084
craigdo@3827
  1085
bool 
craigdo@3830
  1086
EmuNetDevice::IsPointToPoint (void) const
craigdo@3827
  1087
{
craigdo@3827
  1088
  return false;
craigdo@3827
  1089
}
craigdo@3827
  1090
craigdo@3936
  1091
bool 
craigdo@3936
  1092
EmuNetDevice::IsBridge (void) const
craigdo@3936
  1093
{
craigdo@3936
  1094
  return false;
craigdo@3936
  1095
}
craigdo@3936
  1096
craigdo@3827
  1097
void
craigdo@3830
  1098
EmuNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
craigdo@3827
  1099
{
gjc@6278
  1100
  m_promiscRxCallback = cb;
craigdo@3827
  1101
}
craigdo@3827
  1102
craigdo@3827
  1103
  bool 
craigdo@3830
  1104
EmuNetDevice::SupportsSendFrom () const
craigdo@3827
  1105
{
craigdo@3827
  1106
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
  1107
  return true;
craigdo@3827
  1108
}
craigdo@3827
  1109
craigdo@3827
  1110
craigdo@3827
  1111
Ptr<Node> 
craigdo@3830
  1112
EmuNetDevice::GetNode (void) const
craigdo@3827
  1113
{
craigdo@3827
  1114
  return m_node;
craigdo@3827
  1115
}
craigdo@3827
  1116
craigdo@3827
  1117
void 
craigdo@3830
  1118
EmuNetDevice::SetNode (Ptr<Node> node)
craigdo@3827
  1119
{
craigdo@3827
  1120
  m_node = node;
craigdo@3827
  1121
}
craigdo@3827
  1122
craigdo@3827
  1123
bool 
craigdo@3830
  1124
EmuNetDevice::NeedsArp (void) const
craigdo@3827
  1125
{
craigdo@3827
  1126
  return true;
craigdo@3827
  1127
}
craigdo@3827
  1128
craigdo@3827
  1129
void 
craigdo@3830
  1130
EmuNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
craigdo@3827
  1131
{
craigdo@3827
  1132
  m_rxCallback = cb;
craigdo@3827
  1133
}
craigdo@3827
  1134
craigdo@3827
  1135
} // namespace ns3