// -*- c-basic-offset: 4; related-file-name: "../include/click/ip6address.hh" -*-
/*
* ip6address.{cc,hh} -- an IP6 address class. Useful for its hashcode()
* method
* Peilei Fan, Eddie Kohler
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include <click/glue.hh>
#include <click/ip6address.hh>
#include <click/ipaddress.hh>
#include <click/straccum.hh>
#include <click/confparse.hh>
CLICK_DECLS
IP6Address::IP6Address()
{
static_assert(sizeof(struct click_ip6) == 40);
for (int i = 0; i < 4; i++)
_addr.s6_addr32[i] = 0;
}
IP6Address::IP6Address(const unsigned char *data)
{
const unsigned *udata = reinterpret_cast<const unsigned *>(data);
for (int i = 0; i < 4; i++)
_addr.s6_addr32[i] = udata[i];
}
IP6Address::IP6Address(IPAddress ip)
{
const unsigned char *udata = ip.data();
// for (int i=0; i<10; i++)
// _addr.s6_addr[i] = 0;
// _addr.s6_addr[10]=0xff;
// _addr.s6_addr[11]=0xff;
for (int i=0; i<12; i++)
_addr.s6_addr[i] = 0;
for (int i=0; i<4; i++)
_addr.s6_addr[12+i] = udata[i];
}
IP6Address::IP6Address(const String &str)
{
if (!cp_ip6_address(str, this))
for (int i = 0; i < 4; i++)
_addr.s6_addr32[i] = 0;
}
IP6Address
IP6Address::make_prefix(int prefix)
{
assert(prefix >= 0 && prefix <= 128);
static const unsigned char data[] = { 0, 128, 192, 224, 240, 248, 252, 254, 255 };
IP6Address a;
for (int i = 0; i < 16 && prefix > 0; i++, prefix -= 8)
a._addr.s6_addr[i] = (prefix > 8 ? 255 : data[prefix]);
return a;
}
int
IP6Address::mask_to_prefix_len() const
{
// check that prefix is 0xFFFFFFFF
int word = 0;
while (word < 4 && _addr.s6_addr32[word] == 0xFFFFFFFFU)
word++;
// check that suffix is zeros
int zero_word = word + 1;
while (zero_word < 4 && _addr.s6_addr32[zero_word] == 0)
zero_word++;
if (zero_word < 4)
return -1;
// check swing word
int prefix = IPAddress(_addr.s6_addr32[word]).mask_to_prefix_len();
return prefix + (prefix >= 0 ? word * 32 : 0);
}
bool
IP6Address::ether_address(EtherAddress &mac) const
{
/*
* embedded mac address look like this:
* nnnn:nnnn:nnnn:nnnn:xxxx:xxFF:FExx:xxxx
* where xx's are the mac address.
*/
if (_addr.s6_addr[11] == 0xFF && _addr.s6_addr[12] == 0xFE) {
unsigned char *d = mac.data();
d[0] = _addr.s6_addr[8];
d[1] = _addr.s6_addr[9];
d[2] = _addr.s6_addr[10];
d[3] = _addr.s6_addr[13];
d[4] = _addr.s6_addr[14];
d[5] = _addr.s6_addr[15];
return true;
} else
return false;
}
bool
IP6Address::ip4_address(IPAddress &ip4) const
{
if (_addr.s6_addr32[0] == 0 && _addr.s6_addr32[1] == 0
&& (_addr.s6_addr32[2] == 0 || _addr.s6_addr32[2] == htonl(0x0000FFFFU))) {
ip4 = IPAddress(_addr.s6_addr32[3]);
return true;
} else
return false;
}
String
IP6Address::unparse() const
{
char buf[48];
// do some work to print the address well
if (_addr.s6_addr32[0] == 0 && _addr.s6_addr32[1] == 0) {
if (_addr.s6_addr32[2] == 0 && _addr.s6_addr32[3] == 0)
return String::stable_string("::", 2); // empty address
else if (_addr.s6_addr32[2] == 0) {
sprintf(buf, "::%d.%d.%d.%d", _addr.s6_addr[12], _addr.s6_addr[13],
_addr.s6_addr[14], _addr.s6_addr[15]);
return String(buf);
} else if (_addr.s6_addr32[2] == htonl(0x0000FFFFU)) {
sprintf(buf, "::FFFF:%d.%d.%d.%d", _addr.s6_addr[12], _addr.s6_addr[13],
_addr.s6_addr[14], _addr.s6_addr[15]);
return String(buf);
}
}
char *s = buf;
int word;
for (word = 0; word < 8 && _addr.s6_addr16[word] != 0; word++)
s += sprintf(s, (word ? ":%X" : "%X"), ntohs(_addr.s6_addr16[word]));
if (word == 0 || (word < 7 && _addr.s6_addr16[word + 1] == 0)) {
*s++ = ':';
while (word < 8 && _addr.s6_addr16[word] == 0)
word++;
if (word == 8)
*s++ = ':';
}
for (; word < 8; word++)
s += sprintf(s, ":%X", ntohs(_addr.s6_addr16[word]));
return String(buf, s - buf);
}
String
IP6Address::unparse_expanded() const
{
char buf[48];
sprintf(buf, "%X:%X:%X:%X:%X:%X:%X:%X",
ntohs(_addr.s6_addr16[0]), ntohs(_addr.s6_addr16[1]),
ntohs(_addr.s6_addr16[2]), ntohs(_addr.s6_addr16[3]),
ntohs(_addr.s6_addr16[4]), ntohs(_addr.s6_addr16[5]),
ntohs(_addr.s6_addr16[6]), ntohs(_addr.s6_addr16[7]));
return String(buf);
}
StringAccum &
operator<<(StringAccum &sa, const IP6Address &a)
{
return (sa << a.unparse());
}
// those two methods will calculate the checksum field of ICMP6 Message.
// The checksum is the 16-bit one's complement
// of the one's complement sum of the entire ICMPv6 message starting with the
// ICMPv6 message type field, prepended with a "pseudo-header" of IPv6 header
// fields, as specified in [IPv6, section 8.1]. The Next Header value used in
// the pseudo-header is 58 (i.e. 0x3a). (NOTE: the inclusion of a pseudo-header in the
// ICMPv6 checksum is a change from IPv4; see [RFC 2460] for the rationale
// for this change.)
// A "pseudo-header" include src and dst address of ipv6 header, packet length,
// protocal field (for ICMP, it is 58) field. Packet length is the
// payloadlength from the IPv6 header, minus the length of any extension
// header present between the IPv6 header and the upper-layer header.
// The following methods only differ at how it deal with ip6 address, i.e. add 32 bit
// a time or 16 bits a time.
uint16_t
in6_fast_cksum(const struct click_in6_addr *saddr,
const struct click_in6_addr *daddr,
uint16_t len,
uint8_t proto,
uint16_t ori_csum,
const unsigned char *addr,
uint16_t len2)
{
uint16_t ulen;
uint16_t uproto;
uint16_t answer = 0;
uint32_t csum =0;
uint32_t carry;
//get the sum of source and destination address
for (int i=0; i<4; i++) {
csum += ntohl(saddr->s6_addr32[i]);
carry = (csum < ntohl(saddr->s6_addr32[i]));
csum += carry;
}
for (int i=0; i<4; i++) {
csum += ntohl(daddr->s6_addr32[i]);
carry = (csum < ntohl(daddr->s6_addr32[i]));
csum += carry;
}
//get the sum of other fields: packet length, protocal
ulen = ntohs(len);
csum += ulen;
uproto = proto;
csum += uproto;
//get the sum of the ICMP6 package
uint16_t nleft = ntohs(len2);
const uint16_t *w = (const uint16_t *)addr;
while (nleft > 1) {
uint16_t w2=*w++;
csum += ntohs(w2);
nleft -=2;
}
//mop up an odd byte, if necessary
if (nleft == 1) {
*(unsigned char *)(&answer) = *(const unsigned char *)w ;
csum += ntohs(answer);
}
csum -= ntohs(ori_csum); //get rid of the effect of ori_csum in the calculation
// fold >=32-bit csum to 16-bits
while (csum>>16) {
csum = (csum & 0xffff) + (csum >> 16);
}
answer = ~csum; // truncate to 16 bits
return answer;
}
//This is the slow way for in6_cksum
unsigned short
in6_cksum(const struct click_in6_addr *saddr,
const struct click_in6_addr *daddr,
uint16_t len,
uint8_t proto,
uint16_t ori_csum,
unsigned char *addr,
uint16_t len2)
{
uint16_t ulen;
uint16_t uproto;
uint16_t answer = 0;
uint32_t csum =0;
//get the sum of source and destination address
for (int i=0; i<8; i++) {
csum += ntohs(saddr->s6_addr16[i]);
}
for (int i=0; i<8; i++) {
csum += ntohs(daddr->s6_addr16[i]);
}
//get the sum of other fields: packet length, protocal
ulen = ntohs(len);
csum += ulen;
uproto = proto;
csum += uproto;
//get the sum of the ICMP6 package
uint16_t nleft = ntohs(len2);
const uint16_t *w = (const uint16_t *)addr;
while (nleft > 1) {
uint16_t w2=*w++;
csum += ntohs(w2);
nleft -=2;
}
//mop up an odd byte, if necessary
if (nleft == 1) {
*(unsigned char *)(&answer) = *(const unsigned char *)w ;
csum += ntohs(answer);
}
csum -= ntohs(ori_csum); //get rid of the effect of ori_csum in the calculation
// fold >=32-bit csum to 16-bits
while (csum>>16) {
csum = (csum & 0xffff) + (csum >> 16);
}
answer = ~csum; // truncate to 16 bits
return answer;
}
CLICK_ENDDECLS
syntax highlighted by Code2HTML, v. 0.9.1