1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2007-2008 Louis Pasteur University
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;
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.
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
18 * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
24 #include "ipv6-address.h"
25 #include "ns3/assert.h"
26 #include "mac48-address.h"
30 NS_LOG_COMPONENT_DEFINE ("Ipv6Address");
40 * \brief Get a hash key.
42 * \param length the length of the key
43 * \param level the previous hash, or an arbitrary value
45 * \note Adpated from Jens Jakobsen implementation (chillispot).
47 static uint32_t lookuphash (unsigned char* k, uint32_t length, uint32_t level)
51 a -= b; a -= c; a ^= (c>>13); \
52 b -= c; b -= a; b ^= (a<<8); \
53 c -= a; c -= b; c ^= (b>>13); \
54 a -= b; a -= c; a ^= (c>>12); \
55 b -= c; b -= a; b ^= (a<<16); \
56 c -= a; c -= b; c ^= (b>>5); \
57 a -= b; a -= c; a ^= (c>>3); \
58 b -= c; b -= a; b ^= (a<<10); \
59 c -= a; c -= b; c ^= (b>>15); \
62 typedef uint32_t ub4; /* unsigned 4-byte quantities */
63 typedef unsigned char ub1; /* unsigned 1-byte quantities */
66 /* Set up the internal state */
68 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
69 c = level; /* the previous hash value */
71 /*---------------------------------------- handle most of the key */
74 a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
75 b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
76 c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
81 /*------------------------------------- handle the last 11 bytes */
83 switch(len) /* all the case statements fall through */
85 case 11: c+=((ub4)k[10]<<24);
86 case 10: c+=((ub4)k[9]<<16);
87 case 9 : c+=((ub4)k[8]<<8);
88 /* the first byte of c is reserved for the length */
89 case 8 : b+=((ub4)k[7]<<24);
90 case 7 : b+=((ub4)k[6]<<16);
91 case 6 : b+=((ub4)k[5]<<8);
93 case 4 : a+=((ub4)k[3]<<24);
94 case 3 : a+=((ub4)k[2]<<16);
95 case 2 : a+=((ub4)k[1]<<8);
97 /* case 0: nothing left to add */
100 /*-------------------------------------------- report the result */
108 * \brief Convert an IPv6 C-string into a 128-bit representation.
109 * \return 1 if OK, 0 if failure (bad format, ...)
110 * \note This function is strongly inspired by inet_pton6() from Paul Vixie.
111 * \todo Handle IPv6 address with decimal value for last four bytes.
113 static int AsciiToIpv6Host (char const *address, uint8_t addr[16])
115 static const char xdigits_l[] = "0123456789abcdef",
116 xdigits_u[] = "0123456789ABCDEF";
117 unsigned char tmp[16 /*NS_IN6ADDRSZ*/], *tp, *endp, *colonp;
118 const char *xdigits, *curtok;
119 int ch, seen_xdigits;
122 memset((tp = tmp), '\0', 16 /* NS_IN6ADDRSZ*/);
123 endp = tp + 16 /*NS_IN6ADDRSZ*/;
125 /* Leading :: requires some special handling. */
127 if (*++address != ':')
132 while ((ch = *address++) != '\0')
136 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
137 pch = strchr((xdigits = xdigits_u), ch);
141 val |= (pch - xdigits);
142 if (++seen_xdigits > 4)
156 if (tp + 2 /*NS_INT16SZ*/ > endp)
158 *tp++ = (unsigned char) (val >> 8) & 0xff;
159 *tp++ = (unsigned char) val & 0xff;
165 /* TODO Handle address like 2001::xxx.xxx.xxx.xxxx */
167 if (ch == '.' && ((tp + 4 /*NS_INADDRSZ*/) <= endp) &&
168 inet_pton4(curtok, tp) > 0)
170 tp += 4 /*NS_INADDRSZ*/;
172 break;/* '\0' was seen by inet_pton4(). */
179 if (tp + 2/* NS_INT16SZ*/ > endp)
181 *tp++ = (unsigned char) (val >> 8) & 0xff;
182 *tp++ = (unsigned char) val & 0xff;
187 * Since some memmove()'s erroneously fail to handle
188 * overlapping regions, we'll do the shift by hand.
190 const int n = tp - colonp;
195 for (i = 1; i <= n; i++)
197 endp[- i] = colonp[n - i];
205 /* memcpy(dst, tmp, NS_IN6ADDRSZ); */
206 memcpy(addr, tmp, 16);
210 Ipv6Address::Ipv6Address ()
212 memset(m_address, 0x00, 16);
215 Ipv6Address::Ipv6Address (Ipv6Address const& addr)
217 memcpy(m_address, addr.m_address, 16);
220 Ipv6Address::Ipv6Address (Ipv6Address const* addr)
222 memcpy(m_address, addr->m_address, 16);
225 Ipv6Address::Ipv6Address (char const* address)
227 AsciiToIpv6Host (address, m_address);
230 Ipv6Address::Ipv6Address (uint8_t address[16])
232 /* 128 bit => 16 bytes */
233 memcpy(m_address, address, 16);
236 Ipv6Address::~Ipv6Address ()
241 void Ipv6Address::Set (char const* address)
243 AsciiToIpv6Host (address, m_address);
246 void Ipv6Address::Set (uint8_t address[16])
248 /* 128 bit => 16 bytes */
249 memcpy(m_address, address, 16);
252 void Ipv6Address::Serialize (uint8_t buf[16]) const
254 memcpy(buf, m_address, 16);
257 Ipv6Address Ipv6Address::Deserialize (const uint8_t buf[16])
259 Ipv6Address ipv6((uint8_t*)buf);
263 Ipv6Address Ipv6Address::MakeAutoconfiguredAddress (Mac48Address addr, Ipv6Address prefix)
270 prefix.GetBytes(buf2);
272 memcpy(buf2 + 8, buf, 3);
275 memcpy(buf2 + 13, buf + 3, 3);
282 Ipv6Address Ipv6Address::MakeAutoconfiguredLinkLocalAddress (Mac48Address addr)
290 memset(buf2, 0x00, sizeof(buf2));
293 memcpy(buf2 + 8, buf, 3);
296 memcpy(buf2 + 13, buf + 3, 3);
303 Ipv6Address Ipv6Address::MakeSolicitedAddress (Ipv6Address addr)
309 addr.Serialize(buf2);
311 memset(buf, 0x00, sizeof(buf));
324 void Ipv6Address::Print (std::ostream& os) const
326 os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[0]
327 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[1] << ":"
328 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[2]
329 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[3] << ":"
330 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[4]
331 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[5] << ":"
332 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[6]
333 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[7] << ":"
334 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[8]
335 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[9] << ":"
336 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[10]
337 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[11] << ":"
338 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[12]
339 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[13] << ":"
340 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[14]
341 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_address[15];
344 bool Ipv6Address::IsLocalhost () const
346 static Ipv6Address localhost("::1");
347 return (*this == localhost);
350 bool Ipv6Address::IsMulticast () const
352 if(m_address[0] == 0xff)
359 Ipv6Address Ipv6Address::CombinePrefix (Ipv6Prefix const & prefix)
366 memcpy(addr, m_address, 16);
367 ((Ipv6Prefix)prefix).GetBytes(pref);
369 /* a little bit ugly... */
370 for(i = 0 ; i < 16 ; i++)
372 addr[i] = addr[i] & pref[i];
378 bool Ipv6Address::IsSolicitedMulticast () const
394 bool Ipv6Address::IsAllNodesMulticast () const
396 static Ipv6Address allnodes("ff02::1");
397 return (*this == allnodes);
400 bool Ipv6Address::IsAllRoutersMulticast () const
402 static Ipv6Address allrouters("ff02::2");
403 return (*this == allrouters);
406 bool Ipv6Address::IsAllHostsMulticast () const
408 static Ipv6Address allhosts("ff02::3");
409 return (*this == allhosts);
412 bool Ipv6Address::IsAny () const
414 static Ipv6Address any("::");
415 return (*this == any);
418 bool Ipv6Address::IsMatchingType (const Address& address)
420 return address.CheckCompatible(GetType(), 16);
423 Ipv6Address::operator Address () const
428 Address Ipv6Address::ConvertTo (void) const
432 return Address(GetType(), buf, 16);
435 Ipv6Address Ipv6Address::ConvertFrom (const Address &address)
437 NS_ASSERT (address.CheckCompatible (GetType (), 16));
439 address.CopyTo (buf);
440 return Deserialize (buf);
443 uint8_t Ipv6Address::GetType (void)
445 static uint8_t type = Address::Register();
449 Ipv6Address Ipv6Address::GetZero ()
451 Ipv6Address zero("::");
455 Ipv6Address Ipv6Address::GetAny ()
457 Ipv6Address any("::");
461 Ipv6Address Ipv6Address::GetAllNodesMulticast ()
463 Ipv6Address nmc("ff02::1");
467 Ipv6Address Ipv6Address::GetAllRoutersMulticast ()
469 Ipv6Address rmc("ff02::2");
473 Ipv6Address Ipv6Address::GetAllHostsMulticast ()
475 Ipv6Address hmc("ff02::3");
479 Ipv6Address Ipv6Address::GetLoopback ()
481 static Ipv6Address loopback("::1");
485 void Ipv6Address::GetBytes (uint8_t buf[16]) const
487 memcpy(buf, m_address, 16);
490 bool Ipv6Address::IsLinkLocal () const
492 Ipv6Address linkLocal("fe80::0");
493 if(!IsMulticast() && ((Ipv6Address*)this)->CombinePrefix(Ipv6Prefix(64))==linkLocal)
500 bool Ipv6Address::IsEqual (const Ipv6Address& other) const
502 if(!memcmp(m_address, other.m_address, 16))
509 std::ostream& operator << (std::ostream& os, Ipv6Address const& address)
515 std::istream& operator >> (std::istream& is, Ipv6Address& address)
519 address = Ipv6Address (str.c_str ());
523 Ipv6Prefix::Ipv6Prefix ()
525 memset(m_prefix, 0x00, 16);
528 Ipv6Prefix::Ipv6Prefix (char const* prefix)
530 AsciiToIpv6Host(prefix, m_prefix);
533 Ipv6Prefix::Ipv6Prefix (uint8_t prefix[16])
535 memcpy(m_prefix, prefix, 16);
538 Ipv6Prefix::Ipv6Prefix (uint8_t prefix)
544 memset(m_prefix, 0x00, 16);
546 NS_ASSERT(prefix <= 128);
551 memset(m_prefix, 0xff, nb);
555 m_prefix[nb] = 0xff << (8-mod);
561 for(i = nb; i < 16 ; i++)
568 Ipv6Prefix::Ipv6Prefix (Ipv6Prefix const& prefix)
570 memcpy(m_prefix, prefix.m_prefix, 16);
573 Ipv6Prefix::Ipv6Prefix (Ipv6Prefix const* prefix)
575 memcpy(m_prefix, prefix->m_prefix, 16);
578 Ipv6Prefix::~Ipv6Prefix ()
583 bool Ipv6Prefix::IsMatch (Ipv6Address a, Ipv6Address b) const
592 /* a little bit ugly... */
593 for(i = 0 ; i < 16 ; i++)
595 if((addrA[i] & m_prefix[i]) != (addrB[i] & m_prefix[i]))
603 void Ipv6Prefix::Print (std::ostream &os) const
605 os << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[0]
606 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[1] << ":"
607 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[2]
608 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[3] << ":"
609 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[4]
610 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[5] << ":"
611 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[6]
612 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[7] << ":"
613 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[8]
614 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[9] << ":"
615 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[10]
616 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[11] << ":"
617 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[12]
618 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[13] << ":"
619 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[14]
620 << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) m_prefix[15];
623 Ipv6Prefix Ipv6Prefix::GetLoopback ()
625 Ipv6Prefix prefix((uint8_t)128);
629 Ipv6Prefix Ipv6Prefix::GetZero ()
631 Ipv6Prefix prefix((uint8_t)0);
635 void Ipv6Prefix::GetBytes (uint8_t buf[16]) const
637 memcpy(buf, m_prefix, 16);
640 bool Ipv6Prefix::IsEqual (const Ipv6Prefix& other) const
642 if(!memcmp(m_prefix, other.m_prefix, 16))
649 std::ostream& operator<< (std::ostream& os, Ipv6Prefix const& prefix)
655 std::istream& operator >> (std::istream& is, Ipv6Prefix& prefix)
659 prefix = Ipv6Prefix (str.c_str ());
663 bool operator == (Ipv6Prefix const &a, Ipv6Prefix const &b)
665 return a.IsEqual (b);
668 bool operator != (Ipv6Prefix const &a, Ipv6Prefix const &b)
670 return !a.IsEqual (b);
673 size_t Ipv6AddressHash::operator() (Ipv6Address const &x) const
679 return lookuphash(buf, sizeof(buf), 0);
682 ATTRIBUTE_HELPER_CPP (Ipv6Address);
683 ATTRIBUTE_HELPER_CPP (Ipv6Prefix);
685 } /* namespace ns3 */