diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 35b590bb..b3e13311 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*; } {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { + ip4_addr a; + if (!ip4_pton(yytext, &a)) + cf_error("Invalid IPv4 address %s", yytext); + #ifdef IPV6 - if (ipv4_pton_u32(yytext, &cf_lval.i32)) - return RTRID; - cf_error("Invalid IPv4 address %s", yytext); + cf_lval.i32 = ip4_to_u32(a); + return RTRID; #else - if (ip_pton(yytext, &cf_lval.a)) - return IPA; - cf_error("Invalid IP address %s", yytext); + cf_lval.a = ipa_from_ip4(a); + return IPA; #endif } ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { #ifdef IPV6 - if (ip_pton(yytext, &cf_lval.a)) + if (ipa_pton(yytext, &cf_lval.a)) return IPA; - cf_error("Invalid IP address %s", yytext); + cf_error("Invalid IPv6 address %s", yytext); #else cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported"); #endif diff --git a/conf/confbase.Y b/conf/confbase.Y index 49831b1a..16a493e9 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -187,7 +187,7 @@ pxlen: $$ = $2; } | ':' ipa { - $$ = ipa_mklen($2); + $$ = ipa_masklen($2); if ($$ < 0) cf_error("Invalid netmask %I", $2); } ; diff --git a/lib/Modules b/lib/Modules index 7131f0b2..7254df2d 100644 --- a/lib/Modules +++ b/lib/Modules @@ -3,13 +3,6 @@ bitops.c bitops.h ip.h ip.c -#ifdef IPV6 -ipv6.c -ipv6.h -#else -ipv4.c -ipv4.h -#endif lists.c lists.h md5.c diff --git a/lib/ip.c b/lib/ip.c index aa61553e..01edf0d5 100644 --- a/lib/ip.c +++ b/lib/ip.c @@ -1,14 +1,11 @@ /* - * BIRD Library -- IP address routines common for IPv4 and IPv6 + * BIRD Library -- IP address functions * * (c) 1998--2000 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ -#include "nest/bird.h" -#include "lib/ip.h" - /** * DOC: IP addresses * @@ -18,6 +15,333 @@ * they must be manipulated using the following functions and macros. */ +#include + +#include "nest/bird.h" +#include "lib/ip.h" + + +int +ip6_compare(ip6_addr a, ip6_addr b) +{ + int i; + for (i=0; i<4; i++) + if (a.addr[i] > b.addr[i]) + return 1; + else if (a.addr[i] < b.addr[i]) + return -1; + return 0; +} + +ip6_addr +ip6_mkmask(uint n) +{ + ip6_addr a; + int i; + + for (i=0; i<4; i++) + { + if (!n) + a.addr[i] = 0; + else if (n >= 32) + { + a.addr[i] = ~0; + n -= 32; + } + else + { + a.addr[i] = u32_mkmask(n); + n = 0; + } + } + + return a; +} + +int +ip6_masklen(ip6_addr *a) +{ + int i, j, n; + + for (i=0, n=0; i<4; i++, n+=32) + if (a->addr[i] != ~0U) + { + j = u32_masklen(a->addr[i]); + if (j < 0) + return j; + n += j; + while (++i < 4) + if (a->addr[i]) + return -1; + break; + } + + return n; +} + +int +ip4_classify(ip4_addr ad) +{ + u32 a = _I(ad); + u32 b = a >> 24U; + + if (b && b <= 0xdf) + { + if (b == 0x7f) + return IADDR_HOST | SCOPE_HOST; + else if ((b == 0x0a) || + ((a & 0xffff0000) == 0xc0a80000) || + ((a & 0xfff00000) == 0xac100000)) + return IADDR_HOST | SCOPE_SITE; + else + return IADDR_HOST | SCOPE_UNIVERSE; + } + + if (b >= 0xe0 && b <= 0xef) + return IADDR_MULTICAST | SCOPE_UNIVERSE; + + if (a == 0xffffffff) + return IADDR_BROADCAST | SCOPE_LINK; + + return IADDR_INVALID; +} + +int +ip6_classify(ip6_addr *a) +{ + u32 x = a->addr[0]; + + if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ + return IADDR_HOST | SCOPE_UNIVERSE; + if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ + return IADDR_HOST | SCOPE_LINK; + if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ + return IADDR_HOST | SCOPE_SITE; + if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ + { + uint scope = (x >> 16) & 0x0f; + switch (scope) + { + case 1: return IADDR_MULTICAST | SCOPE_HOST; + case 2: return IADDR_MULTICAST | SCOPE_LINK; + case 5: return IADDR_MULTICAST | SCOPE_SITE; + case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; + case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; + default: return IADDR_MULTICAST | SCOPE_UNDEFINED; + } + } + + if (!x && !a->addr[1]) + { + u32 a2 = a->addr[2]; + u32 a3 = a->addr[3]; + + if (a2 == 0 && a3 == 1) + return IADDR_HOST | SCOPE_HOST; /* Loopback address */ + if (a2 == 0) + return ip4_classify(_MI4(a3)); /* IPv4 compatible addresses */ + if (a2 == 0xffff) + return ip4_classify(_MI4(a3)); /* IPv4 mapped addresses */ + + return IADDR_INVALID; + } + + return IADDR_HOST | SCOPE_UNDEFINED; +} + + + +/* + * Conversion of IPv6 address to presentation format and vice versa. + * Heavily inspired by routines written by Paul Vixie for the BIND project + * and of course by RFC 2373. + */ + + +char * +ip4_ntop(ip4_addr a, char *b) +{ + u32 x = _I(a); + return b + bsprintf(b, "%d.%d.%d.%d", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); +} + + +char * +ip6_ntop(ip6_addr a, char *b) +{ + u16 words[8]; + int bestpos, bestlen, curpos, curlen, i; + + /* First of all, preprocess the address and find the longest run of zeros */ + bestlen = bestpos = curpos = curlen = 0; + for (i=0; i<8; i++) + { + u32 x = a.addr[i/2]; + words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; + if (words[i]) + curlen = 0; + else + { + if (!curlen) + curpos = i; + curlen++; + if (curlen > bestlen) + { + bestpos = curpos; + bestlen = curlen; + } + } + } + + if (bestlen < 2) + bestpos = -1; + + /* Is it an encapsulated IPv4 address? */ + if (!bestpos && ((bestlen == 5 && a.addr[2] == 0xffff) || (bestlen == 6))) + { + u32 x = a.addr[3]; + b += bsprintf(b, "::%s%d.%d.%d.%d", + a.addr[2] ? "ffff:" : "", + (x >> 24) & 0xff, + (x >> 16) & 0xff, + (x >> 8) & 0xff, + x & 0xff); + return b; + } + + /* Normal IPv6 formatting, compress the largest sequence of zeros */ + for (i=0; i<8; i++) + { + if (i == bestpos) + { + i += bestlen - 1; + *b++ = ':'; + if (i == 7) + *b++ = ':'; + } + else + { + if (i) + *b++ = ':'; + b += bsprintf(b, "%x", words[i]); + } + } + *b = 0; + return b; +} + +int +ip4_pton(char *a, ip4_addr *o) +{ + int i; + unsigned long int l; + u32 ia = 0; + + i=4; + while (i--) + { + char *d, *c = strchr(a, '.'); + if (!c != !i) + return 0; + l = strtoul(a, &d, 10); + if (d != c && *d || l > 255) + return 0; + ia = (ia << 8) | l; + if (c) + c++; + a = c; + } + *o = ip4_from_u32(ia); + return 1; +} + +int +ip6_pton(char *a, ip6_addr *o) +{ + u16 words[8]; + int i, j, k, l, hfil; + char *start; + + if (a[0] == ':') /* Leading :: */ + { + if (a[1] != ':') + return 0; + a++; + } + + hfil = -1; + i = 0; + while (*a) + { + if (*a == ':') /* :: */ + { + if (hfil >= 0) + return 0; + + hfil = i; + a++; + continue; + } + + j = 0; + l = 0; + start = a; + for (;;) + { + if (*a >= '0' && *a <= '9') + k = *a++ - '0'; + else if (*a >= 'A' && *a <= 'F') + k = *a++ - 'A' + 10; + else if (*a >= 'a' && *a <= 'f') + k = *a++ - 'a' + 10; + else + break; + + j = (j << 4) + k; + if (j >= 0x10000 || ++l > 4) + return 0; + } + + if (*a == ':' && a[1]) + a++; + else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) + { /* Embedded IPv4 address */ + ip4_addr x; + if (!ip4_pton(start, &x)) + return 0; + words[i++] = _I(x) >> 16; + words[i++] = _I(x); + break; + } + else if (*a) + return 0; + + if (i >= 8) + return 0; + + words[i++] = j; + } + + /* Replace :: with an appropriate number of zeros */ + if (hfil >= 0) + { + j = 8 - i; + for (i=7; i-j >= hfil; i--) + words[i] = words[i-j]; + for (; i>=hfil; i--) + words[i] = 0; + } + + /* Convert the address to ip6_addr format */ + for (i=0; i<4; i++) + o->addr[i] = (words[2*i] << 16) | words[2*i+1]; + + return 1; +} + + /** * ip_scope_text - get textual representation of address scope * @scope: scope (%SCOPE_xxx) @@ -25,7 +349,7 @@ * Returns a pointer to a textual name of the scope given. */ char * -ip_scope_text(unsigned scope) +ip_scope_text(uint scope) { static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" }; @@ -35,6 +359,23 @@ ip_scope_text(unsigned scope) return scope_table[scope]; } +ip4_addr +ip4_class_mask(ip4_addr ad) +{ + u32 m, a = _I(ad); + + if (a < 0x80000000) + m = 0xff000000; + else if (a < 0xc0000000) + m = 0xffff0000; + else + m = 0xffffff00; + if (a & ~m) + m = 0xffffffff; + + return _MI4(m); +} + #if 0 /** * ipa_equal - compare two IP addresses for equality @@ -102,14 +443,14 @@ ip_addr ipa_not(ip_addr x) { DUMMY } ip_addr ipa_mkmask(int x) { DUMMY } /** - * ipa_mkmask - calculate netmask length + * ipa_masklen - calculate netmask length * @x: IP address * * This function checks whether @x represents a valid netmask and * returns the size of the associate network prefix or -1 for invalid * mask. */ -int ipa_mklen(ip_addr x) { DUMMY } +int ipa_masklen(ip_addr x) { DUMMY } /** * ipa_hash - hash IP addresses @@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY } int ipa_classify(ip_addr x) { DUMMY } /** - * ipa_class_mask - guess netmask according to address class - * @x: IP address + * ip4_class_mask - guess netmask according to address class + * @x: IPv4 address * * This function (available in IPv4 version only) returns a * network mask according to the address class of @x. Although @@ -160,7 +501,7 @@ int ipa_classify(ip_addr x) { DUMMY } * routing protocols transferring no prefix lengths nor netmasks * and this function could be useful to them. */ -ip_addr ipa_class_mask(ip_addr x) { DUMMY } +ip4_addr ip4_class_mask(ip4_addr x) { DUMMY } /** * ipa_from_u32 - convert IPv4 address to an integer @@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY } int ipa_compare(ip_addr x, ip_addr y) { DUMMY } /** - * ipa_build - build an IPv6 address from parts + * ipa_build6 - build an IPv6 address from parts * @a1: part #1 * @a2: part #2 * @a3: part #3 @@ -203,18 +544,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY } * address. It's used for example when a protocol wants to bind its * socket to a hard-wired multicast address. */ -ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } - -/** - * ipa_absolutize - convert link scope IPv6 address to universe scope - * @x: link scope IPv6 address - * @y: universe scope IPv6 prefix of the interface - * - * This function combines a link-scope IPv6 address @x with the universe - * scope prefix @x of the network assigned to an interface to get a - * universe scope form of @x. - */ -ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY } +ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY } /** * ip_ntop - convert IP address to textual representation diff --git a/lib/ip.h b/lib/ip.h index 023c1064..45e073d9 100644 --- a/lib/ip.h +++ b/lib/ip.h @@ -9,59 +9,474 @@ #ifndef _BIRD_IP_H_ #define _BIRD_IP_H_ -#ifndef IPV6 -#include "ipv4.h" +#include "lib/endian.h" +#include "lib/string.h" +#include "lib/bitops.h" +#include "lib/unaligned.h" + + +#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5) +#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6) + +#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1) +#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2) +#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) +#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) +#define IP6_RIP_ROUTERS ipa_build6(0xFF020000, 0, 0, 9) + +#define IP4_NONE _MI4(0) +#define IP6_NONE _MI6(0,0,0,0) + +#define IP4_MIN_MTU 576 +#define IP6_MIN_MTU 1280 + +#define IP_PREC_INTERNET_CONTROL 0xc0 + + +#ifdef IPV6 +#define MAX_PREFIX_LENGTH 128 +#define BITS_PER_IP_ADDRESS 128 +#define STD_ADDRESS_P_LENGTH 39 +#define SIZE_OF_IP_HEADER 40 #else -#include "ipv6.h" +#define MAX_PREFIX_LENGTH 32 +#define BITS_PER_IP_ADDRESS 32 +#define STD_ADDRESS_P_LENGTH 15 +#define SIZE_OF_IP_HEADER 24 +#endif + + +#ifdef DEBUGGING + +typedef struct ip4_addr { + u32 addr; +} ip4_addr; + +#define _MI4(x) ((struct ip4_addr) { x }) +#define _I(x) (x).addr + +#else + +typedef u32 ip4_addr; + +#define _MI4(x) (x) +#define _I(x) (x) + +#endif + + +typedef struct ip6_addr { + u32 addr[4]; +} ip6_addr; + +#define _MI6(a,b,c,d) ((struct ip6_addr) {{ a, b, c, d }}) +#define _I0(a) ((a).addr[0]) +#define _I1(a) ((a).addr[1]) +#define _I2(a) ((a).addr[2]) +#define _I3(a) ((a).addr[3]) + + +#ifdef IPV6 + +/* Structure ip_addr may contain both IPv4 and IPv6 addresses */ +typedef ip6_addr ip_addr; +#define IPA_NONE IP6_NONE + +#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x)) +#define ipa_from_ip6(x) x +#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x)) + +#define ipa_to_ip4(x) _MI4(_I3(x)) +#define ipa_to_ip6(x) x +#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x)) + +#define ipa_is_ip4(a) ip6_is_v4mapped(a) + +#else + +/* Provisionary ip_addr definition same as ip4_addr */ +typedef ip4_addr ip_addr; +#define IPA_NONE IP4_NONE + +#define ipa_from_ip4(x) x +#define ipa_from_ip6(x) IPA_NONE +#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x)) + +#define ipa_to_ip4(x) x +#define ipa_to_ip6(x) IP6_NONE +#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x)) + +#define ipa_is_ip4(a) 1 + #endif -#define ipa_zero(x) (!ipa_nonzero(x)) -#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) -#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) -#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) /* - * ip_classify() returns either a negative number for invalid addresses - * or scope OR'ed together with address type. + * Public constructors */ +#define ip4_from_u32(x) _MI4(x) +#define ip4_to_u32(x) _I(x) + +#define ip4_build(a,b,c,d) _MI4(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define ip6_build(a,b,c,d) _MI6(a,b,c,d) + +#define ipa_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d)) +#define ipa_build6(a,b,c,d) ipa_from_ip6(ip6_build(a,b,c,d)) + + +/* + * Basic algebraic functions + */ + +static inline int ip4_equal(ip4_addr a, ip4_addr b) +{ return _I(a) == _I(b); } + +static inline int ip4_zero(ip4_addr a) +{ return _I(a) == 0; } + +static inline int ip4_nonzero(ip4_addr a) +{ return _I(a) != 0; } + +static inline ip4_addr ip4_and(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) & _I(b)); } + +static inline ip4_addr ip4_or(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) | _I(b)); } + +static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b) +{ return _MI4(_I(a) ^ _I(b)); } + +static inline ip4_addr ip4_not(ip4_addr a) +{ return _MI4(~_I(a)); } + + +static inline int ip6_equal(ip6_addr a, ip6_addr b) +{ return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); } + +static inline int ip6_zero(ip6_addr a) +{ return !_I0(a) && !_I1(a) && !_I2(a) && !_I3(a); } + +static inline int ip6_nonzero(ip6_addr a) +{ return _I0(a) || _I1(a) || _I2(a) || _I3(a); } + +static inline ip6_addr ip6_and(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) & _I0(b), _I1(a) & _I1(b), _I2(a) & _I2(b), _I3(a) & _I3(b)); } + +static inline ip6_addr ip6_or(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) | _I0(b), _I1(a) | _I1(b), _I2(a) | _I2(b), _I3(a) | _I3(b)); } + +static inline ip6_addr ip6_xor(ip6_addr a, ip6_addr b) +{ return _MI6(_I0(a) ^ _I0(b), _I1(a) ^ _I1(b), _I2(a) ^ _I2(b), _I3(a) ^ _I3(b)); } + +static inline ip6_addr ip6_not(ip6_addr a) +{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); } + + +#ifdef IPV6 +#define ipa_equal(x,y) ip6_equal(x,y) +#define ipa_zero(x) ip6_zero(x) +#define ipa_nonzero(x) ip6_nonzero(x) +#define ipa_and(x,y) ip6_and(x,y) +#define ipa_or(x,y) ip6_or(x,y) +#define ipa_xor(x,y) ip6_xor(x,y) +#define ipa_not(x) ip6_not(x) +#else +#define ipa_equal(x,y) ip4_equal(x,y) +#define ipa_zero(x) ip4_zero(x) +#define ipa_nonzero(x) ip4_nonzero(x) +#define ipa_and(x,y) ip4_and(x,y) +#define ipa_or(x,y) ip4_or(x,y) +#define ipa_xor(x,y) ip4_xor(x,y) +#define ipa_not(x) ip4_not(x) +#endif + + + +#ifdef IPV6 +/* + * A zero address is either a token for invalid/unused, or the prefix of default + * routes. These functions should be used in the second case, where both IPv4 + * and IPv6 zero addresses should be checked. + */ + +static inline int ipa_zero2(ip_addr a) +{ return !_I0(a) && !_I1(a) && ((_I2(a) == 0) || (_I2(a) == 0xffff)) && !_I3(a); } + +static inline int ipa_nonzero2(ip_addr a) +{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); } + +#else +#define ipa_zero2(x) ip4_zero(x) +#define ipa_nonzero2(x) ip4_nonzero(x) +#endif + + +/* + * Hash and compare functions + */ + +static inline uint ip4_hash(ip4_addr a) +{ + /* Returns a 16-bit value */ + u32 x = _I(a); + x ^= x >> 16; + x ^= x << 10; + return x & 0xffff; +} + +static inline u32 ip4_hash32(ip4_addr a) +{ + /* Returns a 32-bit value, although low-order bits are not mixed */ + u32 x = _I(a); + x ^= x << 16; + x ^= x << 12; + return x; +} + +static inline uint ip6_hash(ip6_addr a) +{ + /* Returns a 16-bit hash key */ + u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a); + return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; +} + +static inline u32 ip6_hash32(ip6_addr a) +{ + /* Returns a 32-bit hash key, although low-order bits are not mixed */ + u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a); + return x ^ (x << 16) ^ (x << 24); +} + +static inline int ip4_compare(ip4_addr a, ip4_addr b) +{ return (_I(a) > _I(b)) - (_I(a) < _I(b)); } + +int ip6_compare(ip6_addr a, ip6_addr b); + + +#ifdef IPV6 +#define ipa_hash(x) ip6_hash(x) +#define ipa_hash32(x) ip6_hash32(x) +#define ipa_compare(x,y) ip6_compare(x,y) +#else +#define ipa_hash(x) ip4_hash(x) +#define ipa_hash32(x) ip4_hash32(x) +#define ipa_compare(x,y) ip4_compare(x,y) +#endif + + +/* + * IP address classification + */ + +/* Address class */ #define IADDR_INVALID -1 #define IADDR_SCOPE_MASK 0xfff #define IADDR_HOST 0x1000 #define IADDR_BROADCAST 0x2000 #define IADDR_MULTICAST 0x4000 +/* Address scope */ +#define SCOPE_HOST 0 +#define SCOPE_LINK 1 +#define SCOPE_SITE 2 +#define SCOPE_ORGANIZATION 3 +#define SCOPE_UNIVERSE 4 +#define SCOPE_UNDEFINED 5 + +int ip4_classify(ip4_addr ad); +int ip6_classify(ip6_addr *a); + +static inline int ip6_is_link_local(ip6_addr a) +{ return (_I0(a) & 0xffc00000) == 0xfe800000; } + +static inline int ip6_is_v4mapped(ip6_addr a) +{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; } + +#ifdef IPV6 +#define ipa_classify(x) ip6_classify(&(x)) +#define ipa_is_link_local(x) ip6_is_link_local(x) +#else +#define ipa_classify(x) ip4_classify(x) +#define ipa_is_link_local(x) 0 +#endif + +static inline int ipa_classify_net(ip_addr a) +{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } + + /* - * Address scope + * Miscellaneous IP prefix manipulation */ -#define SCOPE_HOST 0 -#define SCOPE_LINK 1 -#define SCOPE_SITE 2 -#define SCOPE_ORGANIZATION 3 -#define SCOPE_UNIVERSE 4 -#define SCOPE_UNDEFINED 5 +static inline ip4_addr ip4_mkmask(uint n) +{ return _MI4(u32_mkmask(n)); } + +static inline int ip4_masklen(ip4_addr a) +{ return u32_masklen(_I(a)); } + +ip6_addr ip6_mkmask(uint n); +int ip6_masklen(ip6_addr *a); + +/* ipX_pxlen() requires that x != y */ +static inline uint ip4_pxlen(ip4_addr a, ip4_addr b) +{ return 31 - u32_log2(_I(a) ^ _I(b)); } + +static inline uint ip6_pxlen(ip6_addr a, ip6_addr b) +{ + int i = 0; + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + i += (a.addr[i] == b.addr[i]); + return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); +} + +static inline u32 ip4_getbit(ip4_addr a, uint pos) +{ return _I(a) & (0x80000000 >> pos); } + +static inline u32 ip6_getbit(ip6_addr a, uint pos) +{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); } + +static inline ip4_addr ip4_opposite_m1(ip4_addr a) +{ return _MI4(_I(a) ^ 1); } + +static inline ip4_addr ip4_opposite_m2(ip4_addr a) +{ return _MI4(_I(a) ^ 3); } + +static inline ip6_addr ip6_opposite_m1(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 1); } + +static inline ip6_addr ip6_opposite_m2(ip6_addr a) +{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 3); } + +ip4_addr ip4_class_mask(ip4_addr ad); + +#ifdef IPV6 +#define ipa_mkmask(x) ip6_mkmask(x) +#define ipa_masklen(x) ip6_masklen(&x) +#define ipa_pxlen(x,y) ip6_pxlen(x,y) +#define ipa_getbit(x,n) ip6_getbit(x,n) +#define ipa_opposite_m1(x) ip6_opposite_m1(x) +#define ipa_opposite_m2(x) ip6_opposite_m2(x) +#else +#define ipa_mkmask(x) ip4_mkmask(x) +#define ipa_masklen(x) ip4_masklen(x) +#define ipa_pxlen(x,y) ip4_pxlen(x,y) +#define ipa_getbit(x,n) ip4_getbit(x,n) +#define ipa_opposite_m1(x) ip4_opposite_m1(x) +#define ipa_opposite_m2(x) ip4_opposite_m2(x) +#endif + + +/* + * Host/network order conversions + */ + +static inline ip4_addr ip4_hton(ip4_addr a) +{ return _MI4(htonl(_I(a))); } + +static inline ip4_addr ip4_ntoh(ip4_addr a) +{ return _MI4(ntohl(_I(a))); } + +static inline ip6_addr ip6_hton(ip6_addr a) +{ return _MI6(htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a))); } + +static inline ip6_addr ip6_ntoh(ip6_addr a) +{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } + +#ifdef IPV6 +#define ipa_hton(x) x = ip6_hton(x) +#define ipa_ntoh(x) x = ip6_ntoh(x) +#else +#define ipa_hton(x) x = ip4_hton(x) +#define ipa_ntoh(x) x = ip4_ntoh(x) +#endif + + +/* + * Unaligned data access (in network order) + */ + +static inline ip4_addr get_ip4(void *buf) +{ + return _MI4(get_u32(buf)); +} + +static inline ip6_addr get_ip6(void *buf) +{ + ip6_addr a; + memcpy(&a, buf, 16); + return ip6_ntoh(a); +} + +static inline void * put_ip4(void *buf, ip4_addr a) +{ + put_u32(buf, _I(a)); + return buf+4; +} + +static inline void * put_ip6(void *buf, ip6_addr a) +{ + a = ip6_hton(a); + memcpy(buf, &a, 16); + return buf+16; +} + +// XXXX these functions must be redesigned or removed +#ifdef IPV6 +#define get_ipa(x) get_ip6(x) +#define put_ipa(x,y) put_ip6(x,y) +#else +#define get_ipa(x) get_ip4(x) +#define put_ipa(x,y) put_ip4(x,y) +#endif + + +/* + * Binary/text form conversions + */ + +char *ip4_ntop(ip4_addr a, char *b); +char *ip6_ntop(ip6_addr a, char *b); + +static inline char * ip4_ntox(ip4_addr a, char *b) +{ return b + bsprintf(b, "%08x", _I(a)); } + +static inline char * ip6_ntox(ip6_addr a, char *b) +{ return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); } + +int ip4_pton(char *a, ip4_addr *o); +int ip6_pton(char *a, ip6_addr *o); + +// XXXX these functions must be redesigned or removed +#ifdef IPV6 +#define ipa_ntop(x,y) ip6_ntop(x,y) +#define ipa_ntox(x,y) ip6_ntox(x,y) +#define ipa_pton(x,y) ip6_pton(x,y) +#else +#define ipa_ntop(x,y) ip4_ntop(x,y) +#define ipa_ntox(x,y) ip4_ntox(x,y) +#define ipa_pton(x,y) ip4_pton(x,y) +#endif + + +/* + * Miscellaneous + */ + +// XXXX review this + +#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l))))) +#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p)))) +#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2))))) char *ip_scope_text(unsigned); -/* - * Network prefixes - */ - struct prefix { ip_addr addr; unsigned int len; }; -static inline int ipa_classify_net(ip_addr a) -{ return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } - -/* - * Conversions between internal and string representation - */ - -char *ip_ntop(ip_addr a, char *); -char *ip_ntox(ip_addr a, char *); -int ip_pton(char *a, ip_addr *o); #endif diff --git a/lib/ipv4.c b/lib/ipv4.c deleted file mode 100644 index 751351ca..00000000 --- a/lib/ipv4.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * BIRD Library -- IPv4 Address Manipulation Functions - * - * (c) 1998 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/string.h" - -int -ipv4_classify(u32 a) -{ - u32 b = a >> 24U; - - if (b && b <= 0xdf) - { - if (b == 0x7f) - return IADDR_HOST | SCOPE_HOST; - else if (b == 0x0a || - (a & 0xffff0000) == 0xc0a80000 || - (a & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - else - return IADDR_HOST | SCOPE_UNIVERSE; - } - if (b >= 0xe0 && b <= 0xef) - return IADDR_MULTICAST | SCOPE_UNIVERSE; - if (a == 0xffffffff) - return IADDR_BROADCAST | SCOPE_LINK; - return IADDR_INVALID; -} - -char * -ip_ntop(ip_addr a, char *b) -{ - u32 x = _I(a); - - return b + bsprintf(b, "%d.%d.%d.%d", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); -} - -char * -ip_ntox(ip_addr a, char *b) -{ - return b + bsprintf(b, "%08x", _I(a)); -} - -u32 -ipv4_class_mask(u32 a) -{ - u32 m; - - if (a < 0x80000000) - m = 0xff000000; - else if (a < 0xc0000000) - m = 0xffff0000; - else - m = 0xffffff00; - while (a & ~m) - m |= m >> 1; - return m; -} - -int -ip_pton(char *a, ip_addr *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ipa_from_u32(ia); - return 1; -} - -byte * -ipv4_skip_header(byte *pkt, int *len) -{ - int l = *len; - int q; - - if (l < 20 || (*pkt & 0xf0) != 0x40) - return NULL; - q = (*pkt & 0x0f) * 4; - if (q > l) - return NULL; - *len -= q; - return pkt + q; -} diff --git a/lib/ipv4.h b/lib/ipv4.h deleted file mode 100644 index 7fbdf2eb..00000000 --- a/lib/ipv4.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * BIRD -- IP Addresses et Cetera for IPv4 - * - * (c) 1998--1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV4_H_ -#define _BIRD_IPV4_H_ - -#include "lib/endian.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -#ifdef DEBUGGING - -/* - * Use the structural representation when you want to make sure - * nobody unauthorized attempts to handle ip_addr as number. - */ - -typedef struct ipv4_addr { - u32 addr; -} ip_addr; - -#define _I(x) (x).addr -#define _MI(x) ((struct ipv4_addr) { x }) - -#else - -typedef u32 ip_addr; - -#define _I(x) (x) -#define _MI(x) (x) - -#endif - -#define MAX_PREFIX_LENGTH 32 -#define BITS_PER_IP_ADDRESS 32 -#define STD_ADDRESS_P_LENGTH 15 -#define SIZE_OF_IP_HEADER 24 - -#define IPA_NONE (_MI(0)) - -#define ipa_equal(x,y) (_I(x) == _I(y)) -#define ipa_nonzero(x) _I(x) -#define ipa_and(x,y) _MI(_I(x) & _I(y)) -#define ipa_or(x,y) _MI(_I(x) | _I(y)) -#define ipa_xor(x,y) _MI(_I(x) ^ _I(y)) -#define ipa_not(x) _MI(~_I(x)) -#define ipa_mkmask(x) _MI(u32_mkmask(x)) -#define ipa_mklen(x) u32_masklen(_I(x)) -#define ipa_hash(x) ipv4_hash(_I(x)) -#define ipa_hash32(x) ipv4_hash32(_I(x)) -#define ipa_hton(x) x = _MI(htonl(_I(x))) -#define ipa_ntoh(x) x = _MI(ntohl(_I(x))) -#define ipa_classify(x) ipv4_classify(_I(x)) -#define ipa_has_link_scope(x) ipv4_has_link_scope(_I(x)) -#define ipa_opposite_m1(x) _MI(_I(x) ^ 1) -#define ipa_opposite_m2(x) _MI(_I(x) ^ 3) -#define ipa_class_mask(x) _MI(ipv4_class_mask(_I(x))) -#define ipa_from_u32(x) _MI(x) -#define ipa_to_u32(x) _I(x) -#define ipa_compare(x,y) ipv4_compare(_I(x),_I(y)) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv4_pxlen(_I(x), _I(y)) -#define ipa_getbit(x, y) (_I(x) & (0x80000000 >> (y))) -#define ipa_put_addr(x, y) ipv4_put_addr(x, y) - -#define ip_skip_header(x, y) ipv4_skip_header(x, y) - -int ipv4_classify(u32); -u32 ipv4_class_mask(u32); -byte *ipv4_skip_header(byte *, int *); - -static inline int ipv4_has_link_scope(u32 a UNUSED) -{ - return 0; -} - -static inline unsigned ipv4_hash(u32 a) -{ - /* Returns a 16-bit value */ - a ^= a >> 16; - a ^= a << 10; - return a & 0xffff; -} - -static inline u32 ipv4_hash32(u32 a) -{ - /* Returns a 32-bit value, although low-order bits are not mixed */ - a ^= a << 16; - a ^= a << 12; - return a; -} - -static inline int ipv4_compare(u32 x, u32 y) -{ - return (x > y) - (x < y); -} - -static inline u32 ipv4_pxlen(u32 a, u32 b) -{ - return 31 - u32_log2(a ^ b); -} - -static inline byte * ipv4_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf, _I(a)); - return buf+4; -} - -#define IP_PREC_INTERNET_CONTROL 0xc0 - -#endif diff --git a/lib/ipv6.c b/lib/ipv6.c deleted file mode 100644 index 623f6328..00000000 --- a/lib/ipv6.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * BIRD Library -- IPv6 Address Manipulation Functions - * - * (c) 1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include - -#include "nest/bird.h" -#include "lib/ip.h" -#include "lib/bitops.h" -#include "lib/endian.h" -#include "lib/string.h" - -/* - * See RFC 2373 for explanation of IPv6 addressing issues. - */ - -ip_addr -ipv6_mkmask(unsigned n) -{ - ip_addr a; - int i; - - for(i=0; i<4; i++) - { - if (!n) - a.addr[i] = 0; - else if (n >= 32) - { - a.addr[i] = ~0; - n -= 32; - } - else - { - a.addr[i] = u32_mkmask(n); - n = 0; - } - } - return a; -} - -unsigned -ipv6_mklen(ip_addr *a) -{ - int i, j, n; - - for(i=0, n=0; i<4; i++, n+=32) - if (a->addr[i] != ~0U) - { - j = u32_masklen(a->addr[i]); - if (j < 0) - return j; - n += j; - while (++i < 4) - if (a->addr[i]) - return -1; - break; - } - return n; -} - -int -ipv6_classify(ip_addr *a) -{ - u32 x = a->addr[0]; - - if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */ - return IADDR_HOST | SCOPE_UNIVERSE; - if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */ - return IADDR_HOST | SCOPE_LINK; - if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */ - return IADDR_HOST | SCOPE_SITE; - if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */ - { - unsigned int scope = (x >> 16) & 0x0f; - switch (scope) - { - case 1: return IADDR_MULTICAST | SCOPE_HOST; - case 2: return IADDR_MULTICAST | SCOPE_LINK; - case 5: return IADDR_MULTICAST | SCOPE_SITE; - case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION; - case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; - default: return IADDR_MULTICAST | SCOPE_UNDEFINED; - } - } - if (!x && !a->addr[1] && !a->addr[2]) - { - u32 y = a->addr[3]; - if (y == 1) - return IADDR_HOST | SCOPE_HOST; /* Loopback address */ - /* IPv4 compatible addresses */ - if (y >= 0x7f000000 && y < 0x80000000) - return IADDR_HOST | SCOPE_HOST; - if ((y & 0xff000000) == 0x0a000000 || - (y & 0xffff0000) == 0xc0a80000 || - (y & 0xfff00000) == 0xac100000) - return IADDR_HOST | SCOPE_SITE; - if (y >= 0x01000000 && y < 0xe0000000) - return IADDR_HOST | SCOPE_UNIVERSE; - } - return IADDR_HOST | SCOPE_UNDEFINED; -} - -void -ipv6_hton(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = htonl(a->addr[i]); -} - -void -ipv6_ntoh(ip_addr *a) -{ - int i; - - for(i=0; i<4; i++) - a->addr[i] = ntohl(a->addr[i]); -} - -int -ipv6_compare(ip_addr X, ip_addr Y) -{ - int i; - ip_addr *x = &X; - ip_addr *y = &Y; - - for(i=0; i<4; i++) - if (x->addr[i] > y->addr[i]) - return 1; - else if (x->addr[i] < y->addr[i]) - return -1; - return 0; -} - -/* - * Conversion of IPv6 address to presentation format and vice versa. - * Heavily inspired by routines written by Paul Vixie for the BIND project - * and of course by RFC 2373. - */ - -char * -ip_ntop(ip_addr a, char *b) -{ - u16 words[8]; - int bestpos, bestlen, curpos, curlen, i; - - /* First of all, preprocess the address and find the longest run of zeros */ - bestlen = bestpos = curpos = curlen = 0; - for(i=0; i<8; i++) - { - u32 x = a.addr[i/2]; - words[i] = ((i%2) ? x : (x >> 16)) & 0xffff; - if (words[i]) - curlen = 0; - else - { - if (!curlen) - curpos = i; - curlen++; - if (curlen > bestlen) - { - bestpos = curpos; - bestlen = curlen; - } - } - } - if (bestlen < 2) - bestpos = -1; - - /* Is it an encapsulated IPv4 address? */ - if (!bestpos && - (bestlen == 5 && a.addr[2] == 0xffff || - bestlen == 6)) - { - u32 x = a.addr[3]; - b += bsprintf(b, "::%s%d.%d.%d.%d", - a.addr[2] ? "ffff:" : "", - ((x >> 24) & 0xff), - ((x >> 16) & 0xff), - ((x >> 8) & 0xff), - (x & 0xff)); - return b; - } - - /* Normal IPv6 formatting, compress the largest sequence of zeros */ - for(i=0; i<8; i++) - { - if (i == bestpos) - { - i += bestlen - 1; - *b++ = ':'; - if (i == 7) - *b++ = ':'; - } - else - { - if (i) - *b++ = ':'; - b += bsprintf(b, "%x", words[i]); - } - } - *b = 0; - return b; -} - -char * -ip_ntox(ip_addr a, char *b) -{ - int i; - - for(i=0; i<4; i++) - { - if (i) - *b++ = '.'; - b += bsprintf(b, "%08x", a.addr[i]); - } - return b; -} - -int -ipv4_pton_u32(char *a, u32 *o) -{ - int i; - unsigned long int l; - u32 ia = 0; - - i=4; - while (i--) - { - char *d, *c = strchr(a, '.'); - if (!c != !i) - return 0; - l = strtoul(a, &d, 10); - if (d != c && *d || l > 255) - return 0; - ia = (ia << 8) | l; - if (c) - c++; - a = c; - } - *o = ia; - return 1; -} - -int -ip_pton(char *a, ip_addr *o) -{ - u16 words[8]; - int i, j, k, l, hfil; - char *start; - - if (a[0] == ':') /* Leading :: */ - { - if (a[1] != ':') - return 0; - a++; - } - hfil = -1; - i = 0; - while (*a) - { - if (*a == ':') /* :: */ - { - if (hfil >= 0) - return 0; - hfil = i; - a++; - continue; - } - j = 0; - l = 0; - start = a; - for(;;) - { - if (*a >= '0' && *a <= '9') - k = *a++ - '0'; - else if (*a >= 'A' && *a <= 'F') - k = *a++ - 'A' + 10; - else if (*a >= 'a' && *a <= 'f') - k = *a++ - 'a' + 10; - else - break; - j = (j << 4) + k; - if (j >= 0x10000 || ++l > 4) - return 0; - } - if (*a == ':' && a[1]) - a++; - else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0)) - { /* Embedded IPv4 address */ - u32 x; - if (!ipv4_pton_u32(start, &x)) - return 0; - words[i++] = x >> 16; - words[i++] = x; - break; - } - else if (*a) - return 0; - if (i >= 8) - return 0; - words[i++] = j; - } - - /* Replace :: with an appropriate number of zeros */ - if (hfil >= 0) - { - j = 8 - i; - for(i=7; i-j >= hfil; i--) - words[i] = words[i-j]; - for(; i>=hfil; i--) - words[i] = 0; - } - - /* Convert the address to ip_addr format */ - for(i=0; i<4; i++) - o->addr[i] = (words[2*i] << 16) | words[2*i+1]; - return 1; -} - -void ipv6_absolutize(ip_addr *a, ip_addr *ifa) -{ - if ((a->addr[0] & 0xffc00000) == 0xfe800000 && /* a is link-scope */ - ((ifa->addr[0] & 0xe0000000) == 0x20000000 | /* ifa is AGU ... */ - (ifa->addr[0] & 0xffc00000) == 0xfec00000)) /* ... or site-scope */ - { - a->addr[0] = ifa->addr[0]; /* Copy the prefix, leave interface ID */ - a->addr[1] = ifa->addr[1]; - } -} - -#ifdef TEST - -#include "bitops.c" - -static void test(char *x) -{ - ip_addr a; - char c[STD_ADDRESS_P_LENGTH+1]; - - printf("%-40s ", x); - if (!ip_pton(x, &a)) - { - puts("BAD"); - return; - } - ip_ntop(a, c); - printf("%-40s %04x\n", c, ipv6_classify(&a)); -} - -int main(void) -{ - puts("Positive tests:"); - test("1:2:3:4:5:6:7:8"); - test("dead:beef:DEAD:BEEF::f00d"); - test("::"); - test("::1"); - test("1::"); - test("::1.234.5.6"); - test("::ffff:1.234.5.6"); - test("::fffe:1.234.5.6"); - test("1:2:3:4:5:6:7::8"); - test("2080::8:800:200c:417a"); - test("ff01::101"); - - puts("Negative tests:"); - test(":::"); - test("1:2:3:4:5:6:7:8:"); - test("1::2::3"); - test("::12345"); - test("::1.2.3.4:5"); - test(":1:2:3:4:5:6:7:8"); - test("g:1:2:3:4:5:6:7"); - return 0; -} - -#endif diff --git a/lib/ipv6.h b/lib/ipv6.h deleted file mode 100644 index b935a6ef..00000000 --- a/lib/ipv6.h +++ /dev/null @@ -1,141 +0,0 @@ - -/* - * BIRD -- IP Addresses et Cetera for IPv6 - * - * (c) 1999--2000 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_IPV6_H_ -#define _BIRD_IPV6_H_ - -#include -#include -#include "lib/string.h" -#include "lib/bitops.h" -#include "lib/unaligned.h" - -typedef struct ipv6_addr { - u32 addr[4]; -} ip_addr; - -#define _MI(a,b,c,d) ((struct ipv6_addr) {{ a, b, c, d }}) -#define _I0(a) ((a).addr[0]) -#define _I1(a) ((a).addr[1]) -#define _I2(a) ((a).addr[2]) -#define _I3(a) ((a).addr[3]) - -#define MAX_PREFIX_LENGTH 128 -#define BITS_PER_IP_ADDRESS 128 -#define STD_ADDRESS_P_LENGTH 39 -#define SIZE_OF_IP_HEADER 40 - -#define IPA_NONE _MI(0,0,0,0) - -#define ipa_equal(x,y) ({ ip_addr _a=(x), _b=(y); \ - _I0(_a) == _I0(_b) && \ - _I1(_a) == _I1(_b) && \ - _I2(_a) == _I2(_b) && \ - _I3(_a) == _I3(_b); }) -#define ipa_nonzero(x) ({ ip_addr _a=(x); (_I0(_a) || _I1(_a) || _I2(_a) || _I3(_a)); }) -#define ipa_and(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) & _I0(_b), \ - _I1(_a) & _I1(_b), \ - _I2(_a) & _I2(_b), \ - _I3(_a) & _I3(_b)); }) -#define ipa_or(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) | _I0(_b), \ - _I1(_a) | _I1(_b), \ - _I2(_a) | _I2(_b), \ - _I3(_a) | _I3(_b)); }) -#define ipa_xor(x,y) ({ ip_addr _a=(x), _b=(y); \ - _MI(_I0(_a) ^ _I0(_b), \ - _I1(_a) ^ _I1(_b), \ - _I2(_a) ^ _I2(_b), \ - _I3(_a) ^ _I3(_b)); }) -#define ipa_not(x) ({ ip_addr _a=(x); _MI(~_I0(_a),~_I1(_a),~_I2(_a),~_I3(_a)); }) -#define ipa_mkmask(x) ipv6_mkmask(x) -#define ipa_mklen(x) ipv6_mklen(&(x)) -#define ipa_hash(x) ipv6_hash(&(x)) -#define ipa_hash32(x) ipv6_hash32(&(x)) -#define ipa_hton(x) ipv6_hton(&(x)) -#define ipa_ntoh(x) ipv6_ntoh(&(x)) -#define ipa_classify(x) ipv6_classify(&(x)) -#define ipa_has_link_scope(x) ipv6_has_link_scope(&(x)) -#define ipa_opposite_m1(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 1); }) -#define ipa_opposite_m2(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 3); }) -/* ipa_class_mask don't make sense with IPv6 */ -/* ipa_from_u32 and ipa_to_u32 replaced by ipa_build */ -#define ipa_build(a,b,c,d) _MI(a,b,c,d) -#define ipa_compare(x,y) ipv6_compare(x,y) -/* ipa_pxlen() requires that x != y */ -#define ipa_pxlen(x, y) ipv6_pxlen(x, y) -#define ipa_getbit(x, y) ipv6_getbit(x, y) -#define ipa_put_addr(x, y) ipv6_put_addr(x, y) -#define ipa_absolutize(x,y) ipv6_absolutize(x,y) - -/* In IPv6, SOCK_RAW does not return packet header */ -#define ip_skip_header(x, y) x - -ip_addr ipv6_mkmask(unsigned); -unsigned ipv6_mklen(ip_addr *); -int ipv6_classify(ip_addr *); -void ipv6_hton(ip_addr *); -void ipv6_ntoh(ip_addr *); -int ipv6_compare(ip_addr, ip_addr); -int ipv4_pton_u32(char *, u32 *); -void ipv6_absolutize(ip_addr *, ip_addr *); - -static inline int ipv6_has_link_scope(ip_addr *a) -{ - return ((a->addr[0] & 0xffc00000) == 0xfe800000); -} - -/* - * This hash function looks well, but once IPv6 enters - * mainstream use, we need to check that it has good - * distribution properties on real routing tables. - */ - -static inline unsigned ipv6_hash(ip_addr *a) -{ - /* Returns a 16-bit hash key */ - u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a); - return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff; -} - -static inline u32 ipv6_hash32(ip_addr *a) -{ - /* Returns a 32-bit hash key, although low-order bits are not ixed */ - u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a); - return x ^ (x << 16) ^ (x << 24); -} - -static inline u32 ipv6_getbit(ip_addr a, u32 y) -{ - return a.addr[y / 32] & (0x80000000 >> (y % 32)); -} - -static inline u32 ipv6_pxlen(ip_addr a, ip_addr b) -{ - int i = 0; - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - i+= (a.addr[i] == b.addr[i]); - return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]); -} - -static inline byte * ipv6_put_addr(byte *buf, ip_addr a) -{ - put_u32(buf+0, _I0(a)); - put_u32(buf+4, _I1(a)); - put_u32(buf+8, _I2(a)); - put_u32(buf+12, _I3(a)); - return buf+16; -} - -#define IP_PREC_INTERNET_CONTROL 0xc0 - -#endif diff --git a/lib/printf.c b/lib/printf.c index ebecc140..3eb988fa 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -283,9 +283,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args) /* IP address */ case 'I': if (flags & SPECIAL) - ip_ntox(va_arg(args, ip_addr), ipbuf); + ipa_ntox(va_arg(args, ip_addr), ipbuf); else { - ip_ntop(va_arg(args, ip_addr), ipbuf); + ipa_ntop(va_arg(args, ip_addr), ipbuf); if (field_width == 1) field_width = STD_ADDRESS_P_LENGTH; } diff --git a/lib/socket.h b/lib/socket.h index f1fffa94..a5b85aa2 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -91,6 +91,8 @@ int sk_set_ipv6_checksum(sock *s, int offset); int sk_set_icmp6_filter(sock *s, int p1, int p2); void sk_log_error(sock *s, const char *p); +byte * sk_rx_buffer(sock *s, int *len); /* Temporary */ + extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 1d37bfd7..a091ed1e 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -991,7 +991,7 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p if (p->cf->next_hop_self || rta->dest != RTD_ROUTER || ipa_equal(rta->gw, IPA_NONE) || - ipa_has_link_scope(rta->gw) || + ipa_is_link_local(rta->gw) || (!p->is_internal && !p->cf->next_hop_keep && (!p->neigh || (rta->iface != p->neigh->iface)))) set_next_hop(z, p->source_addr); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index e2339112..27825d7f 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -689,7 +689,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->password = p->cf->password; s->tx_hook = bgp_connected; BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface, - s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL); + s->saddr, ipa_is_link_local(s->saddr) ? s->iface : NULL); bgp_setup_conn(p, conn); bgp_setup_sk(conn, s); bgp_conn_set_state(conn, BS_CONNECT); @@ -735,7 +735,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) { struct bgp_proto *p = (struct bgp_proto *) pc->proto; if (ipa_equal(p->cf->remote_ip, sk->daddr) && - (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface))) + (!ipa_is_link_local(sk->daddr) || (p->cf->iface == sk->iface))) { /* We are in proper state and there is no other incoming connection */ int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && @@ -750,7 +750,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) } BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s", - sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, + sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport, acc ? "accepted" : "rejected"); if (!acc) @@ -779,7 +779,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED) } log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)", - sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport); + sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport); reject: rfree(sk); return 0; @@ -1169,8 +1169,8 @@ bgp_check_config(struct bgp_config *c) if (c->multihop && (c->gw_mode == GW_DIRECT)) cf_error("Multihop BGP cannot use direct gateway mode"); - if (c->multihop && (ipa_has_link_scope(c->remote_ip) || - ipa_has_link_scope(c->source_addr))) + if (c->multihop && (ipa_is_link_local(c->remote_ip) || + ipa_is_link_local(c->source_addr))) cf_error("Multihop BGP cannot be used with link-local addresses"); if (c->multihop && c->bfd && ipa_zero(c->source_addr)) diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 8e0b2412..c8345530 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -63,7 +63,7 @@ bgp_proto: | bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' { if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed"); - if (!ipa_has_link_scope($3) != !$4) + if (!ipa_is_link_local($3) != !$4) cf_error("Link-local address and interface scope must be used together"); BGP_CFG->remote_ip = $3; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 0b9de8c1..69646c7d 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -69,8 +69,8 @@ mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0); put_u16(buf+2, BGP_AF); buf+=4; - buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE); - buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE); + buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE); + buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE); return buf; } @@ -522,7 +522,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) *tmp++ = BGP_AF_IPV6; *tmp++ = 1; - if (ipa_has_link_scope(ip)) + if (ipa_is_link_local(ip)) ip = IPA_NONE; if (ipa_nonzero(ip_ll)) @@ -1034,7 +1034,7 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a) int second = (nh->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(nexthop[1]); /* First address should not be link-local, but may be zero in direct mode */ - if (ipa_has_link_scope(*nexthop)) + if (ipa_is_link_local(*nexthop)) *nexthop = IPA_NONE; #else int second = 0; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 6df5df08..e535287c 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -37,36 +37,9 @@ #endif -#define IP4_MIN_MTU 576 -#define IP6_MIN_MTU 1280 - -#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5) -#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6) - -#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5) -#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6) - #ifdef IPV6 -#define ip4_addr u32 -#define ip6_addr ip_addr -#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4) -#define ipa_is_link_local(x) ipa_has_link_scope(x) -#define ipa_from_u32(x) _MI6(0,0,0xffff,x) -#define ipa_to_u32(x) _I3(x) -#define ipa_build4(a,b,c,d) IPA_NONE -#define ipa_build6(a,b,c,d) _MI6(a,b,c,d) #define OSPF_IS_V2 0 #else -#define ip4_addr u32 -#define ip6_addr ip_addr -#define _I0(X) 0 -#define _I1(X) 0 -#define _I2(X) 0 -#define _I3(X) 0 -#define _MI6(x1,x2,x3,x4) IPA_NONE -#define ipa_is_link_local(x) 0 -#define ipa_build4(a,b,c,d) _MI(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) -#define ipa_build6(a,b,c,d) IPA_NONE #define OSPF_IS_V2 1 #endif @@ -744,10 +717,12 @@ lsa_net_count(struct ospf_lsa_header *lsa) #define ipa_from_rid(x) ipa_from_u32(x) #define ipa_to_rid(x) ipa_to_u32(x) - #define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) +/* FIXME: these four functions should be significantly redesigned w.r.t. integration, + also should be named as ospf3_* instead of *_ipv6_* */ + static inline u32 * lsa_get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) { @@ -787,6 +762,7 @@ lsa_get_ipv6_addr(u32 *buf, ip_addr *addr) static inline u32 * put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh) { +#ifdef IPV6 *buf++ = ((pxlen << 24) | (pxopts << 16) | lh); if (pxlen > 0) @@ -797,6 +773,7 @@ put_ipv6_prefix(u32 *buf, ip_addr addr, u8 pxlen, u8 pxopts, u16 lh) *buf++ = _I2(addr); if (pxlen > 96) *buf++ = _I3(addr); +#endif return buf; } diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 2814712d..a545c7fd 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -265,7 +265,8 @@ ospf_rx_hook(sock *sk, int len) } /* Second, we check packet length, checksum, and the protocol version */ - struct ospf_packet *pkt = (struct ospf_packet *) ip_skip_header(sk->rbuf, &len); + struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len); + if (pkt == NULL) DROP("bad IP header", len); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 08f90b49..b616c0d1 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1822,10 +1822,10 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, struct ospf_lsa_link *llsa = lhe->lsa_body; - if (ipa_zero(llsa->lladdr)) + if (ip6_zero(llsa->lladdr)) return NULL; - return new_nexthop(p, llsa->lladdr, pn->iface, pn->weight); + return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight); } } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 15ba013a..42bf9c45 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1319,7 +1319,7 @@ prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) ASSERT(p->lsab_used == 0); ll = lsab_allocz(p, sizeof(struct ospf_lsa_link)); ll->options = ifa->oa->options | (ifa->priority << 24); - ll->lladdr = ifa->addr->ip; + ll->lladdr = ipa_to_ip6(ifa->addr->ip); ll = NULL; /* buffer might be reallocated later */ struct ifa *a; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index ef869722..3862af8d 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -343,7 +343,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown) } RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); - sk_send_to(ifa->sk, ifa->plen, AllNodes, 0); + sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); } @@ -432,7 +432,7 @@ radv_sk_open(struct radv_iface *ifa) if (sk_setup_multicast(sk) < 0) goto err; - if (sk_join_group(sk, AllRouters) < 0) + if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0) goto err; ifa->sk = sk; diff --git a/proto/radv/radv.h b/proto/radv/radv.h index bb80d65f..48ba9c1a 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -26,9 +26,6 @@ #define ICMPV6_PROTO 58 -#define AllNodes _MI(0xFF020000, 0, 0, 1) /* FF02::1 */ -#define AllRouters _MI(0xFF020000, 0, 0, 2) /* FF02::2 */ - #define ICMPV6_RS 133 #define ICMPV6_RA 134 diff --git a/proto/rip/rip.c b/proto/rip/rip.c index bc9ffc5f..a0c28e72 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -305,7 +305,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme, struct A.flags = 0; #ifndef IPV6 A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme; - pxlen = ipa_mklen(b->netmask); + pxlen = ipa_masklen(b->netmask); #else /* FIXME: next hop is in other packet for v6 */ A.gw = whotoldme; @@ -365,7 +365,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme, stru #ifndef IPV6 metric = ntohl( block->metric ); - pxlen = ipa_mklen(block->netmask); + pxlen = ipa_masklen(block->netmask); #else metric = block->metric; pxlen = block->pxlen; @@ -447,7 +447,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr ipa_ntoh( block->netmask ); ipa_ntoh( block->nexthop ); if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */ - block->netmask = ipa_class_mask(block->network); + block->netmask = ip4_class_mask(ipa_to_ip4(block->network)); #endif process_block( p, block, whotoldme, iface ); } @@ -721,7 +721,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ #ifndef IPV6 rif->sock->daddr = ipa_from_u32(0xe0000009); #else - rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9); + rif->sock->daddr = IP6_RIP_ROUTERS; #endif } else { rif->sock->daddr = new->addr->brd; @@ -812,7 +812,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface) #ifndef IPV6 lock->addr = ipa_from_u32(0xe0000009); #else - ip_pton("FF02::9", &lock->addr); + lock->addr = IP6_RIP_ROUTERS; #endif else lock->addr = iface->addr->brd; diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 621f7309..0e65c51c 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -382,7 +382,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) SKIP("strange class/scope\n"); - int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask); + int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask); if (pxlen < 0) { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; } @@ -653,7 +653,7 @@ krt_read_addr(struct ks_msg *msg, int scan) ibrd = ipa_from_sa(&brd); - if ((masklen = ipa_mklen(imask)) < 0) + if ((masklen = ipa_masklen(imask)) < 0) { log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name); return; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 164038ec..04f0fe50 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -764,6 +764,29 @@ sk_set_tos6(sock *s, int tos) return 0; } +static inline byte * +sk_skip_ip_header(byte *pkt, int *len) +{ + if ((*len < 20) || ((*pkt & 0xf0) != 0x40)) + return NULL; + + int hlen = (*pkt & 0x0f) * 4; + if ((hlen < 20) || (hlen > *len)) + return NULL; + + *len -= hlen; + return pkt + hlen; +} + +byte * +sk_rx_buffer(sock *s, int *len) +{ + if (sk_is_ipv4(s) && (s->type == SK_IP)) + return sk_skip_ip_header(s->rbuf, len); + else + return s->rbuf; +} + /* * Public socket functions diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 518713bc..3cee96b4 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -47,19 +47,9 @@ typedef struct sockaddr_bird { #ifdef IPV6 #define BIRD_AF AF_INET6 -#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4) -#define ipa_is_link_local(x) ipa_has_link_scope(x) #define ipa_from_sa(x) ipa_from_sa6(x) -#define ipa_from_u32(x) _MI6(0,0,0xffff,x) -#define ipa_to_u32(x) _I3(x) #else #define BIRD_AF AF_INET -#define _I0(X) 0 -#define _I1(X) 0 -#define _I2(X) 0 -#define _I3(X) 0 -#define _MI6(x1,x2,x3,x4) IPA_NONE -#define ipa_is_link_local(x) 0 #define ipa_from_sa(x) ipa_from_sa4(x) #endif @@ -75,7 +65,7 @@ static inline ip_addr ipa_from_in4(struct in_addr a) { return ipa_from_u32(ntohl(a.s_addr)); } static inline ip_addr ipa_from_in6(struct in6_addr a) -{ return _MI6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); } +{ return ipa_build6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); } static inline ip_addr ipa_from_sa4(sockaddr *sa) { return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); } @@ -86,8 +76,14 @@ static inline ip_addr ipa_from_sa6(sockaddr *sa) static inline struct in_addr ipa_to_in4(ip_addr a) { return (struct in_addr) { htonl(ipa_to_u32(a)) }; } +#ifdef IPV6 static inline struct in6_addr ipa_to_in6(ip_addr a) { return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; } +#else +/* Temporary dummy */ +static inline struct in6_addr ipa_to_in6(ip_addr a) +{ return (struct in6_addr) { .s6_addr32 = { 0, 0, 0, 0 } }; } +#endif void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port); int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);