summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile3
-rw-r--r--lib/Modules35
-rw-r--r--lib/birdlib.h25
-rw-r--r--lib/bitops.c6
-rw-r--r--lib/bitops.h2
-rw-r--r--lib/hash.h36
-rw-r--r--lib/idm.c76
-rw-r--r--lib/idm.h25
-rw-r--r--lib/ip.c6
-rw-r--r--lib/ip.h163
-rw-r--r--lib/lists.h5
-rw-r--r--lib/net.c203
-rw-r--r--lib/net.h357
-rw-r--r--lib/printf.c77
-rw-r--r--lib/socket.h58
-rw-r--r--lib/unaligned.h1
16 files changed, 829 insertions, 249 deletions
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 00000000..551089c3
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,3 @@
+src := bitops.c checksum.c event.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
+obj := $(src-o-files)
+$(all-daemon)
diff --git a/lib/Modules b/lib/Modules
deleted file mode 100644
index 0e30b488..00000000
--- a/lib/Modules
+++ /dev/null
@@ -1,35 +0,0 @@
-sha256.c
-sha256.h
-sha512.c
-sha512.h
-sha1.c
-sha1.h
-birdlib.h
-bitops.c
-bitops.h
-ip.h
-ip.c
-lists.c
-lists.h
-mac.c
-mac.h
-md5.c
-md5.h
-mempool.c
-resource.c
-resource.h
-slab.c
-socket.h
-tbf.c
-unaligned.h
-xmalloc.c
-printf.c
-string.h
-patmatch.c
-slists.c
-slists.h
-event.c
-event.h
-checksum.c
-checksum.h
-alloca.h
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 37337078..ddc963f4 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -9,8 +9,8 @@
#ifndef _BIRD_BIRDLIB_H_
#define _BIRD_BIRDLIB_H_
-#include "timer.h"
-#include "alloca.h"
+#include "sysdep/unix/timer.h"
+#include "lib/alloca.h"
/* Ugly structure offset handling macros */
@@ -34,6 +34,13 @@
#define ABS(a) ((a)>=0 ? (a) : -(a))
#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
+#define CALL(fn, args...) ({ if (fn) fn(args); })
+
+static inline int uint_cmp(uint i1, uint i2)
+{ return (int)(i1 > i2) - (int)(i1 < i2); }
+
+static inline int u64_cmp(u64 i1, u64 i2)
+{ return (int)(i1 > i2) - (int)(i1 < i2); }
/* Bitfield macros */
@@ -49,12 +56,6 @@
#define NULL ((void *) 0)
#endif
-#ifndef IPV6
-#define IP_VERSION 4
-#else
-#define IP_VERSION 6
-#endif
-
/* Macros for gcc attributes */
@@ -62,14 +63,6 @@
#define UNUSED __attribute__((unused))
#define PACKED __attribute__((packed))
-#ifdef IPV6
-#define UNUSED4
-#define UNUSED6 UNUSED
-#else
-#define UNUSED4 UNUSED
-#define UNUSED6
-#endif
-
/* Microsecond time */
typedef s64 btime;
diff --git a/lib/bitops.c b/lib/bitops.c
index 81586e87..efb8710e 100644
--- a/lib/bitops.c
+++ b/lib/bitops.c
@@ -28,15 +28,15 @@ u32_mkmask(uint n)
*
* This function checks whether the given integer @x represents
* a valid bit mask (binary representation contains first ones, then
- * zeroes) and returns the number of ones or -1 if the mask is invalid.
+ * zeroes) and returns the number of ones or 255 if the mask is invalid.
*/
-int
+uint
u32_masklen(u32 x)
{
int l = 0;
u32 n = ~x;
- if (n & (n+1)) return -1;
+ if (n & (n+1)) return 255;
if (x & 0x0000ffff) { x &= 0x0000ffff; l += 16; }
if (x & 0x00ff00ff) { x &= 0x00ff00ff; l += 8; }
if (x & 0x0f0f0f0f) { x &= 0x0f0f0f0f; l += 4; }
diff --git a/lib/bitops.h b/lib/bitops.h
index ce13732a..9f954374 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -19,7 +19,7 @@
*/
u32 u32_mkmask(uint n);
-int u32_masklen(u32 x);
+uint u32_masklen(u32 x);
u32 u32_log2(u32 v);
diff --git a/lib/hash.h b/lib/hash.h
index 4239b1d8..b37d8fa5 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -188,4 +188,40 @@
#define HASH_WALK_FILTER_END } while (0)
+
+static inline void
+mem_hash_init(u64 *h)
+{
+ *h = 0x001047d54778bcafULL;
+}
+
+static inline void
+mem_hash_mix(u64 *h, void *p, uint s)
+{
+ const u64 multiplier = 0xb38bc09a61202731ULL;
+ const char *pp = p;
+ uint i;
+
+ for (i=0; i<s/4; i++)
+ *h = *h * multiplier + ((const u32 *)pp)[i];
+
+ for (i=s & ~0x3; i<s; i++)
+ *h = *h * multiplier + pp[i];
+}
+
+static inline uint
+mem_hash_value(u64 *h)
+{
+ return ((*h >> 32) ^ (*h & 0xffffffff));
+}
+
+static inline uint
+mem_hash(void *p, uint s)
+{
+ static u64 h;
+ mem_hash_init(&h);
+ mem_hash_mix(&h, p, s);
+ return mem_hash_value(&h);
+}
+
#endif
diff --git a/lib/idm.c b/lib/idm.c
new file mode 100644
index 00000000..66e311c6
--- /dev/null
+++ b/lib/idm.c
@@ -0,0 +1,76 @@
+/*
+ * BIRD Library -- ID Map
+ *
+ * (c) 2013--2015 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013--2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+
+#include "nest/bird.h"
+#include "lib/idm.h"
+#include "lib/resource.h"
+#include "lib/string.h"
+
+
+void
+idm_init(struct idm *m, pool *p, uint size)
+{
+ m->pos = 0;
+ m->used = 1;
+ m->size = size;
+ m->data = mb_allocz(p, m->size * sizeof(u32));
+
+ /* ID 0 is reserved */
+ m->data[0] = 1;
+}
+
+static inline int u32_cto(uint x) { return ffs(~x) - 1; }
+
+u32
+idm_alloc(struct idm *m)
+{
+ uint i, j;
+
+ for (i = m->pos; i < m->size; i++)
+ if (m->data[i] != 0xffffffff)
+ goto found;
+
+ /* If we are at least 7/8 full, expand */
+ if (m->used > (m->size * 28))
+ {
+ m->size *= 2;
+ m->data = mb_realloc(m->data, m->size * sizeof(u32));
+ memset(m->data + i, 0, (m->size - i) * sizeof(u32));
+ goto found;
+ }
+
+ for (i = 0; i < m->pos; i++)
+ if (m->data[i] != 0xffffffff)
+ goto found;
+
+ ASSERT(0);
+
+found:
+ ASSERT(i < 0x8000000);
+
+ m->pos = i;
+ j = u32_cto(m->data[i]);
+
+ m->data[i] |= (1 << j);
+ m->used++;
+ return 32 * i + j;
+}
+
+void
+idm_free(struct idm *m, u32 id)
+{
+ uint i = id / 32;
+ uint j = id % 32;
+
+ ASSERT((i < m->size) && (m->data[i] & (1 << j)));
+ m->data[i] &= ~(1 << j);
+ m->used--;
+}
diff --git a/lib/idm.h b/lib/idm.h
new file mode 100644
index 00000000..e3380cce
--- /dev/null
+++ b/lib/idm.h
@@ -0,0 +1,25 @@
+/*
+ * BIRD Library -- ID Map
+ *
+ * (c) 2013--2015 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013--2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_IDM_H_
+#define _BIRD_IDM_H_
+
+struct idm
+{
+ u32 *data;
+ u32 pos;
+ u32 used;
+ u32 size;
+};
+
+void idm_init(struct idm *m, pool *p, uint size);
+u32 idm_alloc(struct idm *m);
+void idm_free(struct idm *m, u32 id);
+
+#endif
diff --git a/lib/ip.c b/lib/ip.c
index 2050d19e..5e039c12 100644
--- a/lib/ip.c
+++ b/lib/ip.c
@@ -58,7 +58,7 @@ ip6_mkmask(uint n)
return a;
}
-int
+uint
ip6_masklen(ip6_addr *a)
{
int i, j, n;
@@ -67,12 +67,12 @@ ip6_masklen(ip6_addr *a)
if (a->addr[i] != ~0U)
{
j = u32_masklen(a->addr[i]);
- if (j < 0)
+ if (j == 255)
return j;
n += j;
while (++i < 4)
if (a->addr[i])
- return -1;
+ return 255;
break;
}
diff --git a/lib/ip.h b/lib/ip.h
index 298b72a7..6541ce1e 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -9,7 +9,7 @@
#ifndef _BIRD_IP_H_
#define _BIRD_IP_H_
-#include "lib/endian.h"
+#include "sysdep/unix/endian.h"
#include "lib/string.h"
#include "lib/bitops.h"
#include "lib/unaligned.h"
@@ -31,6 +31,13 @@
#define IP4_NONE _MI4(0)
#define IP6_NONE _MI6(0,0,0,0)
+#define IP4_MAX_PREFIX_LENGTH 32
+#define IP6_MAX_PREFIX_LENGTH 128
+
+#define IP4_MAX_TEXT_LENGTH 15 /* "255.255.255.255" */
+#define IP6_MAX_TEXT_LENGTH 39 /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
+#define IPA_MAX_TEXT_LENGTH 39
+
#define IP4_MIN_MTU 576
#define IP6_MIN_MTU 1280
@@ -41,19 +48,6 @@
#define UDP_HEADER_LENGTH 8
-#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
-#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 {
@@ -84,8 +78,6 @@ typedef struct ip6_addr {
#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
@@ -100,23 +92,8 @@ typedef ip6_addr ip_addr;
#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_NONE4 ipa_from_ip4(IP4_NONE)
+#define IPA_NONE6 ipa_from_ip6(IP6_NONE)
/*
@@ -181,7 +158,6 @@ 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)
@@ -189,19 +165,8 @@ static inline ip6_addr ip6_not(ip6_addr a)
#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
@@ -214,26 +179,12 @@ static inline int ipa_zero2(ip_addr 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)
+static inline u32 ip4_hash(ip4_addr a)
{
/* Returns a 32-bit value, although low-order bits are not mixed */
u32 x = _I(a);
@@ -242,14 +193,7 @@ static inline u32 ip4_hash32(ip4_addr a)
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)
+static inline u32 ip6_hash(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);
@@ -261,16 +205,8 @@ static inline int ip4_compare(ip4_addr a, ip4_addr 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
/*
@@ -301,14 +237,10 @@ static inline int ip6_is_link_local(ip6_addr a)
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
+/* XXXX remove */
static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
@@ -320,11 +252,11 @@ static inline int ipa_classify_net(ip_addr a)
static inline ip4_addr ip4_mkmask(uint n)
{ return _MI4(u32_mkmask(n)); }
-static inline int ip4_masklen(ip4_addr a)
+static inline uint ip4_masklen(ip4_addr a)
{ return u32_masklen(_I(a)); }
ip6_addr ip6_mkmask(uint n);
-int ip6_masklen(ip6_addr *a);
+uint ip6_masklen(ip6_addr *a);
/* ipX_pxlen() requires that x != y */
static inline uint ip4_pxlen(ip4_addr a, ip4_addr b)
@@ -346,6 +278,18 @@ static inline u32 ip4_getbit(ip4_addr a, uint pos)
static inline u32 ip6_getbit(ip6_addr a, uint pos)
{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); }
+static inline u32 ip4_setbit(ip4_addr *a, uint pos)
+{ return _I(*a) |= (0x80000000 >> pos); }
+
+static inline u32 ip6_setbit(ip6_addr *a, uint pos)
+{ return a->addr[pos / 32] |= (0x80000000 >> (pos % 32)); }
+
+static inline u32 ip4_clrbit(ip4_addr *a, uint pos)
+{ return _I(*a) &= ~(0x80000000 >> pos); }
+
+static inline u32 ip6_clrbit(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); }
@@ -360,21 +304,8 @@ static inline ip6_addr ip6_opposite_m2(ip6_addr a)
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
/*
@@ -393,14 +324,6 @@ static inline ip6_addr ip6_hton(ip6_addr 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)
@@ -431,15 +354,6 @@ static inline void * put_ip6(void *buf, ip6_addr a)
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
@@ -457,34 +371,11 @@ static inline char * ip6_ntox(ip6_addr a, char *b)
int ip4_pton(const char *a, ip4_addr *o);
int ip6_pton(const 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(uint);
-struct prefix {
- ip_addr addr;
- uint len;
-};
-
-
#endif
diff --git a/lib/lists.h b/lib/lists.h
index 51856b05..46b33446 100644
--- a/lib/lists.h
+++ b/lib/lists.h
@@ -52,7 +52,10 @@ typedef union list { /* In fact two overlayed nodes */
#define WALK_LIST2(n,nn,list,pos) \
for(nn=(list).head; NODE_VALID(nn) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nn->next)
#define WALK_LIST_DELSAFE(n,nxt,list) \
- for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
+ for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
+#define WALK_LIST2_DELSAFE(n,nn,nxt,list,pos) \
+ for(nn=HEAD(list); (nxt=nn->next) && (n=SKIP_BACK(typeof(*n),pos,nn)); nn=nxt)
+
/* WALK_LIST_FIRST supposes that called code removes each processed node */
#define WALK_LIST_FIRST(n,list) \
while(n=HEAD(list), (NODE (n))->next)
diff --git a/lib/net.c b/lib/net.c
new file mode 100644
index 00000000..55eec4b5
--- /dev/null
+++ b/lib/net.c
@@ -0,0 +1,203 @@
+
+#include "nest/bird.h"
+#include "lib/ip.h"
+#include "lib/net.h"
+
+
+const char * const net_label[] = {
+ [NET_IP4] = "ipv4",
+ [NET_IP6] = "ipv6",
+ [NET_VPN4] = "vpn4",
+ [NET_VPN6] = "vpn6",
+ [NET_ROA4] = "roa4",
+ [NET_ROA6] = "roa6",
+};
+
+const u16 net_addr_length[] = {
+ [NET_IP4] = sizeof(net_addr_ip4),
+ [NET_IP6] = sizeof(net_addr_ip6),
+ [NET_VPN4] = sizeof(net_addr_vpn4),
+ [NET_VPN6] = sizeof(net_addr_vpn6),
+ [NET_ROA4] = sizeof(net_addr_roa4),
+ [NET_ROA6] = sizeof(net_addr_roa6)
+};
+
+const u8 net_max_prefix_length[] = {
+ [NET_IP4] = IP4_MAX_PREFIX_LENGTH,
+ [NET_IP6] = IP6_MAX_PREFIX_LENGTH,
+ [NET_VPN4] = IP4_MAX_PREFIX_LENGTH,
+ [NET_VPN6] = IP6_MAX_PREFIX_LENGTH,
+ [NET_ROA4] = IP4_MAX_PREFIX_LENGTH,
+ [NET_ROA6] = IP6_MAX_PREFIX_LENGTH
+};
+
+const u16 net_max_text_length[] = {
+ [NET_IP4] = 18, /* "255.255.255.255/32" */
+ [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
+ [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */
+ [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
+ [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */
+ [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
+};
+
+
+int
+net_format(const net_addr *N, char *buf, int buflen)
+{
+ net_addr_union *n = (void *) N;
+
+ switch (n->n.type)
+ {
+ case NET_IP4:
+ return bsnprintf(buf, buflen, "%I4/%d", n->ip4.prefix, n->ip4.pxlen);
+ case NET_IP6:
+ return bsnprintf(buf, buflen, "%I6/%d", n->ip6.prefix, n->ip6.pxlen);
+ case NET_VPN4:
+ return bsnprintf(buf, buflen, "%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
+ case NET_VPN6:
+ return bsnprintf(buf, buflen, "%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
+ case NET_ROA4:
+ return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn);
+ case NET_ROA6:
+ return bsnprintf(buf, buflen, "%I6/%u-%u AS%u", n->roa6.prefix, n->roa6.pxlen, n->roa6.max_pxlen, n->roa6.asn);
+ }
+
+ return 0;
+}
+
+ip_addr
+net_pxmask(const net_addr *a)
+{
+ switch (a->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return ipa_from_ip4(ip4_mkmask(net4_pxlen(a)));
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
+
+ default:
+ return IPA_NONE;
+ }
+}
+
+int
+net_compare(const net_addr *a, const net_addr *b)
+{
+ if (a->type != b->type)
+ return uint_cmp(a->type, b->type);
+
+ switch (a->type)
+ {
+ case NET_IP4:
+ return net_compare_ip4((const net_addr_ip4 *) a, (const net_addr_ip4 *) b);
+ case NET_IP6:
+ return net_compare_ip6((const net_addr_ip6 *) a, (const net_addr_ip6 *) b);
+ case NET_VPN4:
+ return net_compare_vpn4((const net_addr_vpn4 *) a, (const net_addr_vpn4 *) b);
+ case NET_VPN6:
+ return net_compare_vpn6((const net_addr_vpn6 *) a, (const net_addr_vpn6 *) b);
+ case NET_ROA4:
+ return net_compare_roa4((const net_addr_roa4 *) a, (const net_addr_roa4 *) b);
+ case NET_ROA6:
+ return net_compare_roa6((const net_addr_roa6 *) a, (const net_addr_roa6 *) b);
+ }
+ return 0;
+}
+
+int
+net_validate(const net_addr *N)
+{
+ switch (N->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return net_validate_ip4((net_addr_ip4 *) N);
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return net_validate_ip6((net_addr_ip6 *) N);
+
+ default:
+ return 0;
+ }
+}
+
+void
+net_normalize(net_addr *N)
+{
+ net_addr_union *n = (void *) N;
+
+ switch (n->n.type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return net_normalize_ip4(&n->ip4);
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return net_normalize_ip6(&n->ip6);
+ }
+}
+
+int
+net_classify(const net_addr *N)
+{
+ net_addr_union *n = (void *) N;
+
+ switch (n->n.type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return ip4_zero(n->ip4.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip4_classify(n->ip4.prefix);
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
+ }
+
+ return IADDR_INVALID;
+}
+
+int
+ipa_in_netX(const ip_addr a, const net_addr *n)
+{
+ switch (n->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ if (!ipa_is_ip4(a)) return 0;
+ return ip4_zero(ip4_and(ip4_xor(ipa_to_ip4(a), net4_prefix(n)),
+ ip4_mkmask(net4_pxlen(n))));
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ if (ipa_is_ip4(a)) return 0;
+ return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
+ ip6_mkmask(net6_pxlen(n))));
+
+ default:
+ return 0;
+ }
+}
+
+int
+net_in_netX(const net_addr *a, const net_addr *n)
+{
+ if (a->type != n->type)
+ return 0;
+
+ return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n);
+}
diff --git a/lib/net.h b/lib/net.h
new file mode 100644
index 00000000..d9137c4a
--- /dev/null
+++ b/lib/net.h
@@ -0,0 +1,357 @@
+/*
+ * BIRD Internet Routing Daemon -- Network addresses
+ *
+ * (c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_NET_H_
+#define _BIRD_NET_H_
+
+#include "lib/ip.h"
+
+
+#define NET_IP4 1
+#define NET_IP6 2
+#define NET_VPN4 3
+#define NET_VPN6 4
+#define NET_ROA4 5
+#define NET_ROA6 6
+#define NET_MAX 7
+
+#define NB_IP4 (1 << NET_IP4)
+#define NB_IP6 (1 << NET_IP6)
+#define NB_VPN4 (1 << NET_VPN4)
+#define NB_VPN6 (1 << NET_VPN6)
+#define NB_ROA4 (1 << NET_ROA4)
+#define NB_ROA6 (1 << NET_ROA6)
+
+#define NB_IP (NB_IP4 | NB_IP6)
+#define NB_ANY 0xffffffff
+
+
+typedef struct net_addr {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ u8 data[16];
+ u64 align[0];
+} net_addr;
+
+typedef struct net_addr_ip4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+} net_addr_ip4;
+
+typedef struct net_addr_ip6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+} net_addr_ip6;
+
+typedef struct net_addr_vpn4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+ u64 rd;
+} net_addr_vpn4;
+
+typedef struct net_addr_vpn6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+ u64 rd;
+} net_addr_vpn6;
+
+typedef struct net_addr_roa4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+ u32 max_pxlen;
+ u32 asn;
+} net_addr_roa4;
+
+typedef struct net_addr_roa6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+ u32 max_pxlen;
+ u32 asn;
+} net_addr_roa6;
+
+typedef union net_addr_union {
+ net_addr n;
+ net_addr_ip4 ip4;
+ net_addr_ip6 ip6;
+ net_addr_vpn4 vpn4;
+ net_addr_vpn6 vpn6;
+ net_addr_roa4 roa4;
+ net_addr_roa6 roa6;
+} net_addr_union;
+
+
+extern const char * const net_label[];
+extern const u16 net_addr_length[];
+extern const u8 net_max_prefix_length[];
+extern const u16 net_max_text_length[];
+
+#define NET_MAX_TEXT_LENGTH 65
+
+
+#define NET_ADDR_IP4(prefix,pxlen) \
+ ((net_addr_ip4) { NET_IP4, pxlen, sizeof(net_addr_ip4), prefix })
+
+#define NET_ADDR_IP6(prefix,pxlen) \
+ ((net_addr_ip6) { NET_IP6, pxlen, sizeof(net_addr_ip6), prefix })
+
+#define NET_ADDR_VPN4(prefix,pxlen,rd) \
+ ((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd })
+
+#define NET_ADDR_VPN6(prefix,pxlen,rd) \
+ ((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, rd })
+
+#define NET_ADDR_ROA4(prefix,pxlen,max_pxlen,asn) \
+ ((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn })
+
+#define NET_ADDR_ROA6(prefix,pxlen,max_pxlen,asn) \
+ ((net_addr_roa6) { NET_ROA6, pxlen, sizeof(net_addr_roa6), prefix, max_pxlen, asn })
+
+
+
+static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
+{ *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, pxlen); }
+
+static inline void net_fill_ip6(net_addr *a, ip6_addr prefix, uint pxlen)
+{ *(net_addr_ip6 *)a = NET_ADDR_IP6(prefix, pxlen); }
+
+static inline void net_fill_vpn4(net_addr *a, ip4_addr prefix, uint pxlen, u64 rd)
+{ *(net_addr_vpn4 *)a = NET_ADDR_VPN4(prefix, pxlen, rd); }
+
+static inline void net_fill_vpn6(net_addr *a, ip6_addr prefix, uint pxlen, u64 rd)
+{ *(net_addr_vpn6 *)a = NET_ADDR_VPN6(prefix, pxlen, rd); }
+
+static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
+{ *(net_addr_roa4 *)a = NET_ADDR_ROA4(prefix, pxlen, max_pxlen, asn); }
+
+static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
+{ *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); }
+
+static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
+{
+ if (ipa_is_ip4(prefix))
+ net_fill_ip4(a, ipa_to_ip4(prefix), pxlen);
+ else
+ net_fill_ip6(a, ipa_to_ip6(prefix), pxlen);
+}
+
+static inline void net_fill_ip_host(net_addr *a, ip_addr prefix)
+{
+ if (ipa_is_ip4(prefix))
+ net_fill_ip4(a, ipa_to_ip4(prefix), IP4_MAX_PREFIX_LENGTH);
+ else
+ net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
+}
+
+
+static inline int net_val_match(u8 type, u32 mask)
+{ return !!((1 << type) & mask); }
+
+static inline int net_type_match(const net_addr *a, u32 mask)
+{ return net_val_match(a->type, mask); }
+
+static inline int net_is_ip(const net_addr *a)
+{ return (a->type == NET_IP4) || (a->type == NET_IP6); }
+
+
+static inline ip4_addr net4_prefix(const net_addr *a)
+{ return ((net_addr_ip4 *) a)->prefix; }
+
+static inline ip6_addr net6_prefix(const net_addr *a)
+{ return ((net_addr_ip6 *) a)->prefix; }
+
+static inline ip_addr net_prefix(const net_addr *a)
+{
+ switch (a->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return ipa_from_ip4(net4_prefix(a));
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return ipa_from_ip6(net6_prefix(a));
+
+ default:
+ return IPA_NONE;
+ }
+}
+
+static inline uint net4_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+static inline uint net6_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+static inline uint net_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+ip_addr net_pxmask(const net_addr *a);
+
+
+static inline int net_equal(const net_addr *a, const net_addr *b)
+{ return (a->length == b->length) && !memcmp(a, b, a->length); }
+
+static inline int net_equal_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_ip4)); }
+
+static inline int net_equal_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_ip6)); }
+
+static inline int net_equal_vpn4(const net_addr_vpn4 *a, const net_addr_vpn4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_vpn4)); }
+
+static inline int net_equal_vpn6(const net_addr_vpn6 *a, const net_addr_vpn6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_vpn6)); }
+
+static inline int net_equal_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_roa4)); }
+
+static inline int net_equal_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_roa6)); }
+
+static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
+
+static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
+{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
+
+
+static inline int net_zero_ip4(const net_addr_ip4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix); }
+
+static inline int net_zero_ip6(const net_addr_ip6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix); }
+
+static inline int net_zero_vpn4(const net_addr_vpn4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix) && !a->rd; }
+
+static inline int net_zero_vpn6(const net_addr_vpn6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix) && !a->rd; }
+
+static inline int net_zero_roa4(const net_addr_roa4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix) && !a->max_pxlen && !a->asn; }
+
+static inline int net_zero_roa6(const net_addr_roa6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
+
+
+static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
+{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_vpn4(const net_addr_vpn4 *a, const net_addr_vpn4 *b)
+{ return u64_cmp(a->rd, b->rd) ?: ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_vpn6(const net_addr_vpn6 *a, const net_addr_vpn6 *b)
+{ return u64_cmp(a->rd, b->rd) ?: ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); }
+
+static inline int net_compare_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
+{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); }
+
+int net_compare(const net_addr *a, const net_addr *b);
+
+
+static inline void net_copy(net_addr *dst, const net_addr *src)
+{ memcpy(dst, src, src->length); }
+
+static inline void net_copy_ip4(net_addr_ip4 *dst, const net_addr_ip4 *src)
+{ memcpy(dst, src, sizeof(net_addr_ip4)); }
+
+static inline void net_copy_ip6(net_addr_ip6 *dst, const net_addr_ip6 *src)
+{ memcpy(dst, src, sizeof(net_addr_ip6)); }
+
+static inline void net_copy_vpn4(net_addr_vpn4 *dst, const net_addr_vpn4 *src)
+{ memcpy(dst, src, sizeof(net_addr_vpn4)); }
+
+static inline void net_copy_vpn6(net_addr_vpn6 *dst, const net_addr_vpn6 *src)
+{ memcpy(dst, src, sizeof(net_addr_vpn6)); }
+
+static inline void net_copy_roa4(net_addr_roa4 *dst, const net_addr_roa4 *src)
+{ memcpy(dst, src, sizeof(net_addr_roa4)); }
+
+static inline void net_copy_roa6(net_addr_roa6 *dst, const net_addr_roa6 *src)
+{ memcpy(dst, src, sizeof(net_addr_roa6)); }
+
+
+static inline u32 net_hash_ip4(const net_addr_ip4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+static inline u32 net_hash_ip6(const net_addr_ip6 *n)
+{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+/* XXXX */
+static inline u32 u64_hash(u64 a)
+{ return u32_hash(a); }
+
+static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
+
+static inline u32 net_hash_vpn6(const net_addr_vpn6 *n)
+{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
+
+static inline u32 net_hash_roa4(const net_addr_roa4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+static inline u32 net_hash_roa6(const net_addr_roa6 *n)
+{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+
+static inline int net_validate_ip4(const net_addr_ip4 *n)
+{
+ return (n->pxlen <= IP4_MAX_PREFIX_LENGTH) &&
+ ip4_zero(ip4_and(n->prefix, ip4_not(ip4_mkmask(n->pxlen))));
+}
+
+static inline int net_validate_ip6(const net_addr_ip6 *n)
+{
+ return (n->pxlen <= IP6_MAX_PREFIX_LENGTH) &&
+ ip6_zero(ip6_and(n->prefix, ip6_not(ip6_mkmask(n->pxlen))));
+}
+
+int net_validate(const net_addr *N);
+
+
+static inline void net_normalize_ip4(net_addr_ip4 *n)
+{ n->prefix = ip4_and(n->prefix, ip4_mkmask(n->pxlen)); }
+
+static inline void net_normalize_ip6(net_addr_ip6 *n)
+{ n->prefix = ip6_and(n->prefix, ip6_mkmask(n->pxlen)); }
+
+void net_normalize(net_addr *N);
+
+
+int net_classify(const net_addr *N);
+int net_format(const net_addr *N, char *buf, int buflen);
+
+
+int ipa_in_netX(const ip_addr A, const net_addr *N);
+int net_in_netX(const net_addr *A, const net_addr *N);
+
+
+#endif
diff --git a/lib/printf.c b/lib/printf.c
index 4fd75c9b..1632b5f3 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -118,16 +118,16 @@ static char * number(char * str, long num, int base, int size, int precision,
* @fmt: format string
* @args: a list of arguments to be formatted
*
- * This functions acts like ordinary sprintf() except that it checks
- * available space to avoid buffer overflows and it allows some more
- * format specifiers: |%I| for formatting of IP addresses (any non-zero
- * width is automatically replaced by standard IP address width which
- * depends on whether we use IPv4 or IPv6; |%#I| gives hexadecimal format),
- * |%R| for Router / Network ID (u32 value printed as IPv4 address)
- * |%lR| for 64bit Router / Network ID (u64 value printed as eight :-separated octets)
- * and |%m| resp. |%M| for error messages (uses strerror() to translate @errno code to
- * message text). On the other hand, it doesn't support floating
- * point numbers.
+ * This functions acts like ordinary sprintf() except that it checks available
+ * space to avoid buffer overflows and it allows some more format specifiers:
+ * |%I| for formatting of IP addresses (width of 1 is automatically replaced by
+ * standard IP address width which depends on whether we use IPv4 or IPv6; |%I4|
+ * or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
+ * generic network addresses (net_addr *), |%R| for Router / Network ID (u32
+ * value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
+ * value printed as eight :-separated octets) and |%m| resp. |%M| for error
+ * messages (uses strerror() to translate @errno code to message text). On the
+ * other hand, it doesn't support floating point numbers.
*
* Result: number of characters of the output string or -1 if
* the buffer space was insufficient.
@@ -141,7 +141,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
u64 X;
char *str, *start;
const char *s;
- char ipbuf[MAX(STD_ADDRESS_P_LENGTH,ROUTER_ID_64_LENGTH)+1];
+ char ipbuf[NET_MAX_TEXT_LENGTH+1];
struct iface *iface;
int flags; /* flags to number() */
@@ -158,7 +158,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
*str++ = *fmt;
continue;
}
-
+
/* process flags */
flags = 0;
repeat:
@@ -170,7 +170,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
-
+
/* get field width */
field_width = -1;
if (is_digit(*fmt))
@@ -188,7 +188,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* get the precision */
precision = -1;
if (*fmt == '.') {
- ++fmt;
+ ++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
@@ -238,6 +238,14 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case 'M':
s = strerror(va_arg(args, int));
goto str;
+ case 'N': {
+ net_addr *n = va_arg(args, net_addr *);
+ if (field_width == 1)
+ field_width = net_max_text_length[n->type];
+ net_format(n, ipbuf, sizeof(ipbuf));
+ s = ipbuf;
+ goto str;
+ }
case 's':
s = va_arg(args, char *);
if (!s)
@@ -284,14 +292,35 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* IP address */
case 'I':
- if (flags & SPECIAL)
- ipa_ntox(va_arg(args, ip_addr), ipbuf);
- else {
- ipa_ntop(va_arg(args, ip_addr), ipbuf);
- if (field_width == 1)
- field_width = STD_ADDRESS_P_LENGTH;
+ if (fmt[1] == '4') {
+ /* Explicit IPv4 address */
+ ip4_addr a = va_arg(args, ip4_addr);
+ ip4_ntop(a, ipbuf);
+ i = IP4_MAX_TEXT_LENGTH;
+ fmt++;
+ } else if (fmt[1] == '6') {
+ /* Explicit IPv6 address */
+ ip6_addr a = va_arg(args, ip6_addr);
+ ip6_ntop(a, ipbuf);
+ i = IP6_MAX_TEXT_LENGTH;
+ fmt++;
+ } else {
+ /* Just IP address */
+ ip_addr a = va_arg(args, ip_addr);
+
+ if (ipa_is_ip4(a)) {
+ ip4_ntop(ipa_to_ip4(a), ipbuf);
+ i = IP4_MAX_TEXT_LENGTH;
+ } else {
+ ip6_ntop(ipa_to_ip6(a), ipbuf);
+ i = IP6_MAX_TEXT_LENGTH;
+ }
}
+
s = ipbuf;
+ if (field_width == 1)
+ field_width = i;
+
goto str;
/* Interface scope after link-local IP address */
@@ -311,7 +340,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* Router/Network ID - essentially IPv4 address in u32 value */
case 'R':
- if(qualifier == 'l') {
+ if (qualifier == 'l') {
X = va_arg(args, u64);
bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
((X >> 56) & 0xff),
@@ -326,11 +355,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
else
{
x = va_arg(args, u32);
- bsprintf(ipbuf, "%d.%d.%d.%d",
- ((x >> 24) & 0xff),
- ((x >> 16) & 0xff),
- ((x >> 8) & 0xff),
- (x & 0xff));
+ ip4_ntop(ip4_from_u32(x), ipbuf);
}
s = ipbuf;
goto str;
diff --git a/lib/socket.h b/lib/socket.h
index 2da52127..43db3cab 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -10,7 +10,6 @@
#define _BIRD_SOCKET_H_
#include <errno.h>
-// #include <sys/socket.h>
#include "lib/resource.h"
@@ -18,6 +17,7 @@ typedef struct birdsock {
resource r;
pool *pool; /* Pool where incoming connections should be allocated (for SK_xxx_PASSIVE) */
int type; /* Socket type */
+ int subtype; /* Socket subtype */
void *data; /* User data */
ip_addr saddr, daddr; /* IPA_NONE = unspecified */
uint sport, dport; /* 0 = unspecified (for IP: protocol type) */
@@ -45,7 +45,7 @@ typedef struct birdsock {
uint lifindex; /* local interface that received the datagram */
/* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */
- int af; /* Address family (AF_INET, AF_INET6 or 0 for non-IP) of fd */
+ int af; /* System-dependend adress family (e.g. AF_INET) */
int fd; /* System-dependent data */
int index; /* Index in poll buffer */
int rcv_ttl; /* TTL of last received datagram */
@@ -68,19 +68,12 @@ void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */
void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
void sk_dump_all(void);
+int sk_is_ipv4(sock *s); /* True if socket is IPv4 */
+int sk_is_ipv6(sock *s); /* True if socket is IPv6 */
+
static inline int sk_send_buffer_empty(sock *sk)
{ return sk->tbuf == sk->tpos; }
-
-#ifdef IPV6
-#define sk_is_ipv4(X) 0
-#define sk_is_ipv6(X) 1
-#else
-#define sk_is_ipv4(X) 1
-#define sk_is_ipv6(X) 0
-#endif
-
-
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
int sk_join_group(sock *s, ip_addr maddr); /* Join multicast group on sk iface */
int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface */
@@ -99,7 +92,6 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
/* Socket flags */
-#define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */
#define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 0x04 /* Report local address for RX packets */
#define SKF_TTL_RX 0x08 /* Report TTL / Hop Limit for RX packets */
@@ -125,24 +117,34 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
#define SK_UNIX 9
/*
- * For SK_UDP or SK_IP sockets setting DA/DP allows to use sk_send(),
- * otherwise sk_send_to() must be used.
+ * Socket subtypes
+ */
+
+#define SK_IPV4 1
+#define SK_IPV6 2
+
+/*
+ * For TCP/IP sockets, Address family (IPv4 or IPv6) can be specified either
+ * explicitly (SK_IPV4 or SK_IPV6) or implicitly (based on saddr, daddr). But
+ * these specifications must be consistent.
+ *
+ * For SK_UDP or SK_IP sockets setting DA/DP allows to use sk_send(), otherwise
+ * sk_send_to() must be used.
*
- * For SK_IP sockets setting DP specifies protocol number, which is used
- * for both receiving and sending.
+ * For SK_IP sockets setting DP specifies protocol number, which is used for
+ * both receiving and sending.
*
- * For multicast on SK_UDP or SK_IP sockets set IF and TTL,
- * call sk_setup_multicast() to enable multicast on that socket,
- * and then use sk_join_group() and sk_leave_group() to manage
- * a set of received multicast groups.
+ * For multicast on SK_UDP or SK_IP sockets set IF and TTL, call
+ * sk_setup_multicast() to enable multicast on that socket, and then use
+ * sk_join_group() and sk_leave_group() to manage a set of received multicast
+ * groups.
*
- * For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle
- * source address. The socket could be bound to it using bind()
- * syscall, but that also forbids the reception of multicast packets,
- * or the address could be set on per-packet basis using platform
- * dependent options (but these are not available in some corner
- * cases). The first way is used when SKF_BIND is specified, the
- * second way is used otherwise.
+ * For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle source
+ * address. The socket could be bound to it using bind() syscall, but that also
+ * forbids the reception of multicast packets, or the address could be set on
+ * per-packet basis using platform dependent options (but these are not
+ * available in some corner cases). The first way is used when SKF_BIND is
+ * specified, the second way is used otherwise.
*/
#endif
diff --git a/lib/unaligned.h b/lib/unaligned.h
index dc777fbf..ad5811ab 100644
--- a/lib/unaligned.h
+++ b/lib/unaligned.h
@@ -17,6 +17,7 @@
* if possible.
*/
+#include "sysdep/unix/endian.h"
#include "lib/string.h"
static inline u16