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