src/devices/emu/emu-net-device.cc
author vincent@clarinet.u-strasbg.fr
Fri Nov 07 11:36:15 2008 -0800 (2008-11-07)
changeset 3852 9cf7ad0cac85
parent 3851 cc6a7f93dc3f
child 3936 e525995ce5dc
permissions -rw-r--r--
Initial IPv6 capability
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/realtime-simulator-impl.h"
craigdo@3827
    26
#include "ns3/mac48-address.h"
craigdo@3827
    27
#include "ns3/ethernet-header.h"
craigdo@3827
    28
#include "ns3/ethernet-trailer.h"
craigdo@3827
    29
#include "ns3/llc-snap-header.h"
craigdo@3827
    30
#include "ns3/trace-source-accessor.h"
craigdo@3827
    31
#include "ns3/pointer.h"
craigdo@3827
    32
#include "ns3/channel.h"
craigdo@3827
    33
#include "ns3/system-thread.h"
craigdo@3827
    34
#include "ns3/string.h"
craigdo@3827
    35
#include "ns3/boolean.h"
craigdo@3827
    36
craigdo@3830
    37
#include <sys/wait.h>
craigdo@3830
    38
#include <sys/stat.h>
craigdo@3827
    39
#include <sys/socket.h>
craigdo@3830
    40
#include <sys/un.h>
craigdo@3827
    41
#include <sys/ioctl.h>
craigdo@3827
    42
#include <net/ethernet.h>
craigdo@3827
    43
#include <net/if.h>
craigdo@3827
    44
#include <netinet/in.h>
craigdo@3827
    45
#include <netpacket/packet.h>
craigdo@3827
    46
#include <arpa/inet.h>
craigdo@3830
    47
#include <errno.h>
craigdo@3851
    48
#include <limits>
craigdo@3851
    49
#include <stdlib.h>
craigdo@3827
    50
craigdo@3830
    51
NS_LOG_COMPONENT_DEFINE ("EmuNetDevice");
craigdo@3827
    52
craigdo@3827
    53
namespace ns3 {
craigdo@3827
    54
craigdo@3830
    55
NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice);
craigdo@3827
    56
craigdo@3831
    57
#define EMU_MAGIC 65867
craigdo@3831
    58
craigdo@3827
    59
TypeId 
craigdo@3830
    60
EmuNetDevice::GetTypeId (void)
craigdo@3827
    61
{
craigdo@3830
    62
  static TypeId tid = TypeId ("ns3::EmuNetDevice")
craigdo@3827
    63
    .SetParent<NetDevice> ()
craigdo@3830
    64
    .AddConstructor<EmuNetDevice> ()
craigdo@3827
    65
    .AddAttribute ("Address", 
craigdo@3827
    66
                   "The ns-3 MAC address of this (virtual) device.",
craigdo@3827
    67
                   Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
craigdo@3830
    68
                   MakeMac48AddressAccessor (&EmuNetDevice::m_address),
craigdo@3827
    69
                   MakeMac48AddressChecker ())
craigdo@3827
    70
    .AddAttribute ("DeviceName", 
craigdo@3827
    71
                   "The name of the underlying real device (e.g. eth1).",
craigdo@3827
    72
                   StringValue ("eth1"),
craigdo@3830
    73
                   MakeStringAccessor (&EmuNetDevice::m_deviceName),
craigdo@3827
    74
                   MakeStringChecker ())
craigdo@3827
    75
    .AddAttribute ("Start", 
craigdo@3827
    76
                   "The simulation time at which to spin up the device thread.",
craigdo@3827
    77
                   TimeValue (Seconds (0.)),
craigdo@3830
    78
                   MakeTimeAccessor (&EmuNetDevice::m_tStart),
craigdo@3827
    79
                   MakeTimeChecker ())
craigdo@3827
    80
    .AddAttribute ("Stop", 
craigdo@3827
    81
                   "The simulation time at which to tear down the device thread.",
craigdo@3827
    82
                   TimeValue (Seconds (0.)),
craigdo@3830
    83
                   MakeTimeAccessor (&EmuNetDevice::m_tStop),
craigdo@3827
    84
                   MakeTimeChecker ())
craigdo@3827
    85
    .AddAttribute ("TxQueue", 
craigdo@3827
    86
                   "A queue to use as the transmit queue in the device.",
craigdo@3827
    87
                   PointerValue (),
craigdo@3830
    88
                   MakePointerAccessor (&EmuNetDevice::m_queue),
craigdo@3827
    89
                   MakePointerChecker<Queue> ())
craigdo@3827
    90
    .AddTraceSource ("Rx", 
craigdo@3827
    91
                     "Trace source to fire on reception of a MAC packet.",
craigdo@3830
    92
                     MakeTraceSourceAccessor (&EmuNetDevice::m_rxTrace))
craigdo@3827
    93
    .AddTraceSource ("Drop", 
craigdo@3827
    94
                     "Trace source to fire on when a MAC packet is dropped.",
craigdo@3830
    95
                     MakeTraceSourceAccessor (&EmuNetDevice::m_dropTrace))
craigdo@3827
    96
    ;
craigdo@3827
    97
  return tid;
craigdo@3827
    98
}
craigdo@3827
    99
craigdo@3827
   100
craigdo@3830
   101
EmuNetDevice::EmuNetDevice () 
craigdo@3827
   102
: 
craigdo@3827
   103
  m_startEvent (),
craigdo@3827
   104
  m_stopEvent (),
craigdo@3827
   105
  m_sock (-1),
craigdo@3827
   106
  m_readThread (0),
craigdo@3850
   107
  m_ifIndex (std::numeric_limits<uint32_t>::max ()),  // absurdly large value
craigdo@3827
   108
  m_sll_ifindex (-1),
craigdo@3830
   109
  m_name ("Emu NetDevice")
craigdo@3827
   110
{
craigdo@3827
   111
  NS_LOG_FUNCTION (this);
craigdo@3827
   112
  Start (m_tStart);
craigdo@3827
   113
}
craigdo@3827
   114
craigdo@3830
   115
