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