src/node/packet-socket.cc
author Duy Nguyen <dnlove@gmail.com>
Thu Aug 06 21:58:04 2009 -0700 (2009-08-06)
changeset 4698 60cd412fa3dd
parent 4502 07d34c0d8d18
child 6197 ebe303de4725
permissions -rw-r--r--
fix for bug 650 (PacketSocket Close()
mathieu@1188
     1
/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
mathieu@1188
     2
/*
mathieu@1188
     3
 * Copyright (c) 2007 Emmanuelle Laprise, INRIA
mathieu@1188
     4
 *
mathieu@1188
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@1188
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@1188
     7
 * published by the Free Software Foundation;
mathieu@1188
     8
 *
mathieu@1188
     9
 * This program is distributed in the hope that it will be useful,
mathieu@1188
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@1188
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@1188
    12
 * GNU General Public License for more details.
mathieu@1188
    13
 *
mathieu@1188
    14
 * You should have received a copy of the GNU General Public License
mathieu@1188
    15
 * along with this program; if not, write to the Free Software
mathieu@1188
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@1188
    17
 *
mathieu@1188
    18
 * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
mathieu@1188
    19
 *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@1188
    20
 */
mathieu@1188
    21
mathieu@1188
    22
#include "packet-socket.h"
mathieu@1188
    23
#include "packet-socket-address.h"
craigdo@1505
    24
#include "ns3/log.h"
mathieu@1188
    25
#include "ns3/node.h"
mathieu@1866
    26
#include "ns3/packet.h"
tomh@3117
    27
#include "ns3/uinteger.h"
tomh@3112
    28
#include "ns3/trace-source-accessor.h"
mathieu@1188
    29
mathieu@3219
    30
#include <algorithm>
mathieu@3219
    31
craigdo@1505
    32
NS_LOG_COMPONENT_DEFINE ("PacketSocket");
mathieu@1188
    33
mathieu@1188
    34
namespace ns3 {
mathieu@1188
    35
tomh@3112
    36
TypeId
tomh@3112
    37
PacketSocket::GetTypeId (void)
tomh@3112
    38
{
tomh@3112
    39
  static TypeId tid = TypeId ("ns3::PacketSocket")
tomh@3112
    40
    .SetParent<Socket> ()
tomh@3112
    41
    .AddConstructor<PacketSocket> ()
tomh@3112
    42
    .AddTraceSource ("Drop", "Drop packet due to receive buffer overflow",
tomh@3112
    43
                     MakeTraceSourceAccessor (&PacketSocket::m_dropTrace))
tomh@3123
    44
    .AddAttribute ("RcvBufSize",
tomh@3123
    45
                   "PacketSocket maximum receive buffer size (bytes)",
tomh@3123
    46
                   UintegerValue (0xffffffffl),
tomh@3123
    47
                   MakeUintegerAccessor (&PacketSocket::m_rcvBufSize),
tomh@3123
    48
                   MakeUintegerChecker<uint32_t> ())
tomh@3112
    49
    ;
tomh@3112
    50
  return tid;
tomh@3112
    51
}
tomh@3112
    52
tomh@3104
    53
PacketSocket::PacketSocket () : m_rxAvailable (0)
mathieu@1188
    54
{
mathieu@4502
    55
  NS_LOG_FUNCTION (this);
mathieu@1188
    56
  m_state = STATE_OPEN;
mathieu@1188
    57
  m_shutdownSend = false;
mathieu@1188
    58
  m_shutdownRecv = false;
mathieu@1188
    59
  m_errno = ERROR_NOTERROR;
craigdo@3778
    60
  m_isSingleDevice = false;
craigdo@3778
    61
  m_device = 0;
mathieu@1188
    62
}
mathieu@1188
    63
mathieu@2592
    64
void 
mathieu@2592
    65
PacketSocket::SetNode (Ptr<Node> node)
mathieu@2592
    66
{
mathieu@4502
    67
  NS_LOG_FUNCTION (this << node);
mathieu@2592
    68
  m_node = node;
mathieu@2592
    69
}
mathieu@2592
    70
mathieu@1188
    71
PacketSocket::~PacketSocket ()
craigdo@1505
    72
{
mathieu@4502
    73
  NS_LOG_FUNCTION (this);
craigdo@1505
    74
}
mathieu@1188
    75
mathieu@1188
    76
void 
mathieu@1188
    77
PacketSocket::DoDispose (void)
mathieu@1188
    78
{
mathieu@4502
    79
  NS_LOG_FUNCTION (this);
mathieu@1188
    80
  m_device = 0;
mathieu@1188
    81
}
mathieu@1188
    82
mathieu@1264
    83
enum Socket::SocketErrno
mathieu@1264
    84
PacketSocket::GetErrno (void) const
mathieu@1264
    85
{
mathieu@4502
    86
  NS_LOG_FUNCTION (this);
mathieu@1264
    87
  return m_errno;
mathieu@1264
    88
}
mathieu@1264
    89
mathieu@1188
    90
Ptr<Node>
mathieu@1188
    91
PacketSocket::GetNode (void) const
mathieu@1188
    92
{
mathieu@4502
    93
  NS_LOG_FUNCTION (this);
mathieu@1188
    94
  return m_node;
mathieu@1188
    95
}
mathieu@1188
    96
mathieu@1188
    97
int
mathieu@1188
    98
PacketSocket::Bind (void)
mathieu@1188
    99
{
mathieu@4502
   100
  NS_LOG_FUNCTION (this);
mathieu@1188
   101
  PacketSocketAddress address;
mathieu@1188
   102
  address.SetProtocol (0);
mathieu@1195
   103
  address.SetAllDevices ();
mathieu@1188
   104
  return DoBind (address);
mathieu@1188
   105
}
craigdo@1505
   106
mathieu@1188
   107
int
mathieu@1188
   108
PacketSocket::Bind (const Address &address)
craigdo@1505
   109
{ 
mathieu@4502
   110
  NS_LOG_FUNCTION (this << address);
mathieu@1188
   111
  if (!PacketSocketAddress::IsMatchingType (address))
mathieu@1188
   112
    {
mathieu@1188
   113
      m_errno = ERROR_INVAL;
mathieu@1188
   114
      return -1;
mathieu@1188
   115
    }
mathieu@1188
   116
  PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
mathieu@1188
   117
  return DoBind (ad);
mathieu@1188
   118
}
mathieu@1188
   119
mathieu@1188
   120
int
mathieu@1188
   121
PacketSocket::DoBind (const PacketSocketAddress &address)
mathieu@1188
   122
{
mathieu@4502
   123
  NS_LOG_FUNCTION (this << address);
mathieu@1188
   124
  if (m_state == STATE_BOUND ||
mathieu@1188
   125
      m_state == STATE_CONNECTED)
mathieu@1188
   126
    {
mathieu@1188
   127
      m_errno = ERROR_INVAL;
mathieu@1188
   128
      return -1;
mathieu@1188
   129
    }
mathieu@1188
   130
  if (m_state == STATE_CLOSED)
mathieu@1188
   131
    {
mathieu@1188
   132
      m_errno = ERROR_BADF;
mathieu@1188
   133
      return -1;
mathieu@1188
   134
    }
mathieu@1195
   135
  Ptr<NetDevice> dev ;
mathieu@1195
   136
  if (address.IsSingleDevice ())
mathieu@1195
   137
    {
gjc@3018
   138
      dev = m_node->GetDevice (address.GetSingleDevice ());
mathieu@1195
   139
    }
mathieu@1195
   140
  else
mathieu@1195
   141
    {
gjc@3018
   142
      dev = 0;
mathieu@1195
   143
    }
mathieu@1188
   144
  m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
mathieu@1188
   145
                                   address.GetProtocol (), dev);
mathieu@1188
   146
  m_state = STATE_BOUND;
mathieu@1188
   147
  m_protocol = address.GetProtocol ();
mathieu@1195
   148
  m_isSingleDevice = address.IsSingleDevice ();
mathieu@1195
   149
  m_device = address.GetSingleDevice ();
mathieu@1188
   150
  return 0;
mathieu@1188
   151
}
mathieu@1188
   152
mathieu@1188
   153
int
mathieu@1188
   154
PacketSocket::ShutdownSend (void)
mathieu@1188
   155
{
mathieu@4502
   156
  NS_LOG_FUNCTION (this);
mathieu@1188
   157
  if (m_state == STATE_CLOSED)
mathieu@1188
   158
    {
mathieu@1188
   159
      m_errno = ERROR_BADF;
mathieu@1188
   160
      return -1;
mathieu@1188
   161
    }
mathieu@1188
   162
  m_shutdownSend = true;
mathieu@1188
   163
  return 0;
mathieu@1188
   164
}
craigdo@1505
   165
mathieu@1188
   166
int
mathieu@1188
   167
PacketSocket::ShutdownRecv (void)
mathieu@1188
   168
{
mathieu@4502
   169
  NS_LOG_FUNCTION (this);
mathieu@1188
   170
  if (m_state == STATE_CLOSED)
mathieu@1188
   171
    {
mathieu@1188
   172
      m_errno = ERROR_BADF;
mathieu@1188
   173
      return -1;
mathieu@1188
   174
    }
dnlove@4698
   175
  m_shutdownRecv = true;
mathieu@1188
   176
  return 0;
mathieu@1188
   177
}
craigdo@1505
   178
mathieu@1188
   179
int
mathieu@1264
   180
PacketSocket::Close(void)
mathieu@1188
   181
{
mathieu@4502
   182
  NS_LOG_FUNCTION (this);
mathieu@1188
   183
  if (m_state == STATE_CLOSED)
mathieu@1188
   184
    {
mathieu@1188
   185
      m_errno = ERROR_BADF;
mathieu@1188
   186
      return -1;
mathieu@1188
   187
    }
mathieu@1188
   188
  m_state = STATE_CLOSED;
dnlove@4698
   189
  m_shutdownSend = true;
dnlove@4698
   190
  m_shutdownRecv = true;
mathieu@1188
   191
  return 0;
mathieu@1188
   192
}
mathieu@1188
   193
mathieu@1188
   194
int
mathieu@1264
   195
PacketSocket::Connect(const Address &ad)
mathieu@1188
   196
{
mathieu@4502
   197
  NS_LOG_FUNCTION (this << ad);
mathieu@1188
   198
  PacketSocketAddress address;
mathieu@1188
   199
  if (m_state == STATE_CLOSED)
mathieu@1188
   200
    {
mathieu@1188
   201
      m_errno = ERROR_BADF;
mathieu@1188
   202
      goto error;
mathieu@1188
   203
    }
mathieu@1188
   204
  if (m_state == STATE_OPEN)
mathieu@1188
   205
    {
mathieu@1188
   206
      // connect should happen _after_ bind.
mathieu@1188
   207
      m_errno = ERROR_INVAL; // generic error condition.
mathieu@1188
   208
      goto error;
mathieu@1188
   209
    }
mathieu@1188
   210
  if (m_state == STATE_CONNECTED)
mathieu@1188
   211
    {
mathieu@1188
   212
      m_errno = ERROR_ISCONN;
mathieu@1188
   213
      goto error;
mathieu@1188
   214
    }
mathieu@1188
   215
  if (!PacketSocketAddress::IsMatchingType (ad))
mathieu@1188
   216
    {
mathieu@1188
   217
      m_errno = ERROR_AFNOSUPPORT;
mathieu@1188
   218
      goto error;
mathieu@1188
   219
    }
mathieu@1188
   220
  m_destAddr = ad;
mathieu@1188
   221
  m_state = STATE_CONNECTED;
mathieu@1264
   222
  NotifyConnectionSucceeded ();
mathieu@1188
   223
  return 0;
mathieu@1188
   224
 error:
mathieu@1264
   225
  NotifyConnectionFailed ();
mathieu@1188
   226
  return -1;
mathieu@1188
   227
}
mathieu@3213
   228
int 
craigdo@3772
   229
PacketSocket::Listen(void)
mathieu@3213
   230
{
mathieu@3213
   231
  m_errno = Socket::ERROR_OPNOTSUPP;
mathieu@3213
   232
  return -1;
mathieu@3213
   233
}
mathieu@1188
   234
mathieu@1188
   235
int
tomh@3269
   236
PacketSocket::Send (Ptr<Packet> p, uint32_t flags)
mathieu@1188
   237
{
mathieu@4502
   238
  NS_LOG_FUNCTION (this << p << flags);
mathieu@1188
   239
  if (m_state == STATE_OPEN ||
mathieu@1188
   240
      m_state == STATE_BOUND)
mathieu@1188
   241
    {
mathieu@1188
   242
      m_errno = ERROR_NOTCONN;
mathieu@1188
   243
      return -1;
mathieu@1188
   244
    }
tomh@3269
   245
  return SendTo (p, flags, m_destAddr);
mathieu@2983
   246
}
mathieu@2983
   247
mathieu@3219
   248
uint32_t
mathieu@3219
   249
PacketSocket::GetMinMtu (PacketSocketAddress ad) const
mathieu@3219
   250
{
mathieu@3219
   251
  if (ad.IsSingleDevice ())
mathieu@3219
   252
    {
mathieu@3219
   253
      Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
mathieu@3219
   254
      return device->GetMtu ();
mathieu@3219
   255
    }
mathieu@3219
   256
  else
mathieu@3219
   257
    {
mathieu@3219
   258
      uint32_t minMtu = 0xffff;
mathieu@3219
   259
      for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
mathieu@3219
   260
        {
mathieu@3219
   261
          Ptr<NetDevice> device = m_node->GetDevice (i);
mathieu@3219
   262
          minMtu = std::min (minMtu, (uint32_t)device->GetMtu ());
mathieu@3219
   263
        }
mathieu@3219
   264
      return minMtu;
mathieu@3219
   265
    }
mathieu@3219
   266
}
mathieu@3219
   267
tomh@3105
   268
uint32_t 
tomh@3105
   269
PacketSocket::GetTxAvailable (void) const
tomh@3105
   270
{
mathieu@3219
   271
  if (m_state == STATE_CONNECTED)
mathieu@3219
   272
    {
mathieu@3219
   273
      PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (m_destAddr);      
mathieu@3219
   274
      return GetMinMtu (ad);
mathieu@3219
   275
    }
mathieu@3219
   276
  // If we are not connected, we return a 'safe' value by default.
tomh@3122
   277
  return 0xffff;
mathieu@1188
   278
}
mathieu@1188
   279
mathieu@1188
   280
int
tomh@3269
   281
PacketSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
mathieu@1188
   282
{
mathieu@4502
   283
  NS_LOG_FUNCTION (this << p << flags << address);
mathieu@1188
   284
  PacketSocketAddress ad;
mathieu@1188
   285
  if (m_state == STATE_CLOSED)
mathieu@1188
   286
    {
gjc@1832
   287
      NS_LOG_LOGIC ("ERROR_BADF");
mathieu@1188
   288
      m_errno = ERROR_BADF;
mathieu@1188
   289
      return -1;
mathieu@1188
   290
    }
mathieu@1188
   291
  if (m_shutdownSend)
mathieu@1188
   292
    {
gjc@1832
   293
      NS_LOG_LOGIC ("ERROR_SHUTDOWN");
mathieu@1188
   294
      m_errno = ERROR_SHUTDOWN;
mathieu@1188
   295
      return -1;
mathieu@1188
   296
    }
mathieu@1188
   297
  if (!PacketSocketAddress::IsMatchingType (address))
mathieu@1188
   298
    {
gjc@1832
   299
      NS_LOG_LOGIC ("ERROR_AFNOSUPPORT");
mathieu@1188
   300
      m_errno = ERROR_AFNOSUPPORT;
mathieu@1188
   301
      return -1;
mathieu@1188
   302
    }
mathieu@3219
   303
  ad = PacketSocketAddress::ConvertFrom (address);
mathieu@3219
   304
  if (p->GetSize () > GetMinMtu (ad))
tomh@3122
   305
    {
tomh@3122
   306
      m_errno = ERROR_MSGSIZE;
tomh@3122
   307
      return -1;
tomh@3122
   308
    }
mathieu@1188
   309
  
mathieu@1188
   310
  bool error = false;
mathieu@1188
   311
  Address dest = ad.GetPhysicalAddress ();
mathieu@1195
   312
  if (ad.IsSingleDevice ())
mathieu@1188
   313
    {
mathieu@1195
   314
      Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
mathieu@1195
   315
      if (!device->Send (p, dest, ad.GetProtocol ()))
mathieu@1195
   316
        {
gjc@1832
   317
          NS_LOG_LOGIC ("error: NetDevice::Send error");
mathieu@1195
   318
          error = true;
mathieu@1195
   319
        }
mathieu@1195
   320
    }
mathieu@1195
   321
  else
mathieu@1195
   322
    {
mathieu@1195
   323
      for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
mathieu@1188
   324
        {
mathieu@1188
   325
          Ptr<NetDevice> device = m_node->GetDevice (i);
mathieu@1188
   326
          if (!device->Send (p, dest, ad.GetProtocol ()))
mathieu@1188
   327
            {
gjc@1832
   328
              NS_LOG_LOGIC ("error: NetDevice::Send error");
mathieu@1188
   329
              error = true;
mathieu@1188
   330
            }
mathieu@1188
   331
        }
mathieu@1188
   332
    }
mathieu@1264
   333
  if (!error)
mathieu@1188
   334
    {
mathieu@1866
   335
      NotifyDataSent (p->GetSize ());
craigdo@3776
   336
      NotifySend (GetTxAvailable ());
mathieu@1188
   337
    }
mathieu@1188
   338
mathieu@1188
   339
  if (error)
mathieu@1188
   340
    {
gjc@1832
   341
      NS_LOG_LOGIC ("ERROR_INVAL 2");
mathieu@1188
   342
      m_errno = ERROR_INVAL;
mathieu@1188
   343
      return -1;
mathieu@1188
   344
    }
mathieu@1188
   345
  else
mathieu@1188
   346
    {
mathieu@1188
   347
      return 0;
mathieu@1188
   348
    }
mathieu@1188
   349
}
mathieu@1188
   350
mathieu@1188
   351
void 
mathieu@3548
   352
PacketSocket::ForwardUp (Ptr<NetDevice> device, Ptr<const Packet> packet, 
gjc@3448
   353
                         uint16_t protocol, const Address &from,
gjc@3448
   354
                         const Address &to, NetDevice::PacketType packetType)
mathieu@1188
   355
{
mathieu@4502
   356
  NS_LOG_FUNCTION (this << device << packet << protocol << from << to << packetType);
mathieu@1188
   357
  if (m_shutdownRecv)
mathieu@1188
   358
    {
mathieu@1188
   359
      return;
mathieu@1188
   360
    }
gjc@3448
   361
mathieu@1188
   362
mathieu@1188
   363
  PacketSocketAddress address;
mathieu@1188
   364
  address.SetPhysicalAddress (from);
mathieu@1195
   365
  address.SetSingleDevice (device->GetIfIndex ());
mathieu@1188
   366
  address.SetProtocol (protocol);
mathieu@1188
   367
tomh@3123
   368
  if ((m_rxAvailable + packet->GetSize ()) <= m_rcvBufSize)
tomh@3112
   369
    {
mathieu@4502
   370
      Ptr<Packet> copy = packet->Copy ();
tomh@3269
   371
      SocketAddressTag tag;
tomh@3112
   372
      tag.SetAddress (address);
mathieu@4502
   373
      copy->AddPacketTag (tag);
mathieu@4502
   374
      m_deliveryQueue.push (copy);
tomh@3112
   375
      m_rxAvailable += packet->GetSize ();
tomh@3112
   376
      NS_LOG_LOGIC ("UID is " << packet->GetUid() << " PacketSocket " << this);
tomh@3112
   377
      NotifyDataRecv ();
tomh@3112
   378
    }
tomh@3112
   379
  else
tomh@3112
   380
    {
tomh@3112
   381
      // In general, this case should not occur unless the
tomh@3112
   382
      // receiving application reads data from this socket slowly
tomh@3112
   383
      // in comparison to the arrival rate
tomh@3112
   384
      //
tomh@3112
   385
      // drop and trace packet
tomh@3112
   386
      NS_LOG_WARN ("No receive buffer space available.  Drop.");
tomh@3112
   387
      m_dropTrace (packet);
tomh@3112
   388
    }
mathieu@2983
   389
}
mathieu@2983
   390
tomh@3269
   391
uint32_t
tomh@3269
   392
PacketSocket::GetRxAvailable (void) const
tomh@3269
   393
{
mathieu@4502
   394
  NS_LOG_FUNCTION (this);
tomh@3269
   395
  // We separately maintain this state to avoid walking the queue 
tomh@3269
   396
  // every time this might be called
tomh@3269
   397
  return m_rxAvailable;
tomh@3269
   398
}
tomh@3269
   399
tomh@3097
   400
Ptr<Packet> 
tomh@3097
   401
PacketSocket::Recv (uint32_t maxSize, uint32_t flags)
tomh@3097
   402
{
mathieu@4502
   403
  NS_LOG_FUNCTION (this << maxSize << flags);
tomh@3098
   404
  if (m_deliveryQueue.empty() )
tomh@3098
   405
    {
tomh@3098
   406
      return 0;
tomh@3098
   407
    }
tomh@3097
   408
  Ptr<Packet> p = m_deliveryQueue.front ();
tomh@3104
   409
  if (p->GetSize () <= maxSize)
tomh@3098
   410
    {
tomh@3098
   411
      m_deliveryQueue.pop ();
tomh@3104
   412
      m_rxAvailable -= p->GetSize ();
tomh@3098
   413
    }
tomh@3098
   414
  else
tomh@3098
   415
    {
tomh@3098
   416
      p = 0;
tomh@3098
   417
    }
tomh@3097
   418
  return p;
tomh@3097
   419
}
tomh@3097
   420
tomh@3269
   421
Ptr<Packet>
tomh@3269
   422
PacketSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
tomh@3104
   423
{
mathieu@4502
   424
  NS_LOG_FUNCTION (this << maxSize << flags << fromAddress);
tomh@3269
   425
  Ptr<Packet> packet = Recv (maxSize, flags);
tomh@3269
   426
  if (packet != 0)
tomh@3269
   427
    {
tomh@3269
   428
      SocketAddressTag tag;
tomh@3269
   429
      bool found;
mathieu@4502
   430
      found = packet->PeekPacketTag (tag);
tomh@3269
   431
      NS_ASSERT (found);
tomh@3269
   432
      fromAddress = tag.GetAddress ();
tomh@3269
   433
    }
tomh@3269
   434
  return packet;
tomh@3104
   435
}
tomh@3104
   436
craigdo@3778
   437
int
craigdo@3778
   438
PacketSocket::GetSockName (Address &address) const
craigdo@3778
   439
{
mathieu@4502
   440
  NS_LOG_FUNCTION (this << address);
craigdo@3778
   441
  PacketSocketAddress ad = PacketSocketAddress::ConvertFrom(address);
craigdo@3778
   442
  
craigdo@3778
   443
  ad.SetProtocol (m_protocol);
craigdo@3778
   444
  if (m_isSingleDevice)
craigdo@3778
   445
    {
craigdo@3778
   446
      Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
craigdo@3778
   447
      ad.SetPhysicalAddress(device->GetAddress());      
craigdo@3778
   448
      ad.SetSingleDevice (m_device);
craigdo@3778
   449
    }
craigdo@3778
   450
  else
craigdo@3778
   451
    {
craigdo@3778
   452
      ad.SetPhysicalAddress(Address());   
craigdo@3778
   453
      ad.SetAllDevices ();
craigdo@3778
   454
    }  
craigdo@3778
   455
  address = ad;
craigdo@3778
   456
  
craigdo@3778
   457
  return 0;
craigdo@3778
   458
}
craigdo@3778
   459
mathieu@1188
   460
}//namespace ns3