EmuNetDevice::~EmuNetDevice ()
craigdo@3827
   116
{
craigdo@3827
   117
}
craigdo@3827
   118
craigdo@3827
   119
void 
craigdo@3830
   120
EmuNetDevice::DoDispose()
craigdo@3827
   121
{
craigdo@3827
   122
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   123
  m_node = 0;
craigdo@3827
   124
  NetDevice::DoDispose ();
craigdo@3827
   125
}
craigdo@3827
   126
craigdo@3827
   127
void
craigdo@3830
   128
EmuNetDevice::Start (Time tStart)
craigdo@3827
   129
{
craigdo@3827
   130
  NS_LOG_FUNCTION (tStart);
craigdo@3827
   131
craigdo@3827
   132
  //
craigdo@3827
   133
  // Cancel any pending start event and schedule a new one at some relative time in the future.
craigdo@3827
   134
  //
craigdo@3827
   135
  Simulator::Cancel (m_startEvent);
craigdo@3830
   136
  m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
craigdo@3827
   137
}
craigdo@3827
   138
craigdo@3827
   139
  void
craigdo@3830
   140
EmuNetDevice::Stop (Time tStop)
craigdo@3827
   141
{
craigdo@3827
   142
  NS_LOG_FUNCTION (tStop);
craigdo@3827
   143
  //
craigdo@3827
   144
  // Cancel any pending stop event and schedule a new one at some relative time in the future.
craigdo@3827
   145
  //
craigdo@3827
   146
  Simulator::Cancel (m_stopEvent);
craigdo@3830
   147
  m_startEvent = Simulator::Schedule (tStop, &EmuNetDevice::StopDevice, this);
craigdo@3827
   148
}
craigdo@3827
   149
craigdo@3827
   150
  void
craigdo@3830
   151
EmuNetDevice::StartDevice (void)
craigdo@3827
   152
{
craigdo@3827
   153
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   154
craigdo@3827
   155
  //
craigdo@3830
   156
  // Spin up the emu net device and start receiving packets.
craigdo@3827
   157
  //
craigdo@3847
   158
  if (m_sock != -1)
craigdo@3847
   159
    {
craigdo@3847
   160
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Device is already started");
craigdo@3847
   161
    }
craigdo@3827
   162
craigdo@3827
   163
  NS_LOG_LOGIC ("Creating socket");
craigdo@3830
   164
  //
craigdo@3830
   165
  // Call out to a separate process running as suid root in order to get a raw 
craigdo@3830
   166
  // socket.  We do this to avoid having the entire simulation running as root.
craigdo@3830
   167
  // If this method returns, we'll have a raw socket waiting for us in m_sock.
craigdo@3830
   168
  //
craigdo@3830
   169
  CreateSocket ();
craigdo@3827
   170
craigdo@3827
   171
  //
craigdo@3827
   172
  // Figure out which interface index corresponds to the device name in the corresponding attribute.
craigdo@3827
   173
  //
craigdo@3827
   174
  struct ifreq ifr;
craigdo@3827
   175
  bzero (&ifr, sizeof(ifr));
craigdo@3827
   176
  strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
craigdo@3827
   177
craigdo@3827
   178
  NS_LOG_LOGIC ("Getting interface index");
craigdo@3827
   179
  int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
craigdo@3847
   180
  if (rc == -1)
craigdo@3847
   181
    {
craigdo@3847
   182
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface index");
craigdo@3847
   183
    }
craigdo@3827
   184
craigdo@3827
   185
  //
craigdo@3827
   186
  // Save the real interface index for later calls to sendto
craigdo@3827
   187
  //
craigdo@3827
   188
  m_sll_ifindex = ifr.ifr_ifindex;
craigdo@3827
   189
craigdo@3827
   190
  //
craigdo@3827
   191
  // Bind the socket to the interface we just found.
craigdo@3827
   192
  //
craigdo@3827
   193
  struct sockaddr_ll ll;
craigdo@3827
   194
  bzero (&ll, sizeof(ll));
craigdo@3827
   195
craigdo@3827
   196
  ll.sll_family = AF_PACKET;
craigdo@3827
   197
  ll.sll_ifindex = m_sll_ifindex;
craigdo@3827
   198
  ll.sll_protocol = htons(ETH_P_ALL); 
craigdo@3827
   199
craigdo@3827
   200
  NS_LOG_LOGIC ("Binding socket to interface");
craigdo@3827
   201
craigdo@3827
   202
  rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
craigdo@3847
   203
  if (rc == -1)
craigdo@3847
   204
    {
craigdo@3847
   205
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't bind to specified interface");
craigdo@3847
   206
    }
craigdo@3827
   207
craigdo@3831
   208
  rc = ioctl(m_sock, SIOCGIFFLAGS, &ifr);
craigdo@3847
   209
  if (rc == -1)
craigdo@3847
   210
    {
craigdo@3847
   211
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface flags");
craigdo@3847
   212
    }
craigdo@3831
   213
  
craigdo@3831
   214
  //
craigdo@3831
   215
  // This device only works if the underlying interface is up in promiscuous 
craigdo@3831
   216
  // mode.  We could have turned it on in the socket creator, but the situation
craigdo@3831
   217
  // is that we expect these devices to be used in conjunction with virtual 
craigdo@3831
   218
  // machines with connected host-only (simulated) networks, or in a testbed.
craigdo@3831
   219
  // There is a lot of setup and configuration happening outside of this one 
craigdo@3831
   220
  // issue, and we expect that configuration to include choosing a valid
craigdo@3831
   221
  // interface (e.g, "ath1"), ensuring that the device supports promiscuous 
craigdo@3831
   222
  // mode, and placing it in promiscuous mode.  We just make sure of the
craigdo@3831
   223
  // end result.
craigdo@3831
   224
  //
craigdo@3831
   225
  if ((ifr.ifr_flags & IFF_PROMISC) == 0)
craigdo@3831
   226
    {
craigdo@3831
   227
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): " << m_deviceName << " is not in promiscuous mode");
craigdo@3831
   228
    }
craigdo@3831
   229
craigdo@3827
   230
  //
