1282 lines
30 KiB
C++
1282 lines
30 KiB
C++
/*
|
|
* Copyright (c) 2007-2008 Louis Pasteur University
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
|
|
*/
|
|
|
|
// Part of the Ipv6Address::Print function has been adapted from inet_ntop6 Linux function.
|
|
// See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html
|
|
// Author: Paul Vixie, 1996.
|
|
// The inet_ntop6 function was under the copyright below, which is
|
|
// compatible with GPLv2, see http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses.
|
|
|
|
/* Copyright (c) 1996 by Internet Software Consortium.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "ipv6-address.h"
|
|
|
|
#include "mac16-address.h"
|
|
#include "mac48-address.h"
|
|
#include "mac64-address.h"
|
|
|
|
#include "ns3/assert.h"
|
|
#include "ns3/log.h"
|
|
|
|
#include <iomanip>
|
|
#include <memory.h>
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("Ipv6Address");
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{ /* } */
|
|
#endif
|
|
|
|
/**
|
|
* \brief Get a hash key.
|
|
* \param k the key
|
|
* \param length the length of the key
|
|
* \param level the previous hash, or an arbitrary value
|
|
* \return hash
|
|
* \note Adapted from Jens Jakobsen implementation (chillispot).
|
|
*/
|
|
static uint32_t lookuphash(unsigned char* k, uint32_t length, uint32_t level)
|
|
{
|
|
NS_LOG_FUNCTION(k << length << level);
|
|
#define mix(a, b, c) \
|
|
({ \
|
|
(a) -= (b); \
|
|
(a) -= (c); \
|
|
(a) ^= ((c) >> 13); \
|
|
(b) -= (c); \
|
|
(b) -= (a); \
|
|
(b) ^= ((a) << 8); \
|
|
(c) -= (a); \
|
|
(c) -= (b); \
|
|
(c) ^= ((b) >> 13); \
|
|
(a) -= (b); \
|
|
(a) -= (c); \
|
|
(a) ^= ((c) >> 12); \
|
|
(b) -= (c); \
|
|
(b) -= (a); \
|
|
(b) ^= ((a) << 16); \
|
|
(c) -= (a); \
|
|
(c) -= (b); \
|
|
(c) ^= ((b) >> 5); \
|
|
(a) -= (b); \
|
|
(a) -= (c); \
|
|
(a) ^= ((c) >> 3); \
|
|
(b) -= (c); \
|
|
(b) -= (a); \
|
|
(b) ^= ((a) << 10); \
|
|
(c) -= (a); \
|
|
(c) -= (b); \
|
|
(c) ^= ((b) >> 15); \
|
|
})
|
|
|
|
typedef uint32_t ub4; /* unsigned 4-byte quantities */
|
|
uint32_t a = 0;
|
|
uint32_t b = 0;
|
|
uint32_t c = 0;
|
|
uint32_t len = 0;
|
|
|
|
/* Set up the internal state */
|
|
len = length;
|
|
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
|
c = level; /* the previous hash value */
|
|
|
|
/* handle most of the key */
|
|
while (len >= 12)
|
|
{
|
|
a += (k[0] + ((ub4)k[1] << 8) + ((ub4)k[2] << 16) + ((ub4)k[3] << 24));
|
|
b += (k[4] + ((ub4)k[5] << 8) + ((ub4)k[6] << 16) + ((ub4)k[7] << 24));
|
|
c += (k[8] + ((ub4)k[9] << 8) + ((ub4)k[10] << 16) + ((ub4)k[11] << 24));
|
|
mix(a, b, c);
|
|
k += 12;
|
|
len -= 12;
|
|
}
|
|
|
|
/* handle the last 11 bytes */
|
|
c += length;
|
|
switch (len) /* all the case statements fall through */
|
|
{
|
|
case 11:
|
|
c += ((ub4)k[10] << 24);
|
|
case 10:
|
|
c += ((ub4)k[9] << 16);
|
|
case 9:
|
|
c += ((ub4)k[8] << 8); /* the first byte of c is reserved for the length */
|
|
case 8:
|
|
b += ((ub4)k[7] << 24);
|
|
case 7:
|
|
b += ((ub4)k[6] << 16);
|
|
case 6:
|
|
b += ((ub4)k[5] << 8);
|
|
case 5:
|
|
b += k[4];
|
|
case 4:
|
|
a += ((ub4)k[3] << 24);
|
|
case 3:
|
|
a += ((ub4)k[2] << 16);
|
|
case 2:
|
|
a += ((ub4)k[1] << 8);
|
|
case 1:
|
|
a += k[0];
|
|
/* case 0: nothing left to add */
|
|
}
|
|
mix(a, b, c);
|
|
|
|
#undef mix
|
|
|
|
/* report the result */
|
|
return c;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* \brief Convert an IPv6 C-string into a 128-bit representation.
|
|
*
|
|
* \param address pointer to the char buffer with the address ascii representation
|
|
* \param addr the buffer to store the IPv6 address
|
|
*
|
|
* \return true if success, false otherwise (bad format, ...)
|
|
*
|
|
* \note This function is strongly inspired by inet_pton6() from Paul Vixie.
|
|
* \todo Handle IPv6 address with decimal value for last four bytes.
|
|
*/
|
|
static bool
|
|
AsciiToIpv6Host(const char* address, uint8_t addr[16])
|
|
{
|
|
NS_LOG_FUNCTION(address << &addr);
|
|
static const char xdigits_l[] = "0123456789abcdef";
|
|
static const char xdigits_u[] = "0123456789ABCDEF";
|
|
unsigned char tmp[16];
|
|
unsigned char* tp = tmp;
|
|
unsigned char* const endp = tp + 16;
|
|
unsigned char* colonp = nullptr;
|
|
const char* xdigits = nullptr;
|
|
#if 0
|
|
const char* curtok = 0;
|
|
#endif
|
|
int ch = 0;
|
|
int seen_xdigits = 0;
|
|
unsigned int val = 0;
|
|
|
|
memset(tp, 0x00, 16);
|
|
|
|
/* Leading :: requires some special handling. */
|
|
if (*address == ':')
|
|
{
|
|
if (*++address != ':')
|
|
{
|
|
return (0);
|
|
}
|
|
}
|
|
#if 0
|
|
curtok = address;
|
|
#endif
|
|
while ((ch = *address++) != '\0')
|
|
{
|
|
const char* pch = nullptr;
|
|
|
|
if ((pch = strchr((xdigits = xdigits_l), ch)) == nullptr)
|
|
{
|
|
pch = strchr((xdigits = xdigits_u), ch);
|
|
}
|
|
|
|
if (pch != nullptr)
|
|
{
|
|
val <<= 4;
|
|
val |= (pch - xdigits);
|
|
|
|
if (++seen_xdigits > 4)
|
|
{
|
|
return (0);
|
|
}
|
|
continue;
|
|
}
|
|
if (ch == ':')
|
|
{
|
|
#if 0
|
|
curtok = address;
|
|
#endif
|
|
|
|
if (!seen_xdigits)
|
|
{
|
|
if (colonp)
|
|
{
|
|
return (0);
|
|
}
|
|
colonp = tp;
|
|
continue;
|
|
}
|
|
|
|
if (endp - tp < 2)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
*tp++ = (unsigned char)(val >> 8) & 0xff;
|
|
*tp++ = (unsigned char)val & 0xff;
|
|
seen_xdigits = 0;
|
|
val = 0;
|
|
continue;
|
|
}
|
|
|
|
/* \todo Handle IPv4 mapped address (2001::192.168.0.1) */
|
|
#if 0
|
|
if (ch == '.' && (endp - tp > 3 /* NS_INADDRSZ - 1 */)) &&
|
|
inet_pton4 (curtok, tp) > 0)
|
|
{
|
|
tp += 4 /*NS_INADDRSZ*/;
|
|
seen_xdigits = 0;
|
|
break; /* '\0' was seen by inet_pton4(). */
|
|
}
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
if (seen_xdigits)
|
|
{
|
|
if (endp - tp < 2)
|
|
{
|
|
return (0);
|
|
}
|
|
*tp++ = (unsigned char)(val >> 8) & 0xff;
|
|
*tp++ = (unsigned char)val & 0xff;
|
|
}
|
|
|
|
if (colonp != nullptr)
|
|
{
|
|
/*
|
|
* Since some memmove ()'s erroneously fail to handle
|
|
* overlapping regions, we'll do the shift by hand.
|
|
*/
|
|
const int n = tp - colonp;
|
|
int i = 0;
|
|
|
|
if (tp == endp)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
for (i = 1; i <= n; i++)
|
|
{
|
|
endp[-i] = colonp[n - i];
|
|
colonp[n - i] = 0;
|
|
}
|
|
|
|
tp = endp;
|
|
}
|
|
|
|
if (tp != endp)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
memcpy(addr, tmp, 16);
|
|
return (1);
|
|
}
|
|
|
|
Ipv6Address::Ipv6Address()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
memset(m_address, 0x00, 16);
|
|
m_initialized = false;
|
|
}
|
|
|
|
Ipv6Address::Ipv6Address(const Ipv6Address& addr)
|
|
{
|
|
// Do not add function logging here, to avoid stack overflow
|
|
memcpy(m_address, addr.m_address, 16);
|
|
m_initialized = true;
|
|
}
|
|
|
|
Ipv6Address::Ipv6Address(const Ipv6Address* addr)
|
|
{
|
|
// Do not add function logging here, to avoid stack overflow
|
|
memcpy(m_address, addr->m_address, 16);
|
|
m_initialized = true;
|
|
}
|
|
|
|
Ipv6Address::Ipv6Address(const char* address)
|
|
{
|
|
NS_LOG_FUNCTION(this << address);
|
|
AsciiToIpv6Host(address, m_address);
|
|
m_initialized = true;
|
|
}
|
|
|
|
Ipv6Address::Ipv6Address(uint8_t address[16])
|
|
{
|
|
NS_LOG_FUNCTION(this << &address);
|
|
/* 128 bit => 16 bytes */
|
|
memcpy(m_address, address, 16);
|
|
m_initialized = true;
|
|
}
|
|
|
|
Ipv6Address::~Ipv6Address()
|
|
{
|
|
/* do nothing */
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
void
|
|
Ipv6Address::Set(const char* address)
|
|
{
|
|
NS_LOG_FUNCTION(this << address);
|
|
AsciiToIpv6Host(address, m_address);
|
|
m_initialized = true;
|
|
}
|
|
|
|
void
|
|
Ipv6Address::Set(uint8_t address[16])
|
|
{
|
|
/* 128 bit => 16 bytes */
|
|
NS_LOG_FUNCTION(this << &address);
|
|
memcpy(m_address, address, 16);
|
|
m_initialized = true;
|
|
}
|
|
|
|
void
|
|
Ipv6Address::Serialize(uint8_t buf[16]) const
|
|
{
|
|
NS_LOG_FUNCTION(this << &buf);
|
|
memcpy(buf, m_address, 16);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::Deserialize(const uint8_t buf[16])
|
|
{
|
|
NS_LOG_FUNCTION(&buf);
|
|
Ipv6Address ipv6((uint8_t*)buf);
|
|
ipv6.m_initialized = true;
|
|
return ipv6;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeIpv4MappedAddress(Ipv4Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
uint8_t buf[16] = {0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0xff,
|
|
0xff,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00};
|
|
addr.Serialize(&buf[12]);
|
|
return (Ipv6Address(buf));
|
|
}
|
|
|
|
Ipv4Address
|
|
Ipv6Address::GetIpv4MappedAddress() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
uint8_t buf[16];
|
|
Ipv4Address v4Addr;
|
|
|
|
Serialize(buf);
|
|
v4Addr = Ipv4Address::Deserialize(&buf[12]);
|
|
return (v4Addr);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Address addr, Ipv6Address prefix)
|
|
{
|
|
Ipv6Address ipv6Addr = Ipv6Address::GetAny();
|
|
|
|
if (Mac64Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress(Mac64Address::ConvertFrom(addr), prefix);
|
|
}
|
|
else if (Mac48Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress(Mac48Address::ConvertFrom(addr), prefix);
|
|
}
|
|
else if (Mac16Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress(Mac16Address::ConvertFrom(addr), prefix);
|
|
}
|
|
else if (Mac8Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredAddress(Mac8Address::ConvertFrom(addr), prefix);
|
|
}
|
|
|
|
if (ipv6Addr.IsAny())
|
|
{
|
|
NS_ABORT_MSG("Unknown address type");
|
|
}
|
|
return ipv6Addr;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Address addr, Ipv6Prefix prefix)
|
|
{
|
|
Ipv6Address ipv6PrefixAddr = Ipv6Address::GetOnes().CombinePrefix(prefix);
|
|
return MakeAutoconfiguredAddress(addr, ipv6PrefixAddr);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Mac16Address addr, Ipv6Address prefix)
|
|
{
|
|
NS_LOG_FUNCTION(addr << prefix);
|
|
Ipv6Address ret;
|
|
uint8_t buf[2];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
prefix.GetBytes(buf2);
|
|
memset(buf2 + 8, 0, 8);
|
|
|
|
memcpy(buf2 + 14, buf, 2);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Mac48Address addr, Ipv6Address prefix)
|
|
{
|
|
NS_LOG_FUNCTION(addr << prefix);
|
|
Ipv6Address ret;
|
|
uint8_t buf[16];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
prefix.GetBytes(buf2);
|
|
|
|
memcpy(buf2 + 8, buf, 3);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
memcpy(buf2 + 13, buf + 3, 3);
|
|
buf2[8] ^= 0x02;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Mac64Address addr, Ipv6Address prefix)
|
|
{
|
|
NS_LOG_FUNCTION(addr << prefix);
|
|
Ipv6Address ret;
|
|
uint8_t buf[8];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
prefix.GetBytes(buf2);
|
|
|
|
memcpy(buf2 + 8, buf, 8);
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredAddress(Mac8Address addr, Ipv6Address prefix)
|
|
{
|
|
NS_LOG_FUNCTION(addr << prefix);
|
|
Ipv6Address ret;
|
|
uint8_t buf[2];
|
|
uint8_t buf2[16];
|
|
|
|
buf[0] = 0;
|
|
addr.CopyTo(&buf[1]);
|
|
prefix.GetBytes(buf2);
|
|
memset(buf2 + 8, 0, 8);
|
|
|
|
memcpy(buf2 + 14, buf, 2);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Address addr)
|
|
{
|
|
Ipv6Address ipv6Addr = Ipv6Address::GetAny();
|
|
|
|
if (Mac64Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac64Address::ConvertFrom(addr));
|
|
}
|
|
else if (Mac48Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac48Address::ConvertFrom(addr));
|
|
}
|
|
else if (Mac16Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac16Address::ConvertFrom(addr));
|
|
}
|
|
else if (Mac8Address::IsMatchingType(addr))
|
|
{
|
|
ipv6Addr = Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac8Address::ConvertFrom(addr));
|
|
}
|
|
|
|
if (ipv6Addr.IsAny())
|
|
{
|
|
NS_ABORT_MSG("Unknown address type");
|
|
}
|
|
return ipv6Addr;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac16Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
Ipv6Address ret;
|
|
uint8_t buf[2];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
|
|
memset(buf2, 0x00, sizeof(buf2));
|
|
buf2[0] = 0xfe;
|
|
buf2[1] = 0x80;
|
|
memcpy(buf2 + 14, buf, 2);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac48Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
Ipv6Address ret;
|
|
uint8_t buf[16];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
|
|
memset(buf2, 0x00, sizeof(buf2));
|
|
buf2[0] = 0xfe;
|
|
buf2[1] = 0x80;
|
|
memcpy(buf2 + 8, buf, 3);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
memcpy(buf2 + 13, buf + 3, 3);
|
|
buf2[8] ^= 0x02;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac64Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
Ipv6Address ret;
|
|
uint8_t buf[8];
|
|
uint8_t buf2[16];
|
|
|
|
addr.CopyTo(buf);
|
|
|
|
memset(buf2, 0x00, sizeof(buf2));
|
|
buf2[0] = 0xfe;
|
|
buf2[1] = 0x80;
|
|
memcpy(buf2 + 8, buf, 8);
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeAutoconfiguredLinkLocalAddress(Mac8Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
Ipv6Address ret;
|
|
uint8_t buf[2];
|
|
uint8_t buf2[16];
|
|
|
|
buf[0] = 0;
|
|
addr.CopyTo(&buf[1]);
|
|
|
|
memset(buf2, 0x00, sizeof(buf2));
|
|
buf2[0] = 0xfe;
|
|
buf2[1] = 0x80;
|
|
memcpy(buf2 + 14, buf, 2);
|
|
buf2[11] = 0xff;
|
|
buf2[12] = 0xfe;
|
|
|
|
ret.Set(buf2);
|
|
return ret;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::MakeSolicitedAddress(Ipv6Address addr)
|
|
{
|
|
NS_LOG_FUNCTION(addr);
|
|
uint8_t buf[16];
|
|
uint8_t buf2[16];
|
|
Ipv6Address ret;
|
|
|
|
addr.Serialize(buf2);
|
|
|
|
memset(buf, 0x00, sizeof(buf));
|
|
buf[0] = 0xff;
|
|
buf[1] = 0x02;
|
|
buf[11] = 0x01;
|
|
buf[12] = 0xff;
|
|
buf[13] = buf2[13];
|
|
buf[14] = buf2[14];
|
|
buf[15] = buf2[15];
|
|
|
|
ret.Set(buf);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
Ipv6Address::Print(std::ostream& os) const
|
|
{
|
|
NS_LOG_FUNCTION(this << &os);
|
|
|
|
// note: part of this function has been adapted from inet_ntop6 Linux function.
|
|
// See http://www.net-snmp.org/dev/agent/inet__ntop_8c_source.html
|
|
// Author: Paul Vixie, 1996.
|
|
|
|
if (IsIpv4MappedAddress())
|
|
{
|
|
os << "::ffff:" << (unsigned int)m_address[12] << "." << (unsigned int)m_address[13] << "."
|
|
<< (unsigned int)m_address[14] << "." << (unsigned int)m_address[15];
|
|
return;
|
|
}
|
|
|
|
uint16_t address[8];
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
address[i] = (uint16_t(m_address[2 * i]) << 8) | uint16_t(m_address[2 * i + 1]);
|
|
}
|
|
|
|
int8_t bestBase = -1;
|
|
int8_t bestLen = 0;
|
|
int8_t curBase = -1;
|
|
int8_t curLen = 0;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (address[i] == 0)
|
|
{
|
|
if (curBase == -1)
|
|
{
|
|
curBase = i;
|
|
curLen = 1;
|
|
}
|
|
else
|
|
{
|
|
curLen++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (curBase != -1)
|
|
{
|
|
if (bestBase == -1 || curLen > bestLen)
|
|
{
|
|
bestBase = curBase;
|
|
bestLen = curLen;
|
|
}
|
|
curBase = -1;
|
|
}
|
|
}
|
|
}
|
|
if (curBase != -1)
|
|
{
|
|
if (bestBase == -1 || curLen > bestLen)
|
|
{
|
|
bestBase = curBase;
|
|
bestLen = curLen;
|
|
}
|
|
}
|
|
if (bestBase != -1 && bestLen < 2)
|
|
{
|
|
bestBase = -1;
|
|
}
|
|
|
|
for (i = 0; i < 8;)
|
|
{
|
|
// Are we inside the best run of 0x00's?
|
|
if (i == bestBase)
|
|
{
|
|
os << ':';
|
|
i += bestLen;
|
|
continue;
|
|
}
|
|
// Are we following an initial run of 0x00s or any real hex?
|
|
if (i != 0)
|
|
{
|
|
os << ':';
|
|
}
|
|
os << std::hex << (unsigned int)address[i];
|
|
i++;
|
|
}
|
|
// Was it a trailing run of 0x00's?
|
|
if (bestBase != -1 && (bestBase + bestLen) == 8)
|
|
{
|
|
os << ':';
|
|
}
|
|
os << std::dec;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsLocalhost() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address localhost("::1");
|
|
return (*this == localhost);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsMulticast() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
if (m_address[0] == 0xff)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsLinkLocalMulticast() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
if (m_address[0] == 0xff && m_address[1] == 0x02)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsIpv4MappedAddress() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static uint8_t v4MappedPrefix[12] =
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
|
|
if (memcmp(m_address, v4MappedPrefix, sizeof(v4MappedPrefix)) == 0)
|
|
{
|
|
return (true);
|
|
}
|
|
return (false);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::CombinePrefix(const Ipv6Prefix& prefix) const
|
|
{
|
|
NS_LOG_FUNCTION(this << prefix);
|
|
Ipv6Address ipv6;
|
|
uint8_t addr[16];
|
|
uint8_t pref[16];
|
|
unsigned int i = 0;
|
|
|
|
memcpy(addr, m_address, 16);
|
|
((Ipv6Prefix)prefix).GetBytes(pref);
|
|
|
|
/* a little bit ugly... */
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
addr[i] = addr[i] & pref[i];
|
|
}
|
|
ipv6.Set(addr);
|
|
return ipv6;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsSolicitedMulticast() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
|
|
static Ipv6Address documentation("ff02::1:ff00:0");
|
|
if (CombinePrefix(Ipv6Prefix(104)) == documentation)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsAllNodesMulticast() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address allNodesI("ff01::1");
|
|
static Ipv6Address allNodesL("ff02::1");
|
|
static Ipv6Address allNodesR("ff03::1");
|
|
return (*this == allNodesI || *this == allNodesL || *this == allNodesR);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsAllRoutersMulticast() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address allroutersI("ff01::2");
|
|
static Ipv6Address allroutersL("ff02::2");
|
|
static Ipv6Address allroutersR("ff03::2");
|
|
static Ipv6Address allroutersS("ff05::2");
|
|
return (*this == allroutersI || *this == allroutersL || *this == allroutersR ||
|
|
*this == allroutersS);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsAny() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address any("::");
|
|
return (*this == any);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsDocumentation() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address documentation("2001:db8::0");
|
|
if (CombinePrefix(Ipv6Prefix(32)) == documentation)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::HasPrefix(const Ipv6Prefix& prefix) const
|
|
{
|
|
NS_LOG_FUNCTION(this << prefix);
|
|
|
|
Ipv6Address masked = CombinePrefix(prefix);
|
|
Ipv6Address reference = Ipv6Address::GetOnes().CombinePrefix(prefix);
|
|
|
|
return (masked == reference);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsMatchingType(const Address& address)
|
|
{
|
|
NS_LOG_FUNCTION(address);
|
|
return address.CheckCompatible(GetType(), 16);
|
|
}
|
|
|
|
Ipv6Address::operator Address() const
|
|
{
|
|
return ConvertTo();
|
|
}
|
|
|
|
Address
|
|
Ipv6Address::ConvertTo() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
uint8_t buf[16];
|
|
Serialize(buf);
|
|
return Address(GetType(), buf, 16);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::ConvertFrom(const Address& address)
|
|
{
|
|
NS_LOG_FUNCTION(address);
|
|
NS_ASSERT(address.CheckCompatible(GetType(), 16));
|
|
uint8_t buf[16];
|
|
address.CopyTo(buf);
|
|
return Deserialize(buf);
|
|
}
|
|
|
|
uint8_t
|
|
Ipv6Address::GetType()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static uint8_t type = Address::Register();
|
|
return type;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetAllNodesMulticast()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address nmc("ff02::1");
|
|
return nmc;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetAllRoutersMulticast()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address rmc("ff02::2");
|
|
return rmc;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetAllHostsMulticast()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address hmc("ff02::3");
|
|
return hmc;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetLoopback()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address loopback("::1");
|
|
return loopback;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetZero()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address zero("::");
|
|
return zero;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetAny()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address any("::");
|
|
return any;
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Address::GetOnes()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Address ones("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
|
|
return ones;
|
|
}
|
|
|
|
void
|
|
Ipv6Address::GetBytes(uint8_t buf[16]) const
|
|
{
|
|
NS_LOG_FUNCTION(this << &buf);
|
|
memcpy(buf, m_address, 16);
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsLinkLocal() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
static Ipv6Address linkLocal("fe80::0");
|
|
if (CombinePrefix(Ipv6Prefix(64)) == linkLocal)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Ipv6Address::IsInitialized() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
return (m_initialized);
|
|
}
|
|
|
|
std::ostream&
|
|
operator<<(std::ostream& os, const Ipv6Address& address)
|
|
{
|
|
address.Print(os);
|
|
return os;
|
|
}
|
|
|
|
std::istream&
|
|
operator>>(std::istream& is, Ipv6Address& address)
|
|
{
|
|
std::string str;
|
|
is >> str;
|
|
address = Ipv6Address(str.c_str());
|
|
return is;
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
memset(m_prefix, 0x00, 16);
|
|
m_prefixLength = 64;
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(const char* prefix)
|
|
{
|
|
NS_LOG_FUNCTION(this << prefix);
|
|
AsciiToIpv6Host(prefix, m_prefix);
|
|
m_prefixLength = GetMinimumPrefixLength();
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(uint8_t prefix[16])
|
|
{
|
|
NS_LOG_FUNCTION(this << &prefix);
|
|
memcpy(m_prefix, prefix, 16);
|
|
m_prefixLength = GetMinimumPrefixLength();
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(const char* prefix, uint8_t prefixLength)
|
|
{
|
|
NS_LOG_FUNCTION(this << prefix);
|
|
AsciiToIpv6Host(prefix, m_prefix);
|
|
|
|
uint8_t autoLength = GetMinimumPrefixLength();
|
|
NS_ASSERT_MSG(autoLength <= prefixLength,
|
|
"Ipv6Prefix: address and prefix are not compatible: " << Ipv6Address(prefix)
|
|
<< "/" << +prefixLength);
|
|
|
|
m_prefixLength = prefixLength;
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(uint8_t prefix[16], uint8_t prefixLength)
|
|
{
|
|
NS_LOG_FUNCTION(this << &prefix);
|
|
memcpy(m_prefix, prefix, 16);
|
|
|
|
uint8_t autoLength = GetMinimumPrefixLength();
|
|
NS_ASSERT_MSG(autoLength <= prefixLength,
|
|
"Ipv6Prefix: address and prefix are not compatible: " << Ipv6Address(prefix)
|
|
<< "/" << +prefixLength);
|
|
|
|
m_prefixLength = prefixLength;
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(uint8_t prefix)
|
|
{
|
|
NS_LOG_FUNCTION(this << static_cast<uint32_t>(prefix));
|
|
unsigned int nb = 0;
|
|
unsigned int mod = 0;
|
|
unsigned int i = 0;
|
|
|
|
memset(m_prefix, 0x00, 16);
|
|
m_prefixLength = prefix;
|
|
|
|
NS_ASSERT(prefix <= 128);
|
|
|
|
nb = prefix / 8;
|
|
mod = prefix % 8;
|
|
|
|
// protect memset with 'nb > 0' check to suppress
|
|
// __warn_memset_zero_len compiler errors in some gcc>4.5.x
|
|
if (nb > 0)
|
|
{
|
|
memset(m_prefix, 0xff, nb);
|
|
}
|
|
if (mod)
|
|
{
|
|
m_prefix[nb] = 0xff << (8 - mod);
|
|
}
|
|
|
|
if (nb < 16)
|
|
{
|
|
nb++;
|
|
for (i = nb; i < 16; i++)
|
|
{
|
|
m_prefix[i] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(const Ipv6Prefix& prefix)
|
|
{
|
|
memcpy(m_prefix, prefix.m_prefix, 16);
|
|
m_prefixLength = prefix.m_prefixLength;
|
|
}
|
|
|
|
Ipv6Prefix::Ipv6Prefix(const Ipv6Prefix* prefix)
|
|
{
|
|
memcpy(m_prefix, prefix->m_prefix, 16);
|
|
m_prefixLength = prefix->m_prefixLength;
|
|
}
|
|
|
|
Ipv6Prefix::~Ipv6Prefix()
|
|
{
|
|
/* do nothing */
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
bool
|
|
Ipv6Prefix::IsMatch(Ipv6Address a, Ipv6Address b) const
|
|
{
|
|
NS_LOG_FUNCTION(this << a << b);
|
|
uint8_t addrA[16];
|
|
uint8_t addrB[16];
|
|
unsigned int i = 0;
|
|
|
|
a.GetBytes(addrA);
|
|
b.GetBytes(addrB);
|
|
|
|
/* a little bit ugly... */
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
if ((addrA[i] & m_prefix[i]) != (addrB[i] & m_prefix[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
Ipv6Prefix::Print(std::ostream& os) const
|
|
{
|
|
NS_LOG_FUNCTION(this << &os);
|
|
|
|
os << "/" << (unsigned int)GetPrefixLength();
|
|
}
|
|
|
|
Ipv6Prefix
|
|
Ipv6Prefix::GetLoopback()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Prefix prefix((uint8_t)128);
|
|
return prefix;
|
|
}
|
|
|
|
Ipv6Prefix
|
|
Ipv6Prefix::GetOnes()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Prefix ones((uint8_t)128);
|
|
return ones;
|
|
}
|
|
|
|
Ipv6Prefix
|
|
Ipv6Prefix::GetZero()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static Ipv6Prefix prefix((uint8_t)0);
|
|
return prefix;
|
|
}
|
|
|
|
void
|
|
Ipv6Prefix::GetBytes(uint8_t buf[16]) const
|
|
{
|
|
NS_LOG_FUNCTION(this << &buf);
|
|
memcpy(buf, m_prefix, 16);
|
|
}
|
|
|
|
Ipv6Address
|
|
Ipv6Prefix::ConvertToIpv6Address() const
|
|
{
|
|
uint8_t prefixBytes[16];
|
|
memcpy(prefixBytes, m_prefix, 16);
|
|
|
|
Ipv6Address convertedPrefix = Ipv6Address(prefixBytes);
|
|
return convertedPrefix;
|
|
}
|
|
|
|
uint8_t
|
|
Ipv6Prefix::GetPrefixLength() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
return m_prefixLength;
|
|
}
|
|
|
|
void
|
|
Ipv6Prefix::SetPrefixLength(uint8_t prefixLength)
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
m_prefixLength = prefixLength;
|
|
}
|
|
|
|
uint8_t
|
|
Ipv6Prefix::GetMinimumPrefixLength() const
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
|
|
uint8_t prefixLength = 0;
|
|
bool stop = false;
|
|
|
|
for (int8_t i = 15; i >= 0 && !stop; i--)
|
|
{
|
|
uint8_t mask = m_prefix[i];
|
|
|
|
for (uint8_t j = 0; j < 8 && !stop; j++)
|
|
{
|
|
if ((mask & 1) == 0)
|
|
{
|
|
mask = mask >> 1;
|
|
prefixLength++;
|
|
}
|
|
else
|
|
{
|
|
stop = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 128 - prefixLength;
|
|
}
|
|
|
|
std::ostream&
|
|
operator<<(std::ostream& os, const Ipv6Prefix& prefix)
|
|
{
|
|
prefix.Print(os);
|
|
return os;
|
|
}
|
|
|
|
std::istream&
|
|
operator>>(std::istream& is, Ipv6Prefix& prefix)
|
|
{
|
|
std::string str;
|
|
is >> str;
|
|
prefix = Ipv6Prefix(str.c_str());
|
|
return is;
|
|
}
|
|
|
|
size_t
|
|
Ipv6AddressHash::operator()(const Ipv6Address& x) const
|
|
{
|
|
uint8_t buf[16];
|
|
|
|
x.GetBytes(buf);
|
|
|
|
return lookuphash(buf, sizeof(buf), 0);
|
|
}
|
|
|
|
ATTRIBUTE_HELPER_CPP(Ipv6Address);
|
|
ATTRIBUTE_HELPER_CPP(Ipv6Prefix);
|
|
|
|
} /* namespace ns3 */
|