A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ipv6-address.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007-2008 Louis Pasteur University
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: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
19  */
20 
21 #include <iomanip>
22 #include <memory.h>
23 
24 #include "ns3/log.h"
25 #include "ns3/assert.h"
26 
27 #include "mac48-address.h"
28 #include "ipv6-address.h"
29 
30 NS_LOG_COMPONENT_DEFINE ("Ipv6Address");
31 
32 namespace ns3 {
33 
34 #ifdef __cplusplus
35 extern "C"
36 { /* } */
37 #endif
38 
47 static uint32_t lookuphash (unsigned char* k, uint32_t length, uint32_t level)
48 {
49  NS_LOG_FUNCTION (k << length << level);
50 #define mix(a, b, c) \
51  ({ \
52  (a) -= (b); (a) -= (c); (a) ^= ((c) >> 13); \
53  (b) -= (c); (b) -= (a); (b) ^= ((a) << 8); \
54  (c) -= (a); (c) -= (b); (c) ^= ((b) >> 13); \
55  (a) -= (b); (a) -= (c); (a) ^= ((c) >> 12); \
56  (b) -= (c); (b) -= (a); (b) ^= ((a) << 16); \
57  (c) -= (a); (c) -= (b); (c) ^= ((b) >> 5); \
58  (a) -= (b); (a) -= (c); (a) ^= ((c) >> 3); \
59  (b) -= (c); (b) -= (a); (b) ^= ((a) << 10); \
60  (c) -= (a); (c) -= (b); (c) ^= ((b) >> 15); \
61  })
62 
63  typedef uint32_t ub4; /* unsigned 4-byte quantities */
64  typedef unsigned char ub1; /* unsigned 1-byte quantities */
65  uint32_t a = 0;
66  uint32_t b = 0;
67  uint32_t c = 0;
68  uint32_t len = 0;
69 
70  /* Set up the internal state */
71  len = length;
72  a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
73  c = level; /* the previous hash value */
74 
75  /* handle most of the key */
76  while (len >= 12)
77  {
78  a += (k[0] + ((ub4)k[1] << 8) + ((ub4)k[2] << 16) + ((ub4)k[3] << 24));
79  b += (k[4] + ((ub4)k[5] << 8) + ((ub4)k[6] << 16) + ((ub4)k[7] << 24));
80  c += (k[8] + ((ub4)k[9] << 8) + ((ub4)k[10] << 16) + ((ub4)k[11] << 24));
81  mix (a, b, c);
82  k += 12;
83  len -= 12;
84  }
85 
86  /* handle the last 11 bytes */
87  c += length;
88  switch (len) /* all the case statements fall through */
89  {
90  case 11: c += ((ub4)k[10] << 24);
91  case 10: c += ((ub4)k[9] << 16);
92  case 9: c += ((ub4)k[8] << 8); /* the first byte of c is reserved for the length */
93  case 8: b += ((ub4)k[7] << 24);
94  case 7: b += ((ub4)k[6] << 16);
95  case 6: b += ((ub4)k[5] << 8);
96  case 5: b += k[4];
97  case 4: a += ((ub4)k[3] << 24);
98  case 3: a += ((ub4)k[2] << 16);
99  case 2: a += ((ub4)k[1] << 8);
100  case 1: a += k[0];
101  /* case 0: nothing left to add */
102  }
103  mix (a, b, c);
104 
105 #undef mix
106 
107  /* report the result */
108  return c;
109 }
110 
111 #ifdef __cplusplus
112 }
113 #endif
114 
121 static bool AsciiToIpv6Host (const char *address, uint8_t addr[16])
122 {
123  NS_LOG_FUNCTION (address << &addr);
124  static const char xdigits_l[] = "0123456789abcdef";
125  static const char xdigits_u[] = "0123456789ABCDEF";
126  unsigned char tmp[16];
127  unsigned char* tp = tmp;
128  unsigned char* endp = 0;
129  unsigned char* colonp = 0;
130  const char* xdigits = 0;
131 #if 0
132  const char* curtok = 0;
133 #endif
134  int ch = 0;
135  int seen_xdigits = 0;
136  unsigned int val = 0;
137 
138  memset (tp, 0x00, 16);
139  endp = tp + 16;
140 
141  /* Leading :: requires some special handling. */
142  if (*address == ':')
143  {
144  if (*++address != ':')
145  {
146  return (0);
147  }
148  }
149 #if 0
150  curtok = address;
151 #endif
152  while ((ch = *address++) != '\0')
153  {
154  const char *pch = 0;
155 
156  if ((pch = strchr ((xdigits = xdigits_l), ch)) == 0)
157  {
158  pch = strchr ((xdigits = xdigits_u), ch);
159  }
160 
161  if (pch != 0)
162  {
163  val <<= 4;
164  val |= (pch - xdigits);
165 
166  if (++seen_xdigits > 4)
167  {
168  return (0);
169  }
170  continue;
171  }
172  if (ch == ':')
173  {
174 #if 0
175  curtok = address;
176 #endif
177 
178  if (!seen_xdigits)
179  {
180  if (colonp)
181  return (0);
182  colonp = tp;
183  continue;
184  }
185 
186  if (tp + 2 > endp)
187  {
188  return (0);
189  }
190 
191  *tp++ = (unsigned char)(val >> 8) & 0xff;
192  *tp++ = (unsigned char) val & 0xff;
193  seen_xdigits = 0;
194  val = 0;
195  continue;
196  }
197 
198  /* TODO Handle IPv4 mapped address (2001::192.168.0.1) */
199 #if 0
200  if (ch == '.' && ((tp + 4 /*NS_INADDRSZ*/) <= endp) &&
201  inet_pton4 (curtok, tp) > 0)
202  {
203  tp += 4 /*NS_INADDRSZ*/;
204  seen_xdigits = 0;
205  break; /* '\0' was seen by inet_pton4(). */
206  }
207 #endif
208  return (0);
209  }
210 
211  if (seen_xdigits)
212  {
213  if (tp + 2 > endp)
214  {
215  return (0);
216  }
217  *tp++ = (unsigned char)(val >> 8) & 0xff;
218  *tp++ = (unsigned char) val & 0xff;
219  }
220 
221  if (colonp != 0)
222  {
223  /*
224  * Since some memmove ()'s erroneously fail to handle
225  * overlapping regions, we'll do the shift by hand.
226  */
227  const int n = tp - colonp;
228  int i = 0;
229 
230  if (tp == endp)
231  {
232  return (0);
233  }
234 
235  for (i = 1; i <= n; i++)
236  {
237  endp[-i] = colonp[n - i];
238  colonp[n - i] = 0;
239  }
240 
241  tp = endp;
242  }
243 
244  if (tp != endp)
245  {
246  return (0);
247  }
248 
249  memcpy (addr, tmp, 16);
250  return (1);
251 }
252 
254 {
255  NS_LOG_FUNCTION (this);
256  memset (m_address, 0x00, 16);
257 }
258 
260 {
261  // Do not add function logging here, to avoid stack overflow
262  memcpy (m_address, addr.m_address, 16);
263 }
264 
266 {
267  // Do not add function logging here, to avoid stack overflow
268  memcpy (m_address, addr->m_address, 16);
269 }
270 
271 Ipv6Address::Ipv6Address (char const* address)
272 {
273  NS_LOG_FUNCTION (this << address);
274  AsciiToIpv6Host (address, m_address);
275 }
276 
277 Ipv6Address::Ipv6Address (uint8_t address[16])
278 {
279  NS_LOG_FUNCTION (this << &address);
280  /* 128 bit => 16 bytes */
281  memcpy (m_address, address, 16);
282 }
283 
285 {
286  /* do nothing */
287  NS_LOG_FUNCTION (this);
288 }
289 
290 void Ipv6Address::Set (char const* address)
291 {
292  NS_LOG_FUNCTION (this << address);
293  AsciiToIpv6Host (address, m_address);
294 }
295 
296 void Ipv6Address::Set (uint8_t address[16])
297 {
298  /* 128 bit => 16 bytes */
299  NS_LOG_FUNCTION (this << &address);
300  memcpy (m_address, address, 16);
301 }
302 
303 void Ipv6Address::Serialize (uint8_t buf[16]) const
304 {
305  NS_LOG_FUNCTION (this << &buf);
306  memcpy (buf, m_address, 16);
307 }
308 
309 Ipv6Address Ipv6Address::Deserialize (const uint8_t buf[16])
310 {
311  NS_LOG_FUNCTION (&buf);
312  Ipv6Address ipv6 ((uint8_t*)buf);
313  return ipv6;
314 }
315 
317 {
318  NS_LOG_FUNCTION (addr);
319  uint8_t buf[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320  0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
321  addr.Serialize (&buf[12]);
322  return (Ipv6Address (buf));
323 }
324 
326 {
327  NS_LOG_FUNCTION (this);
328  uint8_t buf[16];
329  Ipv4Address v4Addr;
330 
331  Serialize (buf);
332  v4Addr = Ipv4Address::Deserialize (&buf[12]);
333  return (v4Addr);
334 }
335 
337 {
338  NS_LOG_FUNCTION (addr << prefix);
339  Ipv6Address ret;
340  uint8_t buf[16];
341  uint8_t buf2[16];
342 
343  addr.CopyTo (buf);
344  prefix.GetBytes (buf2);
345 
346  memcpy (buf2 + 8, buf, 3);
347  buf2[11] = 0xff;
348  buf2[12] = 0xfe;
349  memcpy (buf2 + 13, buf + 3, 3);
350  buf2[8] |= 0x02;
351 
352  ret.Set (buf2);
353  return ret;
354 }
355 
357 {
358  NS_LOG_FUNCTION (addr);
359  Ipv6Address ret;
360  uint8_t buf[16];
361  uint8_t buf2[16];
362 
363  addr.CopyTo (buf);
364 
365  memset (buf2, 0x00, sizeof (buf2));
366  buf2[0] = 0xfe;
367  buf2[1] = 0x80;
368  memcpy (buf2 + 8, buf, 3);
369  buf2[11] = 0xff;
370  buf2[12] = 0xfe;
371  memcpy (buf2 + 13, buf + 3, 3);
372  buf2[8] |= 0x02;
373 
374  ret.Set (buf2);
375  return ret;
376 }
377 
379 {
380  NS_LOG_FUNCTION (addr);
381  uint8_t buf[16];
382  uint8_t buf2[16];
383  Ipv6Address ret;
384 
385  addr.Serialize (buf2);
386 
387  memset (buf, 0x00, sizeof (buf));
388  buf[0] = 0xff;
389  buf[1] = 0x02;
390  buf[11] = 0x01;
391  buf[12] = 0xff;
392  buf[13] = buf2[13];
393  buf[14] = buf2[14];
394  buf[15] = buf2[15];
395 
396  ret.Set (buf);
397  return ret;
398 }
399 
400 void Ipv6Address::Print (std::ostream& os) const
401 {
402  NS_LOG_FUNCTION (this << &os);
403  os << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[0]
404  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[1] << ":"
405  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[2]
406  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[3] << ":"
407  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[4]
408  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[5] << ":"
409  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[6]
410  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[7] << ":"
411  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[8]
412  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[9] << ":"
413  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[10]
414  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[11] << ":"
415  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[12]
416  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[13] << ":"
417  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[14]
418  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_address[15]
419  << std::dec << std::setfill (' ');
420 }
421 
423 {
424  NS_LOG_FUNCTION (this);
425  static Ipv6Address localhost ("::1");
426  return (*this == localhost);
427 }
428 
430 {
431  NS_LOG_FUNCTION (this);
432  if (m_address[0] == 0xff)
433  {
434  return true;
435  }
436  return false;
437 }
438 
440 {
441  NS_LOG_FUNCTION (this);
442  if (m_address[0] == 0xff && m_address[1] == 0x02)
443  {
444  return true;
445  }
446  return false;
447 }
448 
450 {
451  NS_LOG_FUNCTION (this);
452  uint8_t v4MappedPrefix[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453  0x00, 0x00, 0xff, 0xff };
454  if (memcmp(m_address, v4MappedPrefix, sizeof(v4MappedPrefix)) == 0)
455  {
456  return (true);
457  }
458  return (false);
459 }
460 
462 {
463  NS_LOG_FUNCTION (this << prefix);
464  Ipv6Address ipv6;
465  uint8_t addr[16];
466  uint8_t pref[16];
467  unsigned int i = 0;
468 
469  memcpy (addr, m_address, 16);
470  ((Ipv6Prefix)prefix).GetBytes (pref);
471 
472  /* a little bit ugly... */
473  for (i = 0; i < 16; i++)
474  {
475  addr[i] = addr[i] & pref[i];
476  }
477  ipv6.Set (addr);
478  return ipv6;
479 }
480 
482 {
483  NS_LOG_FUNCTION (this);
484  uint8_t buf[16];
485 
486  Serialize (buf);
487 
488  if (buf[0] == 0xff &&
489  buf[1] == 0x02 &&
490  buf[11] == 0x01 &&
491  buf[12] == 0xff)
492  {
493  return true;
494  }
495  return false;
496 }
497 
499 {
500  NS_LOG_FUNCTION (this);
501  static Ipv6Address allnodes ("ff02::1");
502  return (*this == allnodes);
503 }
504 
506 {
507  NS_LOG_FUNCTION (this);
508  static Ipv6Address allrouters ("ff02::2");
509  return (*this == allrouters);
510 }
511 
513 {
514  NS_LOG_FUNCTION (this);
515  static Ipv6Address allhosts ("ff02::3");
516  return (*this == allhosts);
517 }
518 
519 bool Ipv6Address::IsAny () const
520 {
521  NS_LOG_FUNCTION (this);
522  static Ipv6Address any ("::");
523  return (*this == any);
524 }
525 
527 {
528  NS_LOG_FUNCTION (address);
529  return address.CheckCompatible (GetType (), 16);
530 }
531 
532 Ipv6Address::operator Address () const
533 {
534  return ConvertTo ();
535 }
536 
538 {
539  NS_LOG_FUNCTION (this);
540  uint8_t buf[16];
541  Serialize (buf);
542  return Address (GetType (), buf, 16);
543 }
544 
546 {
547  NS_LOG_FUNCTION (address);
548  NS_ASSERT (address.CheckCompatible (GetType (), 16));
549  uint8_t buf[16];
550  address.CopyTo (buf);
551  return Deserialize (buf);
552 }
553 
554 uint8_t Ipv6Address::GetType (void)
555 {
557  static uint8_t type = Address::Register ();
558  return type;
559 }
560 
562 {
564  static Ipv6Address nmc ("ff02::1");
565  return nmc;
566 }
567 
569 {
571  static Ipv6Address rmc ("ff02::2");
572  return rmc;
573 }
574 
576 {
578  static Ipv6Address hmc ("ff02::3");
579  return hmc;
580 }
581 
583 {
585  static Ipv6Address loopback ("::1");
586  return loopback;
587 }
588 
590 {
592  static Ipv6Address zero ("::");
593  return zero;
594 }
595 
597 {
599  static Ipv6Address any ("::");
600  return any;
601 }
602 
604 {
606  static Ipv6Address ones ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
607  return ones;
608 }
609 
610 void Ipv6Address::GetBytes (uint8_t buf[16]) const
611 {
612  NS_LOG_FUNCTION (this << &buf);
613  memcpy (buf, m_address, 16);
614 }
615 
617 {
618  NS_LOG_FUNCTION (this);
619  Ipv6Address linkLocal ("fe80::0");
620  if (!IsMulticast () && ((Ipv6Address*)this)->CombinePrefix (Ipv6Prefix (64)) == linkLocal)
621  {
622  return true;
623  }
624  return false;
625 }
626 
627 bool Ipv6Address::IsEqual (const Ipv6Address& other) const
628 {
629  NS_LOG_FUNCTION (this << other);
630  if (!memcmp (m_address, other.m_address, 16))
631  {
632  return true;
633  }
634  return false;
635 }
636 
637 std::ostream& operator << (std::ostream& os, Ipv6Address const& address)
638 {
639  address.Print (os);
640  return os;
641 }
642 
643 std::istream& operator >> (std::istream& is, Ipv6Address& address)
644 {
645  std::string str;
646  is >> str;
647  address = Ipv6Address (str.c_str ());
648  return is;
649 }
650 
652 {
653  NS_LOG_FUNCTION (this);
654  memset (m_prefix, 0x00, 16);
655 }
656 
657 Ipv6Prefix::Ipv6Prefix (char const* prefix)
658 {
659  NS_LOG_FUNCTION (this << prefix);
660  AsciiToIpv6Host (prefix, m_prefix);
661 }
662 
663 Ipv6Prefix::Ipv6Prefix (uint8_t prefix[16])
664 {
665  NS_LOG_FUNCTION (this << &prefix);
666  memcpy (m_prefix, prefix, 16);
667 }
668 
669 Ipv6Prefix::Ipv6Prefix (uint8_t prefix)
670 {
671  NS_LOG_FUNCTION (this << static_cast<uint32_t> (prefix));
672  unsigned int nb=0;
673  unsigned int mod=0;
674  unsigned int i=0;
675 
676  memset (m_prefix, 0x00, 16);
677 
678  NS_ASSERT (prefix <= 128);
679 
680  nb = prefix / 8;
681  mod = prefix % 8;
682 
683  // protect memset with 'nb > 0' check to suppress
684  // __warn_memset_zero_len compiler errors in some gcc>4.5.x
685  if (nb > 0)
686  {
687  memset (m_prefix, 0xff, nb);
688  }
689  if (mod)
690  {
691  m_prefix[nb] = 0xff << (8-mod);
692  }
693 
694  if (nb < 16)
695  {
696  nb++;
697  for (i = nb; i < 16; i++)
698  {
699  m_prefix[i] = 0x00;
700  }
701  }
702 }
703 
705 {
706  memcpy (m_prefix, prefix.m_prefix, 16);
707 }
708 
710 {
711  memcpy (m_prefix, prefix->m_prefix, 16);
712 }
713 
715 {
716  /* do nothing */
717  NS_LOG_FUNCTION (this);
718 }
719 
721 {
722  NS_LOG_FUNCTION (this << a << b);
723  uint8_t addrA[16];
724  uint8_t addrB[16];
725  unsigned int i = 0;
726 
727  a.GetBytes (addrA);
728  b.GetBytes (addrB);
729 
730  /* a little bit ugly... */
731  for (i = 0; i < 16; i++)
732  {
733  if ((addrA[i] & m_prefix[i]) != (addrB[i] & m_prefix[i]))
734  {
735  return false;
736  }
737  }
738  return true;
739 }
740 
741 void Ipv6Prefix::Print (std::ostream &os) const
742 {
743  NS_LOG_FUNCTION (this << &os);
744  os << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[0]
745  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[1] << ":"
746  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[2]
747  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[3] << ":"
748  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[4]
749  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[5] << ":"
750  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[6]
751  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[7] << ":"
752  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[8]
753  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[9] << ":"
754  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[10]
755  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[11] << ":"
756  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[12]
757  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[13] << ":"
758  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[14]
759  << std::hex << std::setw (2) << std::setfill ('0') << (unsigned int) m_prefix[15];
760 }
761 
763 {
765  static Ipv6Prefix prefix ((uint8_t)128);
766  return prefix;
767 }
768 
770 {
772  static Ipv6Prefix ones ((uint8_t)128);
773  return ones;
774 }
775 
777 {
779  static Ipv6Prefix prefix ((uint8_t)0);
780  return prefix;
781 }
782 
783 void Ipv6Prefix::GetBytes (uint8_t buf[16]) const
784 {
785  NS_LOG_FUNCTION (this << &buf);
786  memcpy (buf, m_prefix, 16);
787 }
788 
790 {
791  NS_LOG_FUNCTION (this);
792  uint8_t i = 0;
793  uint8_t prefixLength = 0;
794 
795  for(i = 0; i < 16; i++)
796  {
797  uint8_t mask = m_prefix[i];
798 
799  while(mask != 0)
800  {
801  mask = mask << 1;
802  prefixLength++;
803  }
804  }
805 
806  return prefixLength;
807 }
808 
809 bool Ipv6Prefix::IsEqual (const Ipv6Prefix& other) const
810 {
811  if (!memcmp (m_prefix, other.m_prefix, 16))
812  {
813  return true;
814  }
815  return false;
816 }
817 
818 std::ostream& operator << (std::ostream& os, Ipv6Prefix const& prefix)
819 {
820  prefix.Print (os);
821  return os;
822 }
823 
824 std::istream& operator >> (std::istream& is, Ipv6Prefix& prefix)
825 {
826  std::string str;
827  is >> str;
828  prefix = Ipv6Prefix (str.c_str ());
829  return is;
830 }
831 
832 bool operator == (Ipv6Prefix const &a, Ipv6Prefix const &b)
833 {
834  return a.IsEqual (b);
835 }
836 
837 bool operator != (Ipv6Prefix const &a, Ipv6Prefix const &b)
838 {
839  return !a.IsEqual (b);
840 }
841 
843 {
844  uint8_t buf[16];
845 
846  x.GetBytes (buf);
847 
848  return lookuphash (buf, sizeof (buf), 0);
849 }
850 
853 
854 } /* namespace ns3 */
855