craigdo@3827
   231
  // Now spin up a read thread to read packets.
craigdo@3827
   232
  //
craigdo@3847
   233
  if (m_readThread != 0)
craigdo@3847
   234
    {
craigdo@3847
   235
      NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Receive thread is already running");
craigdo@3847
   236
    }
craigdo@3827
   237
craigdo@3827
   238
  NS_LOG_LOGIC ("Spinning up read thread");
craigdo@3827
   239
craigdo@3830
   240
  m_readThread = Create<SystemThread> (MakeCallback (&EmuNetDevice::ReadThread, this));
craigdo@3827
   241
  m_readThread->Start ();
craigdo@3827
   242
craigdo@3827
   243
  NotifyLinkUp ();
craigdo@3827
   244
}
craigdo@3827
   245
craigdo@3827
   246
void
craigdo@3830
   247
EmuNetDevice::CreateSocket (void)
craigdo@3830
   248
{
craigdo@3830
   249
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3830
   250
  //
craigdo@3830
   251
  // We want to create a raw socket for our net device.  Unfortunately for us
craigdo@3830
   252
  // you have to have root privileges to do that.  Instead of running the 
craigdo@3830
   253
  // entire simulation as root, we decided to make a small program who's whole
craigdo@3830
   254
  // reason for being is to run as suid root and create a raw socket.  We're
craigdo@3830
   255
  // going to fork and exec that program soon, but we need to have a socket
craigdo@3830
   256
  // to talk to it with.  So we create a local interprocess (Unix) socket 
craigdo@3830
   257
  // for that purpose.
craigdo@3830
   258
  //
craigdo@3830
   259
  int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
craigdo@3830
   260
  if (sock == -1)
craigdo@3830
   261
    {
craigdo@3830
   262
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Unix socket creation error, errno = " << strerror (errno));
craigdo@3830
   263
    }
craigdo@3830
   264
craigdo@3830
   265
  //
craigdo@3830
   266
  // Bind to that socket and let the kernel allocate an endpoint
craigdo@3830
   267
  //
craigdo@3830
   268
  struct sockaddr_un un;
craigdo@3830
   269
  memset (&un, 0, sizeof (un));
craigdo@3830
   270
  un.sun_family = AF_UNIX;
craigdo@3830
   271
  int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
craigdo@3830
   272
  if (status == -1)
craigdo@3830
   273
    {
craigdo@3830
   274
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << strerror (errno));
craigdo@3830
   275
    }
craigdo@3830
   276
craigdo@3831
   277
  NS_LOG_INFO ("Created Unix socket");
craigdo@3831
   278
  NS_LOG_INFO ("sun_family = " << un.sun_family);
craigdo@3831
   279
  NS_LOG_INFO ("sun_path = " << un.sun_path);
craigdo@3831
   280
craigdo@3830
   281
  //
craigdo@3830
   282
  // We have a socket here, but we want to get it there -- to the program we're
craigdo@3830
   283
  // going to exec.  What we'll do is to do a getsockname and then encode the
craigdo@3830
   284
  // resulting address information as a string, and then send the string to the
craigdo@3830
   285
  // program as an argument.  So we need to get the sock name.
craigdo@3830
   286
  //
craigdo@3830
   287
  socklen_t len = sizeof (un);
craigdo@3830
   288
  status = getsockname (sock, (struct sockaddr*)&un, &len);
craigdo@3830
   289
  if (status == -1)
craigdo@3830
   290
    {
craigdo@3830
   291
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not getsockname(): errno = " << strerror (errno));
craigdo@3830
   292
    }
craigdo@3830
   293
craigdo@3830
   294
  //
craigdo@3831
   295
  // Now encode that socket name (family and path) as a string of hex digits
craigdo@3830
   296
  //
craigdo@3831
   297
  std::string path = EmuBufferToString((uint8_t *)&un, len);
craigdo@3831
   298
  NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
craigdo@3830
   299
  //
craigdo@3830
   300
  // Fork and exec the process to create our socket.  If we're us (the parent)
craigdo@3830
   301
  // we wait for the child (the socket creator) to complete and read the 
craigdo@3830
   302
  // socket it created using the ancillary data mechanism.
craigdo@3830
   303
  //
craigdo@3830
   304
  pid_t pid = ::fork ();
craigdo@3830
   305
  if (pid == 0)
craigdo@3830
   306
    {
craigdo@3830
   307
      NS_LOG_DEBUG ("Child process");
craigdo@3830
   308
craigdo@3830
   309
      //
craigdo@3830
   310
      // build a command line argument from the encoded endpoint string that 
craigdo@3830
   311
      // the socket creation process will use to figure out how to respond to
craigdo@3830
   312
      // the (now) parent process.
craigdo@3830
   313
      //
craigdo@3830
   314
      std::ostringstream oss;
craigdo@3835
   315
      oss << "-p" << path;
craigdo@3831
   316
      NS_LOG_INFO ("Parameters set to \"" << oss.str () << "\"");
craigdo@3830
   317
craigdo@3830
   318
      //
craigdo@3830
   319
      // Execute the socket creation process image.
craigdo@3830
   320
      //
craigdo@3830
   321
      status = ::execl (FindCreator ().c_str (), "emu-sock-creator", oss.str ().c_str (), (char *)NULL);
craigdo@3830
   322
craigdo@3830
   323
      //
craigdo@3830
   324
      // If the execl successfully completes, it never returns.  If it returns it failed or the OS is
craigdo@3830
   325
      // broken.  In either case, we bail.
craigdo@3830
   326
      //
craigdo@3830
   327
      NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Back from execl(), errno = " << ::strerror (errno));
craigdo@3830
   328
    }
craigdo@3830
   329
  else
craigdo@3830
   330
    {
craigdo@3830
   331
      NS_LOG_DEBUG ("Parent process");
craigdo@3830
   332
      //
craigdo@3830
   333
      // We're the process running the emu net device.  We need to wait for the
craigdo@3830
   334
      // socket creator process to finish its job.
craigdo@3830
   335
      //
craigdo@3830
   336
      int st;
craigdo@3830
   337
      pid_t waited = waitpid (pid, &st, 0);
craigdo@3830
   338
      if (waited == -1)
craigdo@3830
   339
	{
craigdo@3830
   340
	  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): waitpid() fails, errno = " << strerror (errno));
craigdo@3830
   341
	}
