src/node/mac48-address.cc
author vincent@clarinet.u-strasbg.fr
Fri Nov 07 11:36:15 2008 -0800 (2008-11-07)
changeset 3852 9cf7ad0cac85
parent 3549 4eaf02702f17
child 4424 af26433b13bc
permissions -rw-r--r--
Initial IPv6 capability
mathieu@1181
     1
/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
mathieu@1181
     2
/*
mathieu@1181
     3
 * Copyright (c) 2007 INRIA
mathieu@1181
     4
 *
mathieu@1181
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@1181
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@1181
     7
 * published by the Free Software Foundation;
mathieu@1181
     8
 *
mathieu@1181
     9
 * This program is distributed in the hope that it will be useful,
mathieu@1181
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@1181
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@1181
    12
 * GNU General Public License for more details.
mathieu@1181
    13
 *
mathieu@1181
    14
 * You should have received a copy of the GNU General Public License
mathieu@1181
    15
 * along with this program; if not, write to the Free Software
mathieu@1181
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@1181
    17
 *
mathieu@1181
    18
 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@1181
    19
 */
mathieu@1494
    20
#include "mac48-address.h"
mathieu@1158
    21
#include "address.h"
mathieu@1158
    22
#include "ns3/assert.h"
mathieu@1167
    23
#include <iomanip>
mathieu@1170
    24
#include <iostream>
mathieu@3365
    25
#include <string.h>
mathieu@1158
    26
mathieu@1158
    27