craigdo@3830
   342
      NS_ASSERT_MSG (pid == waited, "EmuNetDevice::CreateSocket(): pid mismatch");
craigdo@3830
   343
craigdo@3830
   344
      //
craigdo@3830
   345
      // Check to see if the socket creator exited normally and then take a 
craigdo@3830
   346
      // look at the exit code.  If it bailed, so should we.  If it didn't
craigdo@3830
   347
      // even exit normally, we bail too.
craigdo@3830
   348
      //
craigdo@3830
   349
      if (WIFEXITED (st))
craigdo@3830
   350
	{
craigdo@3830
   351
          int exitStatus = WEXITSTATUS (st);
craigdo@3830
   352
          if (exitStatus != 0)
craigdo@3830
   353
            {
craigdo@3830
   354
              NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited normally with status " << exitStatus);
craigdo@3830
   355
            }
craigdo@3830
   356
	}
craigdo@3830
   357
      else 
craigdo@3830
   358
	{
craigdo@3830
   359
          NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited abnormally");
craigdo@3830
   360
	}
craigdo@3830
   361
craigdo@3830
   362
      //
craigdo@3830
   363
      // At this point, the socket creator has run successfully and should 
craigdo@3830
   364
      // have created our raw socket and sent it back to the socket address
craigdo@3830
   365
      // we provided.  Our socket should be waiting on the Unix socket.  We've
craigdo@3830
   366
      // got to do a bunch of grunto work to get at it, though.
craigdo@3830
   367
      //
craigdo@3830
   368
      // The struct iovec below is part of a scatter-gather list.  It describes a
craigdo@3830
   369
      // buffer.  In this case, it describes a buffer (an integer) that will
craigdo@3830
   370
      // get the data that comes back from the socket creator process.  It will
craigdo@3830
   371
      // be a magic number that we use as a consistency/sanity check.
craigdo@3830
   372
      // 
craigdo@3830
   373
      struct iovec iov;
craigdo@3830
   374
      uint32_t magic;
craigdo@3830
   375
      iov.iov_base = &magic;
craigdo@3830
   376
      iov.iov_len = sizeof(magic);
craigdo@3830
   377
craigdo@3830
   378
      //
craigdo@3830
   379
      // The CMSG macros you'll see below are used to create and access control 
craigdo@3830
   380
      // messages (which is another name for ancillary data).  The ancillary 
craigdo@3830
   381
      // data is made up of pairs of struct cmsghdr structures and associated
craigdo@3830
   382
      // data arrays.
craigdo@3830
   383
      //
craigdo@3830
   384
      // First, we're going to allocate a buffer on the stack to receive our 
craigdo@3830
   385
      // data array (that contains the socket).  Sometimes you'll see this called
craigdo@3830
   386
      // an "ancillary element" but the msghdr uses the control message termimology
craigdo@3830
   387
      // so we call it "control."
craigdo@3830
   388
      //
craigdo@3830
   389
      size_t msg_size = sizeof(int);
craigdo@3830
   390
      char control[CMSG_SPACE(msg_size)];
craigdo@3830
   391
craigdo@3830
   392
      //
craigdo@3830
   393
      // There is a msghdr that is used to minimize the number of parameters
craigdo@3830
   394
      // passed to recvmsg (which we will use to receive our ancillary data).  
craigdo@3830
   395
      // This structure uses terminology corresponding to control messages, so
craigdo@3830
   396
      // you'll see msg_control, which is the pointer to the ancillary data and 
craigdo@3830
   397
      // controllen which is the size of the ancillary data array.
craigdo@3830
   398
      //
craigdo@3830
   399
      // So, initialize the message header that describes the ancillary/control
craigdo@3830
   400
      // data we expect to receive and point it to buffer.
craigdo@3830
   401
      //
craigdo@3830
   402
      struct msghdr msg;
craigdo@3830
   403
      msg.msg_name = 0;
craigdo@3830
   404
      msg.msg_namelen = 0;
craigdo@3830
   405
      msg.msg_iov = &iov;
craigdo@3830
   406
      msg.msg_iovlen = 1;
craigdo@3830
   407
      msg.msg_control = control;
craigdo@3830
   408
      msg.msg_controllen = sizeof (control);
craigdo@3830
   409
      msg.msg_flags = 0;
craigdo@3830
   410
craigdo@3830
   411
      //
craigdo@3830
   412
      // Now we can actually receive the interesting bits from the socket
craigdo@3830
   413
      // creator process.
craigdo@3830
   414
      //
craigdo@3830
   415
      ssize_t bytesRead = recvmsg (sock, &msg, 0);
craigdo@3830
   416
      if (bytesRead != sizeof(int))
craigdo@3830
   417
	{
craigdo@3830
   418
          NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Wrong byte count from socket creator");
craigdo@3830
   419
	}
craigdo@3830
   420
craigdo@3830
   421
      //
craigdo@3830
   422
      // There may be a number of message headers/ancillary data arrays coming in.
craigdo@3830
   423
      // Let's look for the one with a type SCM_RIGHTS which indicates it' the
craigdo@3830
   424
      // one we're interested in.
craigdo@3830
   425
      //
craigdo@3830
   426
      struct cmsghdr *cmsg;
craigdo@3830
   427
      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) 
craigdo@3830
   428
	{
craigdo@3830
   429
	  if (cmsg->cmsg_level == SOL_SOCKET &&
craigdo@3830
   430
	      cmsg->cmsg_type == SCM_RIGHTS)
craigdo@3830
   431
	    {
craigdo@3831
   432
              //
craigdo@3831
   433
              // This is the type of message we want.  Check to see if the magic 
craigdo@3831
   434
              // number is correct and then pull out the socket we care about if
craigdo@3831
   435
              // it matches
craigdo@3831
   436
              //
craigdo@3831
   437
              if (magic == EMU_MAGIC)
craigdo@3831
   438
                {
craigdo@3831
   439
                  NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
craigdo@3831
   440
                  int *rawSocket = (int*)CMSG_DATA (cmsg);
craigdo@3831
   441
                  NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
craigdo@3831
   442
                  m_sock = *rawSocket;
craigdo@3831
   443
                  return;
craigdo@3831
   444
                }
craigdo@3831
   445
              else
craigdo@3831
   446
                {
craigdo@3831
   447
                  NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);                  
craigdo@3831
   448
                }
craigdo@3830
   449
	    }
craigdo@3830
   450
	}
craigdo@3830
   451
      NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
craigdo@3830
   452
    }
craigdo@3830
   453
}
craigdo@3830
   454
craigdo@3830
   455
std::string
craigdo@3830
   456
EmuNetDevice::FindCreator (void)
craigdo@3830
   457
{
craigdo@3830
   458
  struct stat st;
craigdo@3830
   459
  std::string debug = "./build/debug/src/devices/emu/emu-sock-creator";
craigdo@3830
   460
  std::string optimized = "./build/optimized/src/devices/emu/emu-sock-creator";
craigdo@3830
   461
craigdo@3830
   462
  if (::stat (debug.c_str (), &st) == 0)
craigdo@3830
   463
    {
craigdo@3830
   464
      return debug;
craigdo@3830
   465
    }
craigdo@3830
   466
craigdo@3830
   467
  if (::stat (optimized.c_str (), &st) == 0)
craigdo@3830
   468
    {
craigdo@3830
   469
      return optimized;
craigdo@3830
   470
    }
craigdo@3830
   471
craigdo@3830
   472
  NS_FATAL_ERROR ("EmuNetDevice::FindCreator(): Couldn't find creator");
craigdo@3830
   473
  return ""; // quiet compiler
craigdo@3830
   474
}
craigdo@3830
   475
craigdo@3830
   476
void
craigdo@3830
   477
EmuNetDevice::StopDevice (void)
craigdo@3827
   478
{
craigdo@3827
   479
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   480
craigdo@3827
   481
  close (m_sock);
craigdo@3827
   482
  m_sock = -1;
craigdo@3827
   483
craigdo@3830
   484
  NS_ASSERT_MSG (m_readThread != 0, "EmuNetDevice::StopDevice(): Receive thread is not running");
craigdo@3827
   485
craigdo@3827
   486
  NS_LOG_LOGIC ("Joining read thread");
craigdo@3827
   487
  m_readThread->Join ();
craigdo@3827
   488
  m_readThread = 0;
craigdo@3827
   489
}
craigdo@3827
   490
craigdo@3827
   491
void
craigdo@3830
   492
EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
craigdo@3827
   493
{
craigdo@3827
   494
  NS_LOG_FUNCTION (buf << len);
craigdo@3827
   495
craigdo@3827
   496
  //
craigdo@3827
   497
  // Create a packet out of the buffer we received and free that buffer.
craigdo@3827
   498
  //
craigdo@3827
   499
  Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
craigdo@3827
   500
  free (buf);
craigdo@3827
   501
  buf = 0;
craigdo@3827
   502
craigdo@3827
   503
  //
craigdo@3827
   504
  // Trace sinks will expect complete packets, not packets without some of the
craigdo@3827
   505
  // headers.
craigdo@3827
   506
  //
craigdo@3827
   507
  Ptr<Packet> originalPacket = packet->Copy ();
craigdo@3827
   508
craigdo@3827
   509
  //
craigdo@3827
   510
  // Checksum the packet
craigdo@3827
   511
  //
craigdo@3827
   512
  EthernetTrailer trailer;
craigdo@3827
   513
  packet->RemoveTrailer (trailer);
craigdo@3827
   514
  trailer.CheckFcs (packet);
craigdo@3827
   515
craigdo@3827
   516
  EthernetHeader header (false);
craigdo@3827
   517
  packet->RemoveHeader (header);
craigdo@3827
   518
craigdo@3827
   519
  NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
craigdo@3827
   520
  NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
craigdo@3827
   521
craigdo@3827
   522
  LlcSnapHeader llc;
craigdo@3827
   523
  packet->RemoveHeader (llc);
craigdo@3827
   524
  uint16_t protocol = llc.GetType ();
craigdo@3827
   525
craigdo@3827
   526
  PacketType packetType;
craigdo@3827
   527
      
vincent@3842
   528
  if (header.GetDestination ().IsBroadcast ())
craigdo@3827
   529
    {
craigdo@3827
   530
      NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
craigdo@3827
   531
      packetType = NS3_PACKET_BROADCAST;
craigdo@3827
   532
    }
vincent@3842
   533
  else if (header.GetDestination ().IsMulticast ())
craigdo@3827
   534
    {
craigdo@3827
   535
      NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
craigdo@3827
   536
      packetType = NS3_PACKET_MULTICAST;
craigdo@3827
   537
    }
vincent@3842
   538
  else if (header.GetDestination () == m_address)
craigdo@3827
   539
    {
craigdo@3827
   540
      NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
craigdo@3827
   541
      packetType = NS3_PACKET_HOST;
craigdo@3827
   542
    }
craigdo@3827
   543
  else
craigdo@3827
   544
    {
craigdo@3827
   545
      NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
craigdo@3827
   546
      packetType = NS3_PACKET_OTHERHOST;
craigdo@3827
   547
    }
craigdo@3827
   548
craigdo@3827
   549
  if (!m_promiscRxCallback.IsNull ())
craigdo@3827
   550
    {
craigdo@3827
   551
      NS_LOG_LOGIC ("calling m_promiscRxCallback");
craigdo@3827
   552
      m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
craigdo@3827
   553
    }
craigdo@3827
   554
craigdo@3827
   555
  if (packetType != NS3_PACKET_OTHERHOST)
craigdo@3827
   556
    {
craigdo@3827
   557
      m_rxTrace (originalPacket);
craigdo@3827
   558
      NS_LOG_LOGIC ("calling m_rxCallback");
craigdo@3827
   559
      m_rxCallback (this, packet, protocol, header.GetSource ());
craigdo@3827
   560
    }
craigdo@3827
   561
}
craigdo@3827
   562