namespace ns3 {
mathieu@1158
    28
mathieu@2582
    29
ATTRIBUTE_HELPER_CPP (Mac48Address);
mathieu@2422
    30
mathieu@1158
    31
#define ASCII_a (0x41)
mathieu@1158
    32
#define ASCII_z (0x5a)
mathieu@1158
    33
#define ASCII_A (0x61)
mathieu@1158
    34
#define ASCII_Z (0x7a)
mathieu@1158
    35
#define ASCII_COLON (0x3a)
mathieu@1158
    36
#define ASCII_ZERO (0x30)
mathieu@1158
    37
mathieu@1158
    38
static char
mathieu@1158
    39
AsciiToLowCase (char c)
mathieu@1158
    40
{
mathieu@1158
    41
  if (c >= ASCII_a && c <= ASCII_z) {
mathieu@1158
    42
    return c;
mathieu@1158
    43
  } else if (c >= ASCII_A && c <= ASCII_Z) {
mathieu@1158
    44
    return c + (ASCII_a - ASCII_A);
mathieu@1158
    45
  } else {
mathieu@1158
    46
    return c;
mathieu@1158
    47
  }
mathieu@1158
    48
}
mathieu@1158
    49
mathieu@1158
    50
mathieu@1494
    51
Mac48Address::Mac48Address ()
mathieu@1158
    52
{
mathieu@1158
    53
  memset (m_address, 0, 6);
mathieu@1158
    54
}
mathieu@1494
    55
Mac48Address::Mac48Address (const char *str)
mathieu@1158
    56
{
mathieu@1158
    57
  int i = 0;
mathieu@1158
    58
  while (*str != 0 && i < 6) 
mathieu@1158
    59
    {
mathieu@1158
    60
      uint8_t byte = 0;
mathieu@1158
    61
      while (*str != ASCII_COLON && *str != 0) 
mathieu@1158
    62
	{
mathieu@1158
    63
	  byte <<= 4;
mathieu@1158
    64
	  char low = AsciiToLowCase (*str);
mathieu@1158
    65
	  if (low >= ASCII_a) 
mathieu@1158
    66
	    {
mathieu@1158
    67
	      byte |= low - ASCII_a + 10;
mathieu@1158
    68
	    } 
mathieu@1158
    69
	  else 
mathieu@1158
    70
	    {
mathieu@1158
    71
	      byte |= low - ASCII_ZERO;
mathieu@1158
    72
	    }
mathieu@1158
    73
	  str++;
mathieu@1158
    74
	}
mathieu@1158
    75
      m_address[i] = byte;
mathieu@1158
    76
      i++;
mathieu@1158
    77
      if (*str == 0) 
mathieu@1158
    78
	{
mathieu@1158
    79
	  break;
mathieu@1158
    80
	}
mathieu@1158
    81
      str++;
mathieu@1158
    82
    }
mathieu@1158
    83
  NS_ASSERT (i == 6);
mathieu@1158
    84
}
mathieu@1167
    85
void 
mathieu@1494
    86
Mac48Address::CopyFrom (const uint8_t buffer[6])
mathieu@1167
    87
{
mathieu@1167
    88
  memcpy (m_address, buffer, 6);
mathieu@1167
    89
}
mathieu@1167
    90
void 
mathieu@1494
    91
Mac48Address::CopyTo (uint8_t buffer[6]) const
mathieu@1167
    92
{
mathieu@1167
    93
  memcpy (buffer, m_address, 6);
mathieu@1167
    94
}
mathieu@1167
    95
mathieu@1173
    96
bool 
mathieu@1494
    97
Mac48Address::IsMatchingType (const Address &address)
mathieu@1173
    98
{
mathieu@1173
    99
  return address.CheckCompatible (GetType (), 6);
mathieu@1173
   100
}
mathieu@1705
   101
Mac48Address::operator Address () const
mathieu@1205
   102
{
mathieu@1205
   103
  return ConvertTo ();
mathieu@1205
   104
}
mathieu@1158
   105
Address 
mathieu@1494
   106
Mac48Address::ConvertTo (void) const
mathieu@1158
   107
{
mathieu@1158
   108
  return Address (GetType (), m_address, 6);
mathieu@1158
   109
}
mathieu@1494
   110
Mac48Address 
mathieu@1494
   111
Mac48Address::ConvertFrom (const Address &address)
mathieu@1158
   112
{
mathieu@1159
   113
  NS_ASSERT (address.CheckCompatible (GetType (), 6));
mathieu@1494
   114
  Mac48Address retval;
mathieu@1158
   115
  address.CopyTo (retval.m_address);
mathieu@1158
   116
  return retval;
mathieu@1158
   117
}
mathieu@1494
   118
Mac48Address 
mathieu@1494
   119
Mac48Address::Allocate (void)
mathieu@1161
   120
{
mathieu@1161
   121
  static uint64_t id = 0;
mathieu@1161
   122
  id++;
mathieu@1494
   123
  Mac48Address address;
mathieu@1179
   124
  address.m_address[0] = (id >> 40) & 0xff;
mathieu@1161
   125
  address.m_address[1] = (id >> 32) & 0xff;
mathieu@1161
   126
  address.m_address[2] = (id >> 24) & 0xff;
mathieu@1161
   127
  address.m_address[3] = (id >> 16) & 0xff;
mathieu@1161
   128
  address.m_address[4] = (id >> 8) & 0xff;
mathieu@1161
   129
  address.m_address[5] = (id >> 0) & 0xff;
mathieu@1161
   130
  return address;
mathieu@1161
   131
}
mathieu@1158
   132
uint8_t 
mathieu@1494
   133
Mac48Address::GetType (void)
mathieu@1158
   134
{
mathieu@1158
   135
  static uint8_t type = Address::Register ();
mathieu@1158
   136
  return type;
mathieu@1158
   137
}
mathieu@1158
   138
mathieu@1707
   139
bool
mathieu@1707
   140
Mac48Address::IsBroadcast (void) const
mathieu@1707
   141
{
mathieu@1707
   142
  return *this == GetBroadcast ();
mathieu@1707
   143
}
mathieu@1707
   144
bool 
mathieu@1707
   145
Mac48Address::IsMulticast (void) const
mathieu@1707
   146
{
mathieu@3549
   147
  uint8_t mcBuf[6];
mathieu@3549
   148
  CopyTo (mcBuf);
mathieu@3549
   149
  mcBuf[3] &= 0x80;
mathieu@3549
   150
  mcBuf[4] = 0;
mathieu@3549
   151
  mcBuf[5] = 0;
mathieu@3549
   152
  Mac48Address prefix;
mathieu@3549
   153
  prefix.CopyFrom (mcBuf);
mathieu@3549
   154
  return prefix == Mac48Address::GetMulticastPrefix ();
mathieu@3549
   155
}
mathieu@3549
   156
bool 
mathieu@3549
   157
Mac48Address::IsGroup (void) const
mathieu@3549
   158
{
mathieu@1707
   159
  return (m_address[0] & 0x01) == 0x01;
mathieu@1707
   160
}
mathieu@1707
   161
Mac48Address
mathieu@1707
   162
Mac48Address::GetBroadcast (void)
mathieu@1707
   163
{
mathieu@1707
   164
  static Mac48Address broadcast = Mac48Address ("ff:ff:ff:ff:ff:ff");
mathieu@1707
   165
  return broadcast;
mathieu@1707
   166
}
mathieu@3549
   167
Mac48Address 
mathieu@3549
   168
Mac48Address::GetMulticastPrefix (void)
mathieu@3549
   169
{
mathieu@3549
   170
  static Mac48Address multicast = Mac48Address ("01:00:5e:00:00:00");
mathieu@3549
   171
  return multicast;
mathieu@3549
   172
}
vincent@3852
   173
Mac48Address
vincent@3852
   174
Mac48Address::GetMulticast6Prefix (void)
vincent@3852
   175
{
vincent@3852
   176
  static Mac48Address multicast = Mac48Address ("33:33:00:00:00:00");
vincent@3852
   177
  return multicast;
vincent@3852
   178
}
mathieu@3549
   179
Mac48Address 
mathieu@3549
   180
Mac48Address::GetMulticast (Ipv4Address multicastGroup)
mathieu@3549
   181
{
mathieu@3549
   182
  Mac48Address etherAddr = Mac48Address::GetMulticastPrefix ();
mathieu@3549
   183
  //
mathieu@3549
   184
  // We now have the multicast address in an abstract 48-bit container.  We 
mathieu@3549
   185
  // need to pull it out so we can play with it.  When we're done, we have the 
mathieu@3549
   186
  // high order bits in etherBuffer[0], etc.
mathieu@3549
   187
  //
mathieu@3549
   188
  uint8_t etherBuffer[6];
mathieu@3549
   189
  etherAddr.CopyTo (etherBuffer);
mathieu@3549
   190
mathieu@3549
   191
  //
mathieu@3549
   192
  // Now we need to pull the raw bits out of the Ipv4 destination address.
mathieu@3549
   193
  //
mathieu@3549
   194
  uint8_t ipBuffer[4];
mathieu@3549
   195
  multicastGroup.Serialize (ipBuffer);
mathieu@3549
   196
mathieu@3549
   197
  //
mathieu@3549
   198
  // RFC 1112 says that an Ipv4 host group address is mapped to an EUI-48
mathieu@3549
   199
  // multicast address by placing the low-order 23-bits of the IP address into 
mathieu@3549
   200
  // the low-order 23 bits of the Ethernet multicast address 
mathieu@3549
   201
  // 01-00-5E-00-00-00 (hex). 
mathieu@3549
   202
  //
mathieu@3549
   203
  etherBuffer[3] |= ipBuffer[1] & 0x7f;
mathieu@3549
   204
  etherBuffer[4] = ipBuffer[2];
mathieu@3549
   205
  etherBuffer[5] = ipBuffer[3];
mathieu@3549
   206
mathieu@3549
   207
  //
mathieu@3549
   208
  // Now, etherBuffer has the desired ethernet multicast address.  We have to
mathieu@3549
   209
  // suck these bits back into the Mac48Address,
mathieu@3549
   210
  //
mathieu@3549
   211
  Mac48Address result;
mathieu@3549
   212
  result.CopyFrom (etherBuffer);
mathieu@3549
   213
  return result;
mathieu@3549
   214
}
vincent@3852
   215
Mac48Address Mac48Address::GetMulticast(Ipv6Address addr)
vincent@3852
   216
{
vincent@3852
   217
  Mac48Address etherAddr = Mac48Address::GetMulticast6Prefix();
vincent@3852
   218
  uint8_t etherBuffer[6];
vincent@3852
   219
  uint8_t ipBuffer[16];
vincent@3852
   220
vincent@3852
   221
  /* a MAC multicast IPv6 address is like 33:33 and the four low bytes */
vincent@3852
   222
  /* for 2001:db8::2fff:fe11:ac10 => 33:33:FE:11:AC:10 */
vincent@3852
   223
  etherAddr.CopyTo (etherBuffer);
vincent@3852
   224
  addr.Serialize (ipBuffer);
vincent@3852
   225
vincent@3852
   226
  etherBuffer[2] = ipBuffer[12];
vincent@3852
   227
  etherBuffer[3] = ipBuffer[13];
vincent@3852
   228
  etherBuffer[4] = ipBuffer[14];
vincent@3852
   229
  etherBuffer[5] = ipBuffer[15];
vincent@3852
   230
vincent@3852
   231
  etherAddr.CopyFrom (etherBuffer);
vincent@3852
   232
vincent@3852
   233
  return etherAddr;
vincent@3852
   234
}
mathieu@2411
   235
mathieu@1494
   236
bool operator == (const Mac48Address &a, const Mac48Address &b)
mathieu@1167
   237
{
mathieu@1707
   238
  return memcmp (a.m_address, b.m_address, 6) == 0;
mathieu@1167
   239
}
mathieu@1494
   240
bool operator != (const Mac48Address &a, const Mac48Address &b)
mathieu@1167
   241
{
mathieu@1167
   242
  return ! (a == b);
mathieu@1167
   243
}
mathieu@1167
   244
mathieu@1707
   245
bool operator < (const Mac48Address &a, const Mac48Address &b)
mathieu@1707
   246
{
mathieu@1926
   247
  uint8_t aP[6];
mathieu@1926
   248
  uint8_t bP[6];
mathieu@1926
   249
  a.CopyTo (aP);
mathieu@1926
   250
  b.CopyTo (bP);
mathieu@1707
   251
  for (uint8_t i = 0; i < 6; i++) 
mathieu@1707
   252
    {
mathieu@1953
   253
       if (a.m_address[i] < b.m_address[i]) 
mathieu@1707
   254
        {
mathieu@1707
   255
          return true;
mathieu@1707
   256
        } 
mathieu@1953
   257
       else if (a.m_address[i] > b.m_address[i]) 
mathieu@1707
   258
        {
mathieu@1707
   259
          return false;
mathieu@1707
   260
        }
mathieu@1707
   261
    }
mathieu@1707
   262
  return false;
mathieu@1707
   263
}
mathieu@1707
   264
mathieu@1707
   265
mathieu@1494
   266
std::ostream& operator<< (std::ostream& os, const Mac48Address & address)
mathieu@1167
   267
{
mathieu@1167
   268
  uint8_t ad[6];
mathieu@1167
   269
  address.CopyTo (ad);
mathieu@1167
   270
mathieu@1167
   271
  os.setf (std::ios::hex, std::ios::basefield);
mathieu@1262
   272
  os.fill('0');
mathieu@1167
   273
  for (uint8_t i=0; i < 5; i++) 
mathieu@1167
   274
    {
mathieu@1167
   275
      os << std::setw(2) << (uint32_t)ad[i] << ":";
mathieu@1167
   276
    }
mathieu@1167
   277
  // Final byte not suffixed by ":"
mathieu@1167
   278
  os << std::setw(2) << (uint32_t)ad[5];
mathieu@1167
   279
  os.setf (std::ios::dec, std::ios::basefield);
mathieu@1262
   280
  os.fill(' ');
mathieu@1167
   281
  return os;
mathieu@1167
   282
}
mathieu@1167
   283
mathieu@2954
   284
static uint8_t
mathieu@2954
   285
AsInt (std::string v)
mathieu@2411
   286
{
mathieu@2954
   287
  std::istringstream iss;
mathieu@2954
   288
  iss.str (v);
mathieu@2954
   289
  uint32_t retval;
mathieu@2954
   290
  iss >> std::hex >> retval >> std::dec;
mathieu@2954
   291
  return retval;
mathieu@2954
   292
}
mathieu@2954
   293
mathieu@2954
   294
std::istream& operator>> (std::istream& is, Mac48Address & address)
mathieu@2954
   295
{
mathieu@2954
   296
  std::string v;
mathieu@2954
   297
  is >> v;
mathieu@2954
   298
mathieu@2954
   299
  std::string::size_type col = 0;
mathieu@2954
   300
  for (uint8_t i = 0; i < 6; ++i)
mathieu@2954
   301
    {
mathieu@2954
   302
      std::string tmp;
mathieu@2954
   303
      std::string::size_type next;
mathieu@2954
   304
      next = v.find (":", col);
mathieu@2954
   305
      if (next == std::string::npos)
mathieu@2954
   306
	{
mathieu@2954
   307
	  tmp = v.substr (col, v.size ()-col);
mathieu@2954
   308
	  address.m_address[i] = AsInt (tmp);
mathieu@2954
   309
	  break;
mathieu@2954
   310
	}
mathieu@2954
   311
      else
mathieu@2954
   312
	{
mathieu@2954
   313
	  tmp = v.substr (col, next-col);
mathieu@2954
   314
	  address.m_address[i] = AsInt (tmp);
mathieu@2954
   315
	  col = next + 1;
mathieu@2954
   316
	}
mathieu@2954
   317
    }
mathieu@2411
   318
  return is;
mathieu@2411
   319
}
mathieu@2411
   320
mathieu@1158
   321
mathieu@1158
   322
} // namespace ns3