craigdo@3827
   563
void
craigdo@3830
   564
EmuNetDevice::ReadThread (void)
craigdo@3827
   565
{
craigdo@3827
   566
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   567
craigdo@3827
   568
  //
craigdo@3827
   569
  // It's important to remember that we're in a completely different thread than the simulator is running in.  We
craigdo@3827
   570
  // need to synchronize with that other thread to get the packet up into ns-3.  What we will need to do is to schedule 
craigdo@3827
   571
  // a method to forward up the packet using the multithreaded simulator we are most certainly running.  However, I just 
craigdo@3827
   572
  // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
craigdo@3827
   573
  // on a shared object.  Just don't do it.  So what we're going to do is to allocate a buffer on the heap and pass that
craigdo@3827
   574
  // buffer into the ns-3 context thread where it will create the packet.
craigdo@3827
   575
  //
craigdo@3827
   576
craigdo@3827
   577
  int32_t len = -1;
craigdo@3827
   578
  struct sockaddr_ll addr;
craigdo@3827
   579
  socklen_t addrSize = sizeof (addr);
craigdo@3827
   580
craigdo@3827
   581
  for (;;) 
craigdo@3827
   582
    {
craigdo@3827
   583
      uint32_t bufferSize = 65536;
craigdo@3827
   584
      uint8_t *buf = (uint8_t *)malloc (bufferSize);
craigdo@3847
   585
      if (buf == 0)
craigdo@3847
   586
        {
craigdo@3847
   587
          NS_FATAL_ERROR ("EmuNetDevice::ReadThread(): malloc packet buffer failed");
craigdo@3847
   588
        }
craigdo@3847
   589
craigdo@3827
   590
      NS_LOG_LOGIC ("Calling recvfrom");
craigdo@3827
   591
      len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
craigdo@3827
   592
craigdo@3827
   593
      if (len == -1)
craigdo@3827
   594
        {
craigdo@3827
   595
          free (buf);
craigdo@3827
   596
          buf = 0;
craigdo@3827
   597
          return;
craigdo@3827
   598
        }
craigdo@3827
   599
craigdo@3830
   600
      NS_LOG_INFO ("EmuNetDevice::ReadThread(): Received packet");
craigdo@3830
   601
      NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
craigdo@3827
   602
      DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
craigdo@3830
   603
        MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
craigdo@3827
   604
      buf = 0;
craigdo@3827
   605
    }
craigdo@3827
   606
}
craigdo@3827
   607
craigdo@3827
   608
bool 
craigdo@3830
   609
EmuNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
craigdo@3827
   610
{
craigdo@3827
   611
  NS_LOG_FUNCTION (packet << dest << protocolNumber);
craigdo@3827
   612
  //
craigdo@3827
   613
  // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and 
craigdo@3827
   614
  // destination (hardware) addresses?
craigdo@3827
   615
  //
craigdo@3830
   616
  // If we return false from EmuNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the 
craigdo@3830
   617
  // hardware (Ethernet) destination by default.  If we return true from EmuNetDevice::NeedsArp, then the hardware
craigdo@3827
   618
  // destination is actually meaningful, but we'll have an ns-3 ARP running on this device.  There can also be an ARP
craigdo@3827
   619
  // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
craigdo@3827
   620
  //
craigdo@3827
   621
  // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the 
craigdo@3827
   622
  // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses.  We don't actually have
craigdo@3827
   623
  // to use the real hardware addresses and IP addresses of the underlying system.  We can completely use MAC-spoofing to
craigdo@3827
   624
  // 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
   625
  // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
craigdo@3827
   626
  // administered address, so there shouldn't be any collisions with real hardware.
craigdo@3827
   627
  //
craigdo@3830
   628
  // 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
   629
  // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
craigdo@3827
   630
  //
craigdo@3827
   631
  return SendFrom (packet, m_address, dest, protocolNumber);
craigdo@3827
   632
}
craigdo@3827
   633
craigdo@3827
   634
bool 
craigdo@3830
   635
EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
craigdo@3827
   636
{
craigdo@3827
   637
  NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
craigdo@3827
   638
craigdo@3827
   639
  if (IsLinkUp () == false)
craigdo@3827
   640
    {
craigdo@3827
   641
      NS_LOG_LOGIC ("Link is down, returning");
craigdo@3827
   642
      return false;
craigdo@3827
   643
    }
craigdo@3827
   644
craigdo@3827
   645
  Mac48Address destination = Mac48Address::ConvertFrom (dest);
craigdo@3827
   646
  Mac48Address source = Mac48Address::ConvertFrom (src);
craigdo@3827
   647
craigdo@3827
   648
  NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
craigdo@3827
   649
  NS_LOG_LOGIC ("Transmit packet from " << source);
craigdo@3827
   650
  NS_LOG_LOGIC ("Transmit packet to " << destination);
craigdo@3827
   651
craigdo@3827
   652
#if 0
craigdo@3827
   653
  {
craigdo@3827
   654
    struct ifreq ifr;
craigdo@3827
   655
    bzero (&ifr, sizeof(ifr));
craigdo@3827
   656
    strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
craigdo@3827
   657
craigdo@3827
   658
    NS_LOG_LOGIC ("Getting MAC address");
craigdo@3827
   659
    int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
craigdo@3847
   660
    if (rc == -1)
craigdo@3847
   661
      {
craigdo@3847
   662
        NS_FATAL_ERROR ("EmuNetDevice::SendFrom(): Can't get MAC address");
craigdo@3847
   663
      }
craigdo@3827
   664
craigdo@3827
   665
    std::ostringstream oss;
craigdo@3827
   666
    oss << std::hex <<
craigdo@3827
   667
      (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
craigdo@3827
   668
      (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
craigdo@3827
   669
      (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
craigdo@3827
   670
      (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
craigdo@3827
   671
      (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
craigdo@3827
   672
      (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
craigdo@3827
   673
craigdo@3827
   674
    NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
craigdo@3827
   675
    source = Mac48Address (oss.str ().c_str ());
craigdo@3827
   676
    NS_LOG_LOGIC ("source now " << source);
craigdo@3827
   677
  }
craigdo@3827
   678
#endif
craigdo@3827
   679
craigdo@3827
   680
  LlcSnapHeader llc;
craigdo@3827
   681
  llc.SetType (protocolNumber);
craigdo@3827
   682
  packet->AddHeader (llc);
craigdo@3827
   683
craigdo@3827
   684
  EthernetHeader header (false);
craigdo@3827
   685
  header.SetSource (source);
craigdo@3827
   686
  header.SetDestination (destination);
craigdo@3827
   687
  header.SetLengthType (packet->GetSize ());
craigdo@3827
   688
  packet->AddHeader (header);
craigdo@3827
   689
craigdo@3827
   690
  EthernetTrailer trailer;
craigdo@3827
   691
  trailer.CalcFcs (packet);
craigdo@3827
   692
  packet->AddTrailer (trailer);
craigdo@3827
   693
craigdo@3827
   694
  // 
craigdo@3827
   695
  // Enqueue and dequeue the packet to hit the tracing hooks.
craigdo@3827
   696
  //
craigdo@3827
   697
  m_queue->Enqueue (packet);
craigdo@3827
   698
  packet = m_queue->Dequeue ();
craigdo@3827
   699
craigdo@3827
   700
  struct sockaddr_ll ll;
craigdo@3827
   701
  bzero (&ll, sizeof (ll));
craigdo@3827
   702
craigdo@3827
   703
  ll.sll_family = AF_PACKET;
craigdo@3827
   704
  ll.sll_ifindex = m_sll_ifindex;
craigdo@3827
   705
  ll.sll_protocol = htons(ETH_P_ALL); 
craigdo@3827
   706
craigdo@3827
   707
  NS_LOG_LOGIC ("calling sendto");
craigdo@3827
   708
craigdo@3827
   709
  int32_t rc;
craigdo@3827
   710
  rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
craigdo@3827
   711
craigdo@3827
   712
  NS_LOG_LOGIC ("sendto returns " << rc);
craigdo@3827
   713
craigdo@3827
   714
  return rc == -1 ? false : true;
craigdo@3827
   715
}
craigdo@3827
   716
craigdo@3827
   717
void 
craigdo@3830
   718
EmuNetDevice::SetDataRate(DataRate bps)
craigdo@3827
   719
{
craigdo@3827
   720
  NS_LOG_FUNCTION (this << bps);
craigdo@3847
   721
  NS_FATAL_ERROR ("EmuNetDevice::SetDataRate():  Unable."); 
craigdo@3827
   722
}
craigdo@3827
   723
craigdo@3827
   724
void
craigdo@3830
   725
EmuNetDevice::SetQueue (Ptr<Queue> q)
craigdo@3827
   726
{
craigdo@3827
   727
  NS_LOG_FUNCTION (this << q);
craigdo@3827
   728
  m_queue = q;
craigdo@3827
   729
}
craigdo@3827
   730
craigdo@3827
   731
Ptr<Queue> 
craigdo@3830
   732
EmuNetDevice::GetQueue(void) const 
craigdo@3827
   733
{ 
craigdo@3827
   734
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   735
  return m_queue;
craigdo@3827
   736
}
craigdo@3827
   737
craigdo@3827
   738
void
craigdo@3830
   739
EmuNetDevice::NotifyLinkUp (void)
craigdo@3827
   740
{
craigdo@3827
   741
  m_linkUp = true;
craigdo@3827
   742
  if (!m_linkChangeCallback.IsNull ())
craigdo@3827
   743
    {
craigdo@3827
   744
      m_linkChangeCallback ();
craigdo@3827
   745
    }
craigdo@3827
   746
}
craigdo@3827
   747
craigdo@3827
   748
void 
craigdo@3830
   749
EmuNetDevice::SetName(const std::string name)
craigdo@3827
   750
{
craigdo@3827
   751
  m_name = name;
craigdo@3827
   752
}
craigdo@3827
   753
craigdo@3827
   754
std::string 
craigdo@3830
   755
EmuNetDevice::GetName(void) const
craigdo@3827
   756
{
craigdo@3827
   757
  return m_name;
craigdo@3827
   758
}
craigdo@3827
   759
craigdo@3827
   760
void 
craigdo@3830
   761
EmuNetDevice::SetIfIndex(const uint32_t index)
craigdo@3827
   762
{
craigdo@3827
   763
  m_ifIndex = index;
craigdo@3827
   764
}
craigdo@3827
   765
craigdo@3827
   766
uint32_t 
craigdo@3830
   767
EmuNetDevice::GetIfIndex(void) const
craigdo@3827
   768
{
craigdo@3827
   769
  return m_ifIndex;
craigdo@3827
   770
}
craigdo@3827
   771
craigdo@3827
   772
Ptr<Channel> 
craigdo@3830
   773
EmuNetDevice::GetChannel (void) const
craigdo@3827
   774
{
craigdo@3847
   775
  NS_FATAL_ERROR ("EmuNetDevice::GetChannel():  Unable."); 
craigdo@3827
   776
  return 0;
craigdo@3827
   777
}
craigdo@3827
   778
craigdo@3827
   779
void 
craigdo@3830
   780
EmuNetDevice::SetAddress (Mac48Address addr)
craigdo@3827
   781
{
craigdo@3827
   782
  NS_LOG_FUNCTION (addr);
craigdo@3827
   783
  m_address = addr;
craigdo@3827
   784
}
craigdo@3827
   785
craigdo@3827
   786
Address 
craigdo@3830
   787
EmuNetDevice::GetAddress (void) const
craigdo@3827
   788
{
craigdo@3827
   789
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   790
  return m_address;
craigdo@3827
   791
}
craigdo@3827
   792
craigdo@3827
   793
bool 
craigdo@3830
   794
EmuNetDevice::SetMtu (const uint16_t mtu)
craigdo@3827
   795
{
craigdo@3847
   796
  NS_FATAL_ERROR ("EmuNetDevice::SetMtu():  Unable."); 
craigdo@3827
   797
  return false;
craigdo@3827
   798
}
craigdo@3827
   799
craigdo@3827
   800
uint16_t 
craigdo@3830
   801
EmuNetDevice::GetMtu (void) const
craigdo@3827
   802
{
craigdo@3827
   803
  struct ifreq ifr;
craigdo@3827
   804
  bzero (&ifr, sizeof (ifr));
craigdo@3827
   805
  strcpy(ifr.ifr_name, m_deviceName.c_str ());
craigdo@3827
   806
craigdo@3827
   807
  int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
craigdo@3827
   808
craigdo@3847
   809
craigdo@3827
   810
  int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
craigdo@3847
   811
  if (rc == -1)
craigdo@3847
   812
    {
craigdo@3847
   813
      NS_FATAL_ERROR ("EmuNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
craigdo@3847
   814
    }
craigdo@3827
   815
craigdo@3827
   816
  close (fd);
craigdo@3827
   817
craigdo@3827
   818
  return ifr.ifr_mtu;
craigdo@3827
   819
}
craigdo@3827
   820
craigdo@3827
   821
bool 
craigdo@3830
   822
EmuNetDevice::IsLinkUp (void) const
craigdo@3827
   823
{
craigdo@3827
   824
  return m_linkUp;
craigdo@3827
   825
}
craigdo@3827
   826
craigdo@3827
   827
void 
craigdo@3830
   828
EmuNetDevice::SetLinkChangeCallback (Callback<void> callback)
craigdo@3827
   829
{
craigdo@3827
   830
  m_linkChangeCallback = callback;
craigdo@3827
   831
}
craigdo@3827
   832
craigdo@3827
   833
bool 
craigdo@3830
   834
EmuNetDevice::IsBroadcast (void) const
craigdo@3827
   835
{
craigdo@3827
   836
  return true;
craigdo@3827
   837
}
craigdo@3827
   838
craigdo@3827
   839
Address
craigdo@3830
   840
EmuNetDevice::GetBroadcast (void) const
craigdo@3827
   841
{
craigdo@3827
   842
  return Mac48Address ("ff:ff:ff:ff:ff:ff");
craigdo@3827
   843
}
craigdo@3827
   844
craigdo@3827
   845
bool 
craigdo@3830
   846
EmuNetDevice::IsMulticast (void) const
craigdo@3827
   847
{
craigdo@3827
   848
  return false;
craigdo@3827
   849
}
craigdo@3827
   850
vincent@3842
   851
  Address 
vincent@3842
   852
EmuNetDevice::GetMulticast (Ipv4Address multicastGroup) const
craigdo@3827
   853
{
craigdo@3836
   854
  NS_LOG_FUNCTION (multicastGroup);
craigdo@3836
   855
vincent@3842
   856
  Mac48Address ad = Mac48Address::GetMulticast (multicastGroup);
craigdo@3836
   857
craigdo@3836
   858
  //
craigdo@3836
   859
  // Implicit conversion (operator Address ()) is defined for Mac48Address, so
craigdo@3836
   860
  // use it by just returning the EUI-48 address which is automagically converted
craigdo@3836
   861
  // to an Address.
craigdo@3836
   862
  //
vincent@3842
   863
  NS_LOG_LOGIC ("multicast address is " << ad);
vincent@3842
   864
vincent@3842
   865
  return ad;
craigdo@3827
   866
}
craigdo@3827
   867
vincent@3852
   868
Address
vincent@3852
   869
EmuNetDevice::GetMulticast (Ipv6Address addr) const
vincent@3852
   870
{
vincent@3852
   871
  NS_LOG_FUNCTION(this << addr);
vincent@3852
   872
vincent@3852
   873
  Mac48Address ad = Mac48Address::GetMulticast (addr);
vincent@3852
   874
  NS_LOG_LOGIC("MAC IPv6 multicast address is " << ad);
vincent@3852
   875
vincent@3852
   876
  return ad;
vincent@3852
   877
}
vincent@3852
   878
craigdo@3827
   879
bool 
craigdo@3830
   880
EmuNetDevice::IsPointToPoint (void) const
craigdo@3827
   881
{
craigdo@3827
   882
  return false;
craigdo@3827
   883
}
craigdo@3827
   884
craigdo@3827
   885
void
craigdo@3830
   886
EmuNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
craigdo@3827
   887
{
craigdo@3847
   888
  NS_FATAL_ERROR ("EmuNetDevice::SetPromiscReceiveCallback(): Not implemented");
craigdo@3827
   889
}
craigdo@3827
   890
craigdo@3827
   891
  bool 
craigdo@3830
   892
EmuNetDevice::SupportsSendFrom () const
craigdo@3827
   893
{
craigdo@3827
   894
  NS_LOG_FUNCTION_NOARGS ();
craigdo@3827
   895
  return true;
craigdo@3827
   896
}
craigdo@3827
   897
craigdo@3827
   898
craigdo@3827
   899
Ptr<Node> 
craigdo@3830
   900
EmuNetDevice::GetNode (void) const
craigdo@3827
   901
{
craigdo@3827
   902
  return m_node;
craigdo@3827
   903
}
craigdo@3827
   904
craigdo@3827
   905
void 
craigdo@3830
   906
EmuNetDevice::SetNode (Ptr<Node> node)
craigdo@3827
   907
{
craigdo@3827
   908
  m_node = node;
craigdo@3827
   909
}
craigdo@3827
   910
craigdo@3827
   911
bool 
craigdo@3830
   912
EmuNetDevice::NeedsArp (void) const
craigdo@3827
   913
{
craigdo@3827
   914
  return true;
craigdo@3827
   915
}
craigdo@3827
   916
craigdo@3827
   917
void 
craigdo@3830
   918
EmuNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
craigdo@3827
   919
{
craigdo@3827
   920
  m_rxCallback = cb;
craigdo@3827
   921
}
craigdo@3827
   922
craigdo@3827
   923
} // namespace ns3