summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Doc1
-rw-r--r--lib/Makefile6
-rw-r--r--lib/birdlib.h5
-rw-r--r--lib/bitops.h2
-rw-r--r--lib/bitops_test.c123
-rw-r--r--lib/buffer.h16
-rw-r--r--lib/buffer_test.c147
-rw-r--r--lib/checksum_test.c94
-rw-r--r--lib/event_test.c88
-rw-r--r--lib/fletcher16_test.c169
-rw-r--r--lib/hash.h29
-rw-r--r--lib/hash_test.c305
-rw-r--r--lib/heap_test.c186
-rw-r--r--lib/idm.c2
-rw-r--r--lib/ip.c2
-rw-r--r--lib/ip.h1
-rw-r--r--lib/ip_test.c161
-rw-r--r--lib/lists.c12
-rw-r--r--lib/lists.h1
-rw-r--r--lib/lists_test.c287
-rw-r--r--lib/mac.c289
-rw-r--r--lib/mac.h121
-rw-r--r--lib/mac_test.c1159
-rw-r--r--lib/md5.c81
-rw-r--r--lib/md5.h21
-rw-r--r--lib/net.c18
-rw-r--r--lib/net.h2
-rw-r--r--lib/patmatch_test.c149
-rw-r--r--lib/printf.c2
-rw-r--r--lib/printf_test.c70
-rw-r--r--lib/sha1.c95
-rw-r--r--lib/sha1.h30
-rw-r--r--lib/sha256.c150
-rw-r--r--lib/sha256.h42
-rw-r--r--lib/sha512.c150
-rw-r--r--lib/sha512.h44
-rw-r--r--lib/slist_test.c384
-rw-r--r--lib/slists.c82
-rw-r--r--lib/socket.h2
-rw-r--r--lib/string.h30
-rw-r--r--lib/unaligned.h18
41 files changed, 3940 insertions, 636 deletions
diff --git a/lib/Doc b/lib/Doc
index 8af1c669..632bf1f6 100644
--- a/lib/Doc
+++ b/lib/Doc
@@ -2,6 +2,7 @@ H Library functions
S ip.c
S lists.c
S checksum.c bitops.c patmatch.c printf.c xmalloc.c tbf.c
+S mac.c
D resource.sgml
S resource.c
S mempool.c
diff --git a/lib/Makefile b/lib/Makefile
index a9aae66f..a7da9802 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -2,6 +2,10 @@ src := bitops.c checksum.c ip.c lists.c md5.c net.c patmatch.c printf.c sha1.c s
obj := $(src-o-files)
$(all-client)
-src := bitops.c checksum.c event.c idm.c ip.c lists.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
+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)
+
+tests_src := heap_test.c buffer_test.c event_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c mac_test.c ip_test.c hash_test.c printf_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 188e59b2..bb19df54 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -35,6 +35,7 @@
#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); })
+#define ADVANCE(w, r, l) ({ r -= l; w += l; })
static inline int uint_cmp(uint i1, uint i2)
{ return (int)(i1 > i2) - (int)(i1 < i2); }
@@ -56,14 +57,12 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define NULL ((void *) 0)
#endif
-
/* Macros for gcc attributes */
#define NORET __attribute__((noreturn))
#define UNUSED __attribute__((unused))
#define PACKED __attribute__((packed))
-
/* Microsecond time */
typedef s64 btime;
@@ -151,7 +150,7 @@ void bug(const char *msg, ...) NORET;
#define L_FATAL "\010" /* Fatal errors */
#define L_BUG "\011" /* BIRD bugs */
-void debug(const char *msg, ...); /* Printf to debug output */
+void debug(const char *msg, ...); /* Printf to debug output */
/* Debugging */
diff --git a/lib/bitops.h b/lib/bitops.h
index 9f954374..af648c26 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -9,6 +9,8 @@
#ifndef _BIRD_BITOPTS_H_
#define _BIRD_BITOPTS_H_
+#include "sysdep/config.h"
+
/*
* Bit mask operations:
*
diff --git a/lib/bitops_test.c b/lib/bitops_test.c
new file mode 100644
index 00000000..f816b9d1
--- /dev/null
+++ b/lib/bitops_test.c
@@ -0,0 +1,123 @@
+/*
+ * BIRD Library -- Generic Bit Operations Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h" /* naive_pow() */
+
+#include "lib/bitops.h"
+
+#define MAX_NUM 1000
+#define CHECK_BIT(var,pos) ((var) & (u32)(1<<(pos)))
+
+static int
+t_mkmask(void)
+{
+ int i;
+ u32 compute, expect;
+
+ bt_assert(u32_mkmask(0) == 0x00000000);
+ for (i = 1; i <= 32; i++)
+ {
+ compute = u32_mkmask(i);
+ expect = (u32) (0xffffffff << (32-i));
+ bt_assert_msg(compute == expect, "u32_mkmask(%d) = 0x%08X, expected 0x%08X", i, compute, expect);
+ }
+
+ return 1;
+}
+
+static int
+u32_masklen_expected(u32 mask)
+{
+ int j, expect = 0;
+
+ int valid = 0;
+ for (j = 0; j <= 32; j++)
+ if (mask == (j ? (0xffffffff << (32-j)) : 0)) /* Shifting 32-bit value by 32 bits is undefined behavior */
+ valid = 1;
+
+ if (!valid && mask != 0)
+ expect = 255;
+ else
+ for (j = 0; j <= 31; j++)
+ if (CHECK_BIT(mask, (31-j)))
+ expect = j+1;
+ else
+ break;
+ return expect;
+}
+
+static void
+check_mask(u32 mask)
+{
+ int expected, masklen;
+
+ expected = u32_masklen_expected(mask);
+ masklen = u32_masklen(mask);
+ int ok = (expected == masklen);
+ bt_debug("u32_masklen(Ox%08x) = %d, expected %d %s\n", mask, masklen, expected, ok ? "OK" : "FAIL!");
+ bt_assert(ok);
+}
+
+static int
+t_masklen(void)
+{
+ u32 i;
+
+ check_mask(0x82828282);
+ check_mask(0x00000000);
+
+ for (i = 0; i <= 32; i++)
+ check_mask(((u32) (i ? (0xffffffff << (32-i)) : 0)) & 0xffffffff); /* Shifting 32-bit value by 32 bits is undefined behavior */
+
+ for (i = 0; i <= MAX_NUM; i++)
+ check_mask(bt_random());
+
+ return 1;
+}
+
+static void
+check_log2(u32 n)
+{
+ u32 log = u32_log2(n);
+ u32 low = bt_naive_pow(2, log);
+ u32 high = bt_naive_pow(2, log+1);
+
+ bt_assert_msg(n >= low && n < high,
+ "u32_log2(%u) = %u, %u should be in the range <%u, %u)",
+ n, log, n, low, high);
+}
+
+static int
+t_log2(void)
+{
+ u32 i;
+
+ for (i = 0; i < 31; i++)
+ bt_assert(u32_log2(bt_naive_pow(2, i+1)) == i+1);
+
+ for (i = 1; i < MAX_NUM; i++)
+ check_log2(i);
+
+ for (i = 1; i < MAX_NUM; i++)
+ check_log2(((u32) bt_random()) % 0x0fffffff);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_mkmask, "u32_mkmask()");
+ bt_test_suite(t_masklen, "u32_masklen()");
+ bt_test_suite(t_log2, "u32_log2()");
+
+ return bt_exit_value();
+}
diff --git a/lib/buffer.h b/lib/buffer.h
index cf073e88..2a53f211 100644
--- a/lib/buffer.h
+++ b/lib/buffer.h
@@ -1,3 +1,17 @@
+/*
+ * BIRD Library -- Generic Buffer Structure
+ *
+ * (c) 2013 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_BUFFER_H_
+#define _BIRD_BUFFER_H_
+
+#include "lib/resource.h"
+#include "sysdep/config.h"
#define BUFFER(type) struct { type *data; uint used, size; }
@@ -32,4 +46,4 @@
#define BUFFER_FLUSH(v) ({ (v).used = 0; })
-
+#endif /* _BIRD_BUFFER_H_ */
diff --git a/lib/buffer_test.c b/lib/buffer_test.c
new file mode 100644
index 00000000..55179e82
--- /dev/null
+++ b/lib/buffer_test.c
@@ -0,0 +1,147 @@
+/*
+ * BIRD Library -- Buffer Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+
+#include "test/birdtest.h"
+
+#include "lib/buffer.h"
+
+#define MAX_NUM 33
+
+typedef BUFFER(int) buffer_int;
+static int expected[MAX_NUM];
+static buffer_int buf;
+static struct pool *buffer_pool;
+
+static void
+show_buf(buffer_int *b)
+{
+ uint i;
+ bt_debug(".used = %d, .size = %d\n", b->used, b->size);
+
+ for (i = 0; i < b->used; i++)
+ bt_debug(" .data[%3u] = %-16d expected %-16d %s\n", i, b->data[i], expected[i], (b->data[i] == expected[i] ? "OK" : "FAIL!"));
+}
+
+static void
+fill_expected_array(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ expected[i] = bt_random();
+}
+
+static void
+init_buffer(void)
+{
+ resource_init();
+ buffer_pool = &root_pool;
+ BUFFER_INIT(buf, buffer_pool, MAX_NUM);
+}
+
+static int
+is_buffer_as_expected(buffer_int *b)
+{
+ show_buf(b);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(b->data[i] == expected[i]);
+ return 1;
+}
+
+static int
+t_buffer_push(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+
+ return 1;
+}
+
+static int
+t_buffer_pop(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+
+ /* POP a half of elements */
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ for (i = MAX_NUM-1; i >= MAX_NUM/2; i--)
+ BUFFER_POP(buf);
+ for (i = MAX_NUM/2; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i] = bt_random();
+ is_buffer_as_expected(&buf);
+
+ /* POP all of elements */
+ for (i = MAX_NUM-1; i >= 0; i--)
+ BUFFER_POP(buf);
+ bt_assert(buf.used == 0);
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+
+ return 1;
+}
+
+static int
+t_buffer_resize(void)
+{
+ int i;
+
+ init_buffer();
+ BUFFER_INIT(buf, buffer_pool, 0);
+ fill_expected_array();
+
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+ is_buffer_as_expected(&buf);
+ bt_assert(buf.size >= MAX_NUM);
+
+ return 1;
+}
+
+static int
+t_buffer_flush(void)
+{
+ int i;
+
+ init_buffer();
+ fill_expected_array();
+ for (i = 0; i < MAX_NUM; i++)
+ BUFFER_PUSH(buf) = expected[i];
+
+ BUFFER_FLUSH(buf);
+ bt_assert(buf.used == 0);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_buffer_push, "Pushing new elements");
+ bt_test_suite(t_buffer_pop, "Fill whole buffer (PUSH), a half of elements POP and PUSH new elements");
+ bt_test_suite(t_buffer_resize, "Init a small buffer and try overfill");
+ bt_test_suite(t_buffer_flush, "Fill and flush all elements");
+
+ return bt_exit_value();
+}
diff --git a/lib/checksum_test.c b/lib/checksum_test.c
new file mode 100644
index 00000000..7e5658eb
--- /dev/null
+++ b/lib/checksum_test.c
@@ -0,0 +1,94 @@
+/*
+ * BIRD Library -- IP One-Complement Checksum Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+
+#include "test/birdtest.h"
+
+#include "lib/checksum.h"
+
+#define MAX_NUM 10000
+
+static u16
+ipsum_calculate_expected(u32 *a)
+{
+ int i;
+ u32 sum = 0;
+
+ for(i = 0; i < MAX_NUM; i++)
+ {
+ sum += a[i] & 0xffff;
+ bt_debug("low) \t0x%08X \n", sum);
+
+ sum += a[i] >> 16;
+ bt_debug("high) \t0x%08X \n", sum);
+
+ u16 carry = sum >> 16;
+ sum = (sum & 0xffff) + carry;
+ bt_debug("carry) \t0x%08X \n\n", sum);
+ }
+ bt_debug("sum) \t0x%08X \n", sum);
+
+ sum = sum ^ 0xffff;
+ bt_debug("~sum) \t0x%08X \n", sum);
+
+ return sum;
+}
+
+static int
+t_calculate(void)
+{
+ u32 a[MAX_NUM];
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ a[i] = bt_random();
+
+ u16 sum_calculated = ipsum_calculate(a, sizeof(a), NULL);
+ u16 sum_calculated_2 = ipsum_calculate(&a[0], sizeof(u32)*(MAX_NUM/2), &a[MAX_NUM/2], sizeof(u32)*(MAX_NUM - MAX_NUM/2), NULL);
+ bt_assert(sum_calculated == sum_calculated_2);
+
+ u16 sum_expected = ipsum_calculate_expected(a);
+
+ bt_debug("sum_calculated: %08X \n", sum_calculated);
+ bt_debug("sum_expected: %08X \n", sum_expected);
+
+ bt_assert(sum_calculated == sum_expected);
+
+ return 1;
+}
+
+static int
+t_verify(void)
+{
+ u32 a[MAX_NUM+1];
+ int i;
+
+ for (i = 0; i < MAX_NUM; i++)
+ a[i] = bt_random();
+
+ u16 sum = ipsum_calculate_expected(a);
+
+ a[MAX_NUM] = sum;
+
+ bt_assert(ipsum_verify(a, sizeof(a), NULL));
+
+ return 1;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_calculate, "Checksum of pseudo-random data");
+ bt_test_suite(t_verify, "Verification of pseudo-random data.");
+
+ return bt_exit_value();
+}
diff --git a/lib/event_test.c b/lib/event_test.c
new file mode 100644
index 00000000..92172389
--- /dev/null
+++ b/lib/event_test.c
@@ -0,0 +1,88 @@
+/*
+ * BIRD Library -- Event Processing Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+
+#include "test/birdtest.h"
+
+#include "lib/net.h"
+#include "lib/event.h"
+#include "conf/conf.h"
+#include "nest/locks.h"
+#include "sysdep/unix/unix.h"
+#include "nest/iface.h"
+#include "nest/route.h"
+
+#define MAX_NUM 4
+
+int event_check_points[MAX_NUM];
+
+#define event_hook_body(num) \
+ do { \
+ bt_debug("Event Hook " #num "\n"); \
+ event_check_points[num] = 1; \
+ bt_assert_msg(event_check_points[num-1], "Events should be run in right order"); \
+ } while (0)
+
+static void event_hook_1(void *data UNUSED) { event_hook_body(1); }
+static void event_hook_2(void *data UNUSED) { event_hook_body(2); }
+static void event_hook_3(void *data UNUSED) { event_hook_body(3); }
+
+#define schedule_event(num) \
+ do { \
+ struct event *event_##num = ev_new(&root_pool); \
+ event_##num->hook = event_hook_##num; \
+ ev_schedule(event_##num); \
+ } while (0)
+
+static void
+init_event_check_points(void)
+{
+ int i;
+ event_check_points[0] = 1;
+ for (i = 1; i < MAX_NUM; i++)
+ event_check_points[i] = 0;
+}
+
+static int
+t_ev_run_list(void)
+{
+ int i;
+
+ resource_init();
+ olock_init();
+ io_init();
+ rt_init();
+ if_init();
+// roa_init();
+ config_init();
+ config = config_alloc("");
+
+ init_event_check_points();
+
+ schedule_event(1);
+ schedule_event(2);
+ schedule_event(3);
+
+ ev_run_list(&global_event_list);
+
+ for (i = 1; i < MAX_NUM; i++)
+ bt_assert(event_check_points[i]);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_ev_run_list, "Schedule and run 3 events in right order.");
+
+ return bt_exit_value();
+}
+
diff --git a/lib/fletcher16_test.c b/lib/fletcher16_test.c
new file mode 100644
index 00000000..1020e6ec
--- /dev/null
+++ b/lib/fletcher16_test.c
@@ -0,0 +1,169 @@
+/*
+ * BIRD Library -- Fletcher-16 Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "lib/fletcher16.h"
+
+static u16
+straightforward_fletcher16_compute(const char *data)
+{
+ int count = strlen(data);
+
+ u16 sum1 = 0;
+ u16 sum2 = 0;
+ int index;
+
+ for (index = 0; index < count; ++index)
+ {
+ sum1 = (sum1 + data[index]) % 255;
+ sum2 = (sum2 + sum1) % 255;
+ }
+
+ return (sum2 << 8) | sum1;
+}
+
+static u16
+straightforward_fletcher16_checksum(const char *data)
+{
+ u16 csum;
+ u8 c0,c1,f0,f1;
+
+ csum = straightforward_fletcher16_compute(data);
+ f0 = csum & 0xff;
+ f1 = (csum >> 8) & 0xff;
+ c0 = 0xff - ((f0 + f1) % 0xff);
+ c1 = 0xff - ((f0 + c0) % 0xff);
+
+ return (c1 << 8) | c0;
+}
+
+static int
+test_fletcher16(void *out_, const void *in_, const void *expected_out_)
+{
+ u16 *out = out_;
+ const char *in = in_;
+ const u16 *expected_out = expected_out_;
+
+ struct fletcher16_context ctxt;
+
+ fletcher16_init(&ctxt);
+ fletcher16_update(&ctxt, in, strlen(in));
+ put_u16(out, fletcher16_compute(&ctxt));
+
+ return *out == *expected_out;
+}
+
+static int
+test_fletcher16_checksum(void *out_, const void *in_, const void *expected_out_)
+{
+ u16 *out = out_;
+ const char *in = in_;
+ const u16 *expected_out = expected_out_;
+
+ struct fletcher16_context ctxt;
+ int len = strlen(in);
+
+ fletcher16_init(&ctxt);
+ fletcher16_update(&ctxt, in, len);
+ put_u16(out, fletcher16_final(&ctxt, len, len));
+
+ return *out == *expected_out;
+}
+
+static int
+t_fletcher16_compute(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "\001\002",
+ .out = & (const u16) { 0x0403 },
+ },
+ {
+ .in = "",
+ .out = & ((const u16) { straightforward_fletcher16_compute("") }),
+ },
+ {
+ .in = "a",
+ .out = & ((const u16) { straightforward_fletcher16_compute("a") }),
+ },
+ {
+ .in = "abcd",
+ .out = & ((const u16) { straightforward_fletcher16_compute("abcd") }),
+ },
+ {
+ .in = "message digest",
+ .out = & ((const u16) { straightforward_fletcher16_compute("message digest") }),
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = & ((const u16) { straightforward_fletcher16_compute("abcdefghijklmnopqrstuvwxyz") }),
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = & ((const u16) { straightforward_fletcher16_compute("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = & ((const u16) { straightforward_fletcher16_compute("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_fletcher16, bt_fmt_str, bt_fmt_unsigned);
+}
+
+static int
+t_fletcher16_checksum(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "\001\002",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("\001\002") }),
+ },
+ {
+ .in = "",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("") }),
+ },
+ {
+ .in = "a",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("a") }),
+ },
+ {
+ .in = "abcd",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("abcd") }),
+ },
+ {
+ .in = "message digest",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("message digest") }),
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("abcdefghijklmnopqrstuvwxyz") }),
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") }),
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = & ((const u16) { straightforward_fletcher16_checksum("12345678901234567890123456789012345678901234567890123456789012345678901234567890") }),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_fletcher16_checksum, bt_fmt_str, bt_fmt_unsigned);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_fletcher16_compute, "Fletcher-16 Compute Tests");
+ bt_test_suite(t_fletcher16_checksum, "Fletcher-16 Checksum Tests");
+
+ return bt_exit_value();
+}
diff --git a/lib/hash.h b/lib/hash.h
index c2fd8bca..b37d8fa5 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -1,8 +1,18 @@
-
+/*
+ * BIRD Library -- Generic Hash Table
+ *
+ * (c) 2013 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2013 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_HASH_H_
+#define _BIRD_HASH_H_
#define HASH(type) struct { type **data; uint count, order; }
#define HASH_TYPE(v) typeof(** (v).data)
-#define HASH_SIZE(v) (1 << (v).order)
+#define HASH_SIZE(v) (1U << (v).order)
#define HASH_EQ(v,id,k1,k2...) (id##_EQ(k1, k2))
#define HASH_FN(v,id,key...) ((u32) (id##_FN(key)) >> (32 - (v).order))
@@ -116,12 +126,12 @@
#define HASH_MAY_RESIZE_DOWN_(v,pool,rehash_fn,args) \
({ \
- int _o = (v).order; \
- while (((v).count < ((1 << _o) REHASH_LO_MARK(args))) && \
+ uint _o = (v).order; \
+ while (((v).count < ((1U << _o) REHASH_LO_MARK(args))) && \
(_o > (REHASH_LO_BOUND(args)))) \
_o -= (REHASH_LO_STEP(args)); \
if (_o < (v).order) \
- rehash_fn(&(v), pool, _o - (int) (v).order); \
+ rehash_fn(&(v), pool, _o - (v).order); \
})
@@ -178,6 +188,7 @@
#define HASH_WALK_FILTER_END } while (0)
+
static inline void
mem_hash_init(u64 *h)
{
@@ -185,14 +196,15 @@ mem_hash_init(u64 *h)
}
static inline void
-mem_hash_mix(u64 *h, void *p, int s)
+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];
}
@@ -204,7 +216,7 @@ mem_hash_value(u64 *h)
}
static inline uint
-mem_hash(void *p, int s)
+mem_hash(void *p, uint s)
{
static u64 h;
mem_hash_init(&h);
@@ -212,3 +224,4 @@ mem_hash(void *p, int s)
return mem_hash_value(&h);
}
+#endif
diff --git a/lib/hash_test.c b/lib/hash_test.c
new file mode 100644
index 00000000..59beb7c0
--- /dev/null
+++ b/lib/hash_test.c
@@ -0,0 +1,305 @@
+/*
+ * BIRD Library -- Hash Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#undef LOCAL_DEBUG
+
+#include "test/birdtest.h"
+
+#include "lib/hash.h"
+
+struct test_node {
+ struct test_node *next; /* Hash chain */
+ u32 key;
+};
+
+#define TEST_KEY(n) n->key
+#define TEST_NEXT(n) n->next
+#define TEST_EQ(n1,n2) n1 == n2
+#define TEST_FN(n) (n) ^ u32_hash((n))
+#define TEST_ORDER 13
+#define TEST_PARAMS /TEST_ORDER, *2, 2, 2, TEST_ORDER, 20
+#define TEST_REHASH test_rehash
+
+HASH_DEFINE_REHASH_FN(TEST, struct test_node);
+
+HASH(struct test_node) hash;
+struct pool *my_pool;
+
+#define MAX_NUM (1 << TEST_ORDER)
+
+struct test_node nodes[MAX_NUM];
+
+static void
+print_rate_of_fulfilment(void)
+{
+ int i;
+ int num_stacked_items = 0;
+
+ for (i = 0; i < MAX_NUM; i++)
+ if (!hash.data[i])
+ num_stacked_items++;
+
+ double percent_stacked_items = ((double)num_stacked_items/(double)MAX_NUM)*100.;
+ bt_debug("%d (%.2f %%) chained of %d hashes \n", num_stacked_items, percent_stacked_items, MAX_NUM);
+}
+
+#ifdef LOCAL_DEBUG
+static void
+dump_nodes(void)
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_debug("nodes[%3d] is at address %14p has .key %3d, .next %14p \n", i, &nodes[i], nodes[i].key, nodes[i].next);
+}
+#endif
+
+static void
+init_hash_(uint order)
+{
+ resource_init();
+ my_pool = rp_new(&root_pool, "Test pool");
+
+ HASH_INIT(hash, my_pool, order);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ nodes[i].next = NULL;
+ }
+
+ bt_debug("MAX_NUM %d \n", MAX_NUM);
+}
+
+static void
+init_hash(void)
+{
+ init_hash_(TEST_ORDER);
+}
+
+static void
+validate_filled_hash(void)
+{
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ node = HASH_FIND(hash, TEST, nodes[i].key);
+ bt_assert_msg(node->key == nodes[i].key, "Hash should be filled, to find (%p) the node[%d] (%p) with .key = %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
+ }
+
+ print_rate_of_fulfilment();
+}
+
+static void
+validate_empty_hash(void)
+{
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ node = HASH_FIND(hash, TEST, nodes[i].key);
+ bt_assert_msg(node == NULL, "Hash should be empty, to find (%p) the node[%d] (%p) with .key %u, .next %p", node, i, &nodes[i], nodes[i].key, nodes[i].next);
+ }
+}
+
+static void
+fill_hash(void)
+{
+ int i;
+ struct test_node *node;
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ node = &nodes[i];
+ HASH_INSERT(hash, TEST, node);
+ }
+}
+
+static int
+t_insert_find(void)
+{
+ init_hash();
+ fill_hash();
+ validate_filled_hash();
+
+ return 1;
+}
+
+static int
+t_insert_find_random(void)
+{
+ init_hash();
+
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = bt_random();
+ node = &nodes[i];
+ HASH_INSERT(hash, TEST, node);
+ }
+
+ validate_filled_hash();
+
+ return 1;
+}
+
+static int
+t_insert2_find(void)
+{
+ init_hash_(1);
+
+ int i;
+ struct test_node *node;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].key = i;
+ node = &nodes[i];
+ HASH_INSERT2(hash, TEST, my_pool, node);
+ }
+ bt_assert_msg(hash.order != 1, "The hash should auto-resize from order 2^1. The order of the hash is 2^%u.", hash.order);
+
+ validate_filled_hash();
+
+ return 1;
+}
+
+static int
+t_walk(void)
+{
+ init_hash();
+ fill_hash();
+
+ uint i;
+ uint check[MAX_NUM];
+ for (i = 0; i < MAX_NUM; i++)
+ check[i] = 0;
+
+ HASH_WALK(hash, next, n)
+ {
+ check[n->key]++;
+ }
+ HASH_WALK_END;
+
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(check[i] == 1);
+
+ return 1;
+}
+
+static int
+t_walk_delsafe_delete(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_DELETE(hash, TEST, n->key);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return 1;
+}
+
+static int
+t_walk_delsafe_remove(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_REMOVE(hash, TEST, n);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return 1;
+}
+
+static int
+t_walk_delsafe_delete2(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_DELETE2(hash, TEST, my_pool, n->key);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return 1;
+}
+
+static int
+t_walk_delsafe_remove2(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK_DELSAFE(hash, next, n)
+ {
+ HASH_REMOVE2(hash, TEST, my_pool, n);
+ }
+ HASH_WALK_DELSAFE_END;
+
+ validate_empty_hash();
+
+ return 1;
+}
+
+static int
+t_walk_filter(void)
+{
+ init_hash();
+ fill_hash();
+
+ uint i;
+ uint check[MAX_NUM];
+ for (i = 0; i < MAX_NUM; i++)
+ check[i] = 0;
+
+ HASH_WALK_FILTER(hash, next, n, m)
+ {
+ bt_assert(n == *m);
+ check[n->key]++;
+ }
+ HASH_WALK_FILTER_END;
+
+ for (i = 0; i < MAX_NUM; i++)
+ bt_assert(check[i] == 1);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_insert_find, "HASH_INSERT and HASH_FIND");
+ bt_test_suite(t_insert_find_random, "HASH_INSERT pseudo-random keys and HASH_FIND");
+ bt_test_suite(t_insert2_find, "HASH_INSERT2 and HASH_FIND. HASH_INSERT2 is HASH_INSERT and a smart auto-resize function");
+ bt_test_suite(t_walk, "HASH_WALK");
+ bt_test_suite(t_walk_delsafe_delete, "HASH_WALK_DELSAFE and HASH_DELETE");
+ bt_test_suite(t_walk_delsafe_delete2, "HASH_WALK_DELSAFE and HASH_DELETE2. HASH_DELETE2 is HASH_DELETE and smart auto-resize function");
+ bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
+ bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
+ bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
+
+ return bt_exit_value();
+}
diff --git a/lib/heap_test.c b/lib/heap_test.c
new file mode 100644
index 00000000..c04a0450
--- /dev/null
+++ b/lib/heap_test.c
@@ -0,0 +1,186 @@
+/*
+ * BIRD Library -- Universal Heap Macros Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "sysdep/config.h"
+#include "lib/heap.h"
+
+#define MAX_NUM 1000
+#define SPECIAL_KEY -3213
+
+#define MY_CMP(x, y) ((x) < (y))
+
+#define MY_HEAP_SWAP(heap,a,b,t) \
+ do { \
+ bt_debug("swap(%u %u) ", a, b); \
+ HEAP_SWAP(heap,a,b,t); \
+ } while(0)
+
+static int heap[MAX_NUM+1];
+static uint num;
+
+/*
+ * A valid heap must follow these rules:
+ * - `num >= 0`
+ * - `heap[i] >= heap[i / 2]` for each `i` in `[2, num]`
+ */
+static int
+is_heap_valid(int heap[], uint num)
+{
+ uint i;
+
+ if (num > MAX_NUM)
+ return 0;
+
+ for (i = 2; i <= num; i++)
+ if (heap[i] < heap[i / 2])
+ return 0;
+
+ return 1;
+}
+
+static void
+show_heap(void)
+{
+ uint i;
+ bt_debug("\n");
+ bt_debug("numbers %u; ", num);
+ for (i = 0; i <= num; i++)
+ bt_debug("%d ", heap[i]);
+ bt_debug(is_heap_valid(heap, num) ? "OK" : "NON-VALID HEAP!");
+ bt_debug("\n");
+}
+
+static void
+init_heap(void)
+{
+ uint i;
+ num = 0;
+ heap[0] = SPECIAL_KEY; /* heap[0] should be unused */
+ for (i = 1; i <= MAX_NUM; i++)
+ heap[i] = 0;
+}
+
+static int
+t_heap_insert(void)
+{
+ uint i;
+
+ init_heap();
+
+ for (i = MAX_NUM; i >= 1; i--)
+ {
+ bt_debug("ins %u at pos %u ", i, MAX_NUM - i);
+ heap[MAX_NUM - i + 1] = i;
+ HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return 1;
+}
+
+static int
+t_heap_increase_decrease(void)
+{
+ uint i;
+
+ t_heap_insert();
+
+ for (i = 1; i <= MAX_NUM; i++)
+ {
+ if ((int)i > heap[i])
+ {
+ bt_debug("inc %u ", i);
+ heap[i] = i;
+ HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ }
+ else if ((int)i < heap[i])
+ {
+ bt_debug("dec %u ", i);
+ heap[i] = i;
+ HEAP_INCREASE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ }
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return 1;
+}
+
+static int
+t_heap_delete(void)
+{
+ uint i;
+
+ t_heap_insert();
+
+ for (i = 1; i <= num; i++)
+ {
+ bt_debug("del at pos %u ", i);
+ HEAP_DELETE(heap, num, int, MY_CMP, MY_HEAP_SWAP, i);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ return 1;
+}
+
+static int
+t_heap_0(void)
+{
+ init_heap();
+ t_heap_insert();
+ t_heap_increase_decrease();
+ t_heap_delete();
+
+ return heap[0] == SPECIAL_KEY;
+}
+
+static int
+t_heap_insert_random(void)
+{
+ int i, j;
+ int expected[MAX_NUM+1];
+
+ init_heap();
+
+ for (i = 1; i <= MAX_NUM; i++)
+ {
+ heap[i] = expected[i] = bt_random();
+ HEAP_INSERT(heap, ++num, int, MY_CMP, MY_HEAP_SWAP);
+ show_heap();
+ bt_assert(is_heap_valid(heap, num));
+ }
+
+ for (i = 1; i <= MAX_NUM; i++)
+ for (j = 1; j <= MAX_NUM; j++)
+ if(expected[i] == heap[j])
+ break;
+ else if (j == MAX_NUM)
+ {
+ show_heap();
+ bt_abort_msg("Did not find a number %d in heap.", expected[i]);
+ }
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_heap_insert, "Inserting a descending sequence of numbers (the worst case)");
+ bt_test_suite(t_heap_insert_random, "Inserting pseudo-random numbers");
+ bt_test_suite(t_heap_increase_decrease, "Increasing/Decreasing");
+ bt_test_suite(t_heap_delete, "Deleting");
+ bt_test_suite(t_heap_0, "Is a heap[0] really unused?");
+
+ return bt_exit_value();
+}
diff --git a/lib/idm.c b/lib/idm.c
index 16d0e855..66e311c6 100644
--- a/lib/idm.c
+++ b/lib/idm.c
@@ -53,7 +53,7 @@ idm_alloc(struct idm *m)
ASSERT(0);
- found:
+found:
ASSERT(i < 0x8000000);
m->pos = i;
diff --git a/lib/ip.c b/lib/ip.c
index 5e039c12..9497248c 100644
--- a/lib/ip.c
+++ b/lib/ip.c
@@ -306,7 +306,7 @@ ip6_pton(const char *a, ip6_addr *o)
if (*a == ':' && a[1])
a++;
- else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
+ else if (*a == '.' && (i == 6 || (i < 6 && hfil >= 0)))
{ /* Embedded IPv4 address */
ip4_addr x;
if (!ip4_pton(start, &x))
diff --git a/lib/ip.h b/lib/ip.h
index 6541ce1e..86750675 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -91,6 +91,7 @@ typedef ip6_addr ip_addr;
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
#define ipa_is_ip4(a) ip6_is_v4mapped(a)
+#define ipa_is_ip6(a) (! ip6_is_v4mapped(a))
#define IPA_NONE4 ipa_from_ip4(IP4_NONE)
#define IPA_NONE6 ipa_from_ip6(IP6_NONE)
diff --git a/lib/ip_test.c b/lib/ip_test.c
new file mode 100644
index 00000000..fd70c957
--- /dev/null
+++ b/lib/ip_test.c
@@ -0,0 +1,161 @@
+/*
+ * BIRD Library -- IP address functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/ip.h"
+
+#define IP4_MAX_LEN 16
+
+static int
+test_ipa_pton(void *out_, const void *in_, const void *expected_out_)
+{
+ ip_addr *out = out_;
+ const char *in = in_;
+ const ip_addr *expected_out = expected_out_;
+
+ if (ipa_is_ip4(*expected_out))
+ {
+ ip4_addr ip4;
+ bt_assert(ip4_pton(in, &ip4));
+ *out = ipa_from_ip4(ip4);
+ }
+ else
+ {
+ bt_assert(ip6_pton(in, out));
+ /* ip_addr == ip6_addr */
+ }
+
+ return ipa_equal(*out, *expected_out);
+}
+
+static int
+t_ip4_pton(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "192.168.1.128",
+ .out = & ipa_build4(192, 168, 1, 128),
+ },
+ {
+ .in = "255.255.255.255",
+ .out = & ipa_build4(255, 255, 255, 255),
+ },
+ {
+ .in = "0.0.0.0",
+ .out = & ipa_build4(0, 0, 0, 0),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+}
+
+static int
+t_ip6_pton(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "2001:0db8:0000:0000:0000:0000:1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:0db8:0000:0000:0000::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:0db8::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "2001:db8::1428:57ab",
+ .out = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ },
+ {
+ .in = "::1",
+ .out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000001),
+ },
+ {
+ .in = "::",
+ .out = & ipa_build6(0x00000000, 0x00000000, 0x00000000, 0x00000000),
+ },
+ {
+ .in = "2605:2700:0:3::4713:93e3",
+ .out = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+}
+
+static int
+test_ipa_ntop(void *out_, const void *in_, const void *expected_out_)
+{
+ char *out = out_;
+ const ip_addr *in = in_;
+ const char *expected_out = expected_out_;
+
+ if (ipa_is_ip4(*in))
+ ip4_ntop(ipa_to_ip4(*in), out);
+ else
+ ip6_ntop(ipa_to_ip6(*in), out);
+
+ int result = strncmp(out, expected_out, ipa_is_ip4(*in) ? IP4_MAX_TEXT_LENGTH : IP6_MAX_TEXT_LENGTH) == 0;
+ return result;
+}
+
+static int
+t_ip4_ntop(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & ipa_build4(192, 168, 1, 128),
+ .out = "192.168.1.128",
+ },
+ {
+ .in = & ipa_build4(255, 255, 255, 255),
+ .out = "255.255.255.255",
+ },
+ {
+ .in = & ipa_build4(0, 0, 0, 1),
+ .out = "0.0.0.1",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
+}
+
+static int
+t_ip6_ntop(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & ipa_build6(0x20010DB8, 0x00000000, 0x00000000, 0x142857AB),
+ .out = "2001:db8::1428:57ab",
+ },
+ {
+ .in = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
+ .out = "2605:2700:0:3::4713:93e3",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_ip4_pton, "Converting IPv4 string to ip4_addr struct");
+ bt_test_suite(t_ip6_pton, "Converting IPv6 string to ip6_addr struct");
+ bt_test_suite(t_ip4_ntop, "Converting ip4_addr struct to IPv4 string");
+ bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
+
+ return bt_exit_value();
+}
+
diff --git a/lib/lists.c b/lib/lists.c
index 12ef3cc6..4a48d3b7 100644
--- a/lib/lists.c
+++ b/lib/lists.c
@@ -158,3 +158,15 @@ add_tail_list(list *to, list *l)
q->next = &to->tail_node;
to->tail = q;
}
+
+LIST_INLINE uint
+list_length(list *l)
+{
+ uint len = 0;
+ node *n;
+
+ WALK_LIST(n, *l)
+ len++;
+
+ return len;
+}
diff --git a/lib/lists.h b/lib/lists.h
index 46b33446..066eafbb 100644
--- a/lib/lists.h
+++ b/lib/lists.h
@@ -80,6 +80,7 @@ void rem_node(node *);
void add_tail_list(list *, list *);
void init_list(list *);
void insert_node(node *, node *);
+uint list_length(list *);
#endif
#endif
diff --git a/lib/lists_test.c b/lib/lists_test.c
new file mode 100644
index 00000000..f26a88e2
--- /dev/null
+++ b/lib/lists_test.c
@@ -0,0 +1,287 @@
+/*
+ * BIRD Library -- Linked Lists Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "lib/lists.h"
+
+#define MAX_NUM 1000
+
+static node nodes[MAX_NUM];
+static list l;
+
+static void
+show_list(void)
+{
+ bt_debug("\n");
+ bt_debug("list.null is at %p and point to %p\n", &l.null, l.null);
+ bt_debug("list.head is at %p and point to %p\n", &l.head, l.head);
+ bt_debug("list.tail is at %p and point to %p\n", &l.tail, l.tail);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ bt_debug("n[%3i] is at %p\n", i, &nodes[i]);
+ bt_debug(" prev is at %p and point to %p\n", &(nodes[i].prev), nodes[i].prev);
+ bt_debug(" next is at %p and point to %p\n", &(nodes[i].next), nodes[i].next);
+ }
+}
+
+static int
+is_filled_list_well_linked(void)
+{
+ int i;
+ bt_assert(l.head == &nodes[0]);
+ bt_assert(l.tail == &nodes[MAX_NUM-1]);
+ bt_assert((void *) nodes[0].prev == (void *) &l.head);
+ bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &l.null);
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ if (i < (MAX_NUM-1))
+ bt_assert(nodes[i].next == &nodes[i+1]);
+
+ if (i > 0)
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+
+ return 1;
+}
+
+static int
+is_empty_list_well_unlinked(void)
+{
+ int i;
+
+ bt_assert(l.head == NODE &l.null);
+ bt_assert(l.tail == NODE &l.head);
+ bt_assert(EMPTY_LIST(l));
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ bt_assert(nodes[i].next == NULL);
+ bt_assert(nodes[i].prev == NULL);
+ }
+
+ return 1;
+}
+
+static void
+init_list__(list *l, struct node nodes[])
+{
+ init_list(l);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].next = NULL;
+ nodes[i].prev = NULL;
+ }
+}
+
+static void
+init_list_(void)
+{
+ init_list__(&l, (node *) nodes);
+}
+
+static int
+t_add_tail(void)
+{
+ int i;
+
+ init_list_();
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ add_tail(&l, &nodes[i]);
+ bt_debug(".");
+ bt_assert(l.tail == &nodes[i]);
+ bt_assert(l.head == &nodes[0]);
+ bt_assert((void *) nodes[i].next == (void *) &l.null);
+ if (i > 0)
+ {
+ bt_assert(nodes[i-1].next == &nodes[i]);
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+ }
+ show_list();
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static int
+t_add_head(void)
+{
+ int i;
+
+ init_list_();
+ for (i = MAX_NUM-1; i >= 0; i--)
+ {
+ add_head(&l, &nodes[i]);
+ bt_debug(".");
+ bt_assert(l.head == &nodes[i]);
+ bt_assert(l.tail == &nodes[MAX_NUM-1]);
+ if (i < MAX_NUM-1)
+ {
+ bt_assert(nodes[i+1].prev == &nodes[i]);
+ bt_assert(nodes[i].next == &nodes[i+1]);
+ }
+ }
+ show_list();
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static void
+insert_node_(node *n, node *after)
+{
+ insert_node(n, after);
+ bt_debug(".");
+}
+
+static int
+t_insert_node(void)
+{
+ int i;
+
+ init_list_();
+
+ // add first node
+ insert_node_(&nodes[0], NODE &l.head);
+
+ // add odd nodes
+ for (i = 2; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-2]);
+
+ // add even nodes
+ for (i = 1; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-1]);
+
+ bt_debug("\n");
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static void
+fill_list2(list *l, node nodes[])
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ add_tail(l, &nodes[i]);
+}
+
+static void
+fill_list(void)
+{
+ fill_list2(&l, (node *) nodes);
+}
+
+static int
+t_remove_node(void)
+{
+ int i;
+
+ init_list_();
+
+ /* Fill & Remove & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i++)
+ rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ /* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i+=2)
+ rem_node(&nodes[i]);
+
+ int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
+ bt_assert(l.head == &nodes[1]);
+ bt_assert(l.tail == &nodes[tail_node_index]);
+ bt_assert(nodes[tail_node_index].next == NODE &l.null);
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ {
+ if (i > 1)
+ bt_assert(nodes[i].prev == &nodes[i-2]);
+ if (i < tail_node_index)
+ bt_assert(nodes[i].next == &nodes[i+2]);
+ }
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ return 1;
+}
+
+static int
+t_replace_node(void)
+{
+ node head, inside, tail;
+
+ init_list_();
+ fill_list();
+
+ replace_node(&nodes[0], &head);
+ bt_assert(l.head == &head);
+ bt_assert(head.prev == NODE &l.head);
+ bt_assert(head.next == &nodes[1]);
+ bt_assert(nodes[1].prev == &head);
+
+ replace_node(&nodes[MAX_NUM/2], &inside);
+ bt_assert(nodes[MAX_NUM/2-1].next == &inside);
+ bt_assert(nodes[MAX_NUM/2+1].prev == &inside);
+ bt_assert(inside.prev == &nodes[MAX_NUM/2-1]);
+ bt_assert(inside.next == &nodes[MAX_NUM/2+1]);
+
+ replace_node(&nodes[MAX_NUM-1], &tail);
+ bt_assert(l.tail == &tail);
+ bt_assert(tail.prev == &nodes[MAX_NUM-2]);
+ bt_assert(tail.next == NODE &l.null);
+ bt_assert(nodes[MAX_NUM-2].next == &tail);
+
+ return 1;
+}
+
+static int
+t_add_tail_list(void)
+{
+ node nodes2[MAX_NUM];
+ list l2;
+
+ init_list__(&l, (node *) nodes);
+ fill_list2(&l, (node *) nodes);
+
+ init_list__(&l2, (node *) nodes2);
+ fill_list2(&l2, (node *) nodes2);
+
+ add_tail_list(&l, &l2);
+
+ bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
+ bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
+ bt_assert(l.tail == &nodes2[MAX_NUM-1]);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_add_tail, "Adding nodes to tail of list");
+ bt_test_suite(t_add_head, "Adding nodes to head of list");
+ bt_test_suite(t_insert_node, "Inserting nodes to list");
+ bt_test_suite(t_remove_node, "Removing nodes from list");
+ bt_test_suite(t_replace_node, "Replacing nodes in list");
+ bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
+
+ return bt_exit_value();
+}
diff --git a/lib/mac.c b/lib/mac.c
new file mode 100644
index 00000000..977d6559
--- /dev/null
+++ b/lib/mac.c
@@ -0,0 +1,289 @@
+/*
+ * BIRD Library -- Message Authentication Codes
+ *
+ * (c) 2016 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2016 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/**
+ * DOC: Message authentication codes
+ *
+ * MAC algorithms are simple cryptographic tools for message authentication.
+ * They use shared a secret key a and message text to generate authentication
+ * code, which is then passed with the message to the other side, where the code
+ * is verified. There are multiple families of MAC algorithms based on different
+ * cryptographic primitives, BIRD implements two MAC families which use hash
+ * functions.
+ *
+ * The first family is simply a cryptographic hash camouflaged as MAC algorithm.
+ * Originally supposed to be (m|k)-hash (message is concatenated with key, and
+ * that is hashed), but later it turned out that a raw hash is more practical.
+ * This is used for cryptographic authentication in OSPFv2, RIP and BFD.
+ *
+ * The second family is the standard HMAC (RFC 2104), using inner and outer hash
+ * to process key and message. HMAC (with SHA) is used in advanced OSPF and RIP
+ * authentication (RFC 5709, RFC 4822).
+ */
+
+#include "lib/mac.h"
+#include "lib/md5.h"
+#include "lib/sha1.h"
+#include "lib/sha256.h"
+#include "lib/sha512.h"
+
+
+/*
+ * Internal hash calls
+ */
+
+static inline void
+hash_init(struct mac_context *mctx, struct hash_context *hctx)
+{ mctx->type->hash_init(hctx); }
+
+static inline void
+hash_update(struct mac_context *mctx, struct hash_context *hctx, const byte *buf, uint len)
+{ mctx->type->hash_update(hctx, buf, len); }
+
+static inline byte *
+hash_final(struct mac_context *mctx, struct hash_context *hctx)
+{ return mctx->type->hash_final(hctx); }
+
+static inline void
+hash_buffer(struct mac_context *mctx, byte *outbuf, const byte *buffer, uint length)
+{
+ struct hash_context hctx;
+
+ hash_init(mctx, &hctx);
+ hash_update(mctx, &hctx, buffer, length);
+ memcpy(outbuf, hash_final(mctx, &hctx), mctx->type->hash_size);
+}
+
+
+/*
+ * (not-really-MAC) Hash
+ */
+
+static void
+nrmh_init(struct mac_context *ctx, const byte *key UNUSED, uint keylen UNUSED)
+{
+ struct nrmh_context *ct = (void *) ctx;
+ hash_init(ctx, &ct->ictx);
+}
+
+static void
+nrmh_update(struct mac_context *ctx, const byte *data, uint datalen)
+{
+ struct nrmh_context *ct = (void *) ctx;
+ hash_update(ctx, &ct->ictx, data, datalen);
+}
+
+static byte *
+nrmh_final(struct mac_context *ctx)
+{
+ struct nrmh_context *ct = (void *) ctx;
+ return hash_final(ctx, &ct->ictx);
+}
+
+
+/*
+ * HMAC
+ */
+
+static void
+hmac_init(struct mac_context *ctx, const byte *key, uint keylen)
+{
+ struct hmac_context *ct = (void *) ctx;
+ uint block_size = ctx->type->block_size;
+ uint hash_size = ctx->type->hash_size;
+
+ byte *keybuf = alloca(block_size);
+ byte *buf = alloca(block_size);
+ uint i;
+
+ /* Hash the key if necessary */
+ if (keylen <= block_size)
+ {
+ memcpy(keybuf, key, keylen);
+ memset(keybuf + keylen, 0, block_size - keylen);
+ }
+ else
+ {
+ hash_buffer(ctx, keybuf, key, keylen);
+ memset(keybuf + hash_size, 0, block_size - hash_size);
+ }
+
+ /* Initialize the inner digest */
+ hash_init(ctx, &ct->ictx);
+ for (i = 0; i < block_size; i++)
+ buf[i] = keybuf[i] ^ 0x36;
+ hash_update(ctx, &ct->ictx, buf, block_size);
+
+ /* Initialize the outer digest */
+ hash_init(ctx, &ct->octx);
+ for (i = 0; i < block_size; i++)
+ buf[i] = keybuf[i] ^ 0x5c;
+ hash_update(ctx, &ct->octx, buf, block_size);
+}
+
+static void
+hmac_update(struct mac_context *ctx, const byte *data, uint datalen)
+{
+ struct hmac_context *ct = (void *) ctx;
+
+ /* Just update the inner digest */
+ hash_update(ctx, &ct->ictx, data, datalen);
+}
+
+static byte *
+hmac_final(struct mac_context *ctx)
+{
+ struct hmac_context *ct = (void *) ctx;
+
+ /* Finish the inner digest */
+ byte *isha = hash_final(ctx, &ct->ictx);
+
+ /* Finish the outer digest */
+ hash_update(ctx, &ct->octx, isha, ctx->type->hash_size);
+ return hash_final(ctx, &ct->octx);
+}
+
+
+/*
+ * Common code
+ */
+
+#define HASH_DESC(name, px, PX) \
+ { name, PX##_SIZE, sizeof(struct nrmh_context), nrmh_init, nrmh_update, nrmh_final, \
+ PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
+
+#define HMAC_DESC(name, px, PX) \
+ { name, PX##_SIZE, sizeof(struct hmac_context), hmac_init, hmac_update, hmac_final, \
+ PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
+
+const struct mac_desc mac_table[ALG_MAX] = {
+ [ALG_MD5] = HASH_DESC("Keyed MD5", md5, MD5),
+ [ALG_SHA1] = HASH_DESC("Keyed SHA-1", sha1, SHA1),
+ [ALG_SHA224] = HASH_DESC("Keyed SHA-224", sha224, SHA224),
+ [ALG_SHA256] = HASH_DESC("Keyed SHA-256", sha256, SHA256),
+ [ALG_SHA384] = HASH_DESC("Keyed SHA-384", sha384, SHA384),
+ [ALG_SHA512] = HASH_DESC("Keyed SHA-512", sha512, SHA512),
+ [ALG_HMAC_MD5] = HMAC_DESC("HMAC-MD5", md5, MD5),
+ [ALG_HMAC_SHA1] = HMAC_DESC("HMAC-SHA-1", sha1, SHA1),
+ [ALG_HMAC_SHA224] = HMAC_DESC("HMAC-SHA-224", sha224, SHA224),
+ [ALG_HMAC_SHA256] = HMAC_DESC("HMAC-SHA-256", sha256, SHA256),
+ [ALG_HMAC_SHA384] = HMAC_DESC("HMAC-SHA-384", sha384, SHA384),
+ [ALG_HMAC_SHA512] = HMAC_DESC("HMAC-SHA-512", sha512, SHA512),
+};
+
+
+/**
+ * mac_init - initialize MAC algorithm
+ * @ctx: context to initialize
+ * @id: MAC algorithm ID
+ * @key: MAC key
+ * @keylen: MAC key length
+ *
+ * Initialize MAC context @ctx for algorithm @id (e.g., %ALG_HMAC_SHA1), with
+ * key @key of length @keylen. After that, message data could be added using
+ * mac_update() function.
+ */
+void
+mac_init(struct mac_context *ctx, uint id, const byte *key, uint keylen)
+{
+ ctx->type = &mac_table[id];
+ ctx->type->init(ctx, key, keylen);
+}
+
+#if 0
+/**
+ * mac_update - add more data to MAC algorithm
+ * @ctx: MAC context
+ * @data: data to add
+ * @datalen: length of data
+ *
+ * Push another @datalen bytes of data pointed to by @data into the MAC
+ * algorithm currently in @ctx. Can be called multiple times for the same MAC
+ * context. It has the same effect as concatenating all the data together and
+ * passing them at once.
+ */
+void mac_update(struct mac_context *ctx, const byte *data, uint datalen)
+{ DUMMY; }
+
+/**
+ * mac_final - finalize MAC algorithm
+ * @ctx: MAC context
+ *
+ * Finish MAC computation and return a pointer to the result. No more
+ * @mac_update() calls could be done, but the context may be reinitialized
+ * later.
+ *
+ * Note that the returned pointer points into data in the @ctx context. If it
+ * ceases to exist, the pointer becomes invalid.
+ */
+byte *mac_final(struct mac_context *ctx)
+{ DUMMY; }
+
+/**
+ * mac_cleanup - cleanup MAC context
+ * @ctx: MAC context
+ *
+ * Cleanup MAC context after computation (by filling with zeros). Not strictly
+ * necessary, just to erase sensitive data from stack. This also invalidates the
+ * pointer returned by @mac_final().
+ */
+void mac_cleanup(struct mac_context *ctx)
+{ DUMMY; }
+
+#endif
+
+/**
+ * mac_fill - compute and fill MAC
+ * @id: MAC algorithm ID
+ * @key: secret key
+ * @keylen: key length
+ * @data: message data
+ * @datalen: message length
+ * @mac: place to fill MAC
+ *
+ * Compute MAC for specified key @key and message @data using algorithm @id and
+ * copy it to buffer @mac. mac_fill() is a shortcut function doing all usual
+ * steps for transmitted messages.
+ */
+void
+mac_fill(uint id, const byte *key, uint keylen, const byte *data, uint datalen, byte *mac)
+{
+ struct mac_context ctx;
+
+ mac_init(&ctx, id, key, keylen);
+ mac_update(&ctx, data, datalen);
+ memcpy(mac, mac_final(&ctx), mac_get_length(&ctx));
+ mac_cleanup(&ctx);
+}
+
+/**
+ * mac_verify - compute and verify MAC
+ * @id: MAC algorithm ID
+ * @key: secret key
+ * @keylen: key length
+ * @data: message data
+ * @datalen: message length
+ * @mac: received MAC
+ *
+ * Compute MAC for specified key @key and message @data using algorithm @id and
+ * compare it with received @mac, return whether they are the same. mac_verify()
+ * is a shortcut function doing all usual steps for received messages.
+ */
+int
+mac_verify(uint id, const byte *key, uint keylen, const byte *data, uint datalen, const byte *mac)
+{
+ struct mac_context ctx;
+
+ mac_init(&ctx, id, key, keylen);
+ mac_update(&ctx, data, datalen);
+ int res = !memcmp(mac, mac_final(&ctx), mac_get_length(&ctx));
+ mac_cleanup(&ctx);
+
+ return res;
+}
diff --git a/lib/mac.h b/lib/mac.h
new file mode 100644
index 00000000..b6f3af52
--- /dev/null
+++ b/lib/mac.h
@@ -0,0 +1,121 @@
+/*
+ * BIRD Library -- Message Authentication Codes
+ *
+ * (c) 2016 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2016 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_MAC_H_
+#define _BIRD_MAC_H_
+
+#include "nest/bird.h"
+#include "lib/sha512.h"
+
+
+#define ALG_UNDEFINED 0
+#define ALG_MD5 0x01
+#define ALG_SHA1 0x02
+#define ALG_SHA224 0x03
+#define ALG_SHA256 0x04
+#define ALG_SHA384 0x05
+#define ALG_SHA512 0x06
+#define ALG_HMAC 0x10
+#define ALG_HMAC_MD5 0x11
+#define ALG_HMAC_SHA1 0x12
+#define ALG_HMAC_SHA224 0x13
+#define ALG_HMAC_SHA256 0x14
+#define ALG_HMAC_SHA384 0x15
+#define ALG_HMAC_SHA512 0x16
+#define ALG_MAX 0x17
+
+/* These are maximums for HASH/MAC lengths and required context space */
+#define MAX_HASH_SIZE SHA512_SIZE
+#define HASH_STORAGE sizeof(struct sha512_context)
+#define MAC_STORAGE sizeof(struct hmac_context)
+
+/* This value is used by several IETF protocols for padding */
+#define HMAC_MAGIC htonl(0x878FE1F3)
+
+/* Generic context used by hash functions */
+struct hash_context
+{
+ u8 data[HASH_STORAGE];
+ u64 align[0];
+};
+
+/* Context for embedded hash (not-really-MAC hash) */
+struct nrmh_context {
+ const struct mac_desc *type;
+ struct hash_context ictx;
+};
+
+/* Context for hash based HMAC */
+struct hmac_context {
+ const struct mac_desc *type;
+ struct hash_context ictx;
+ struct hash_context octx;
+};
+
+/* Generic context used by MAC functions */
+struct mac_context
+{
+ const struct mac_desc *type;
+ u8 data[MAC_STORAGE - sizeof(void *)];
+ u64 align[0];
+};
+
+/* Union to satisfy C aliasing rules */
+union mac_context_union {
+ struct mac_context mac;
+ struct nrmh_context nrmh;
+ struct hmac_context hmac;
+};
+
+
+struct mac_desc {
+ const char *name; /* Name of MAC algorithm */
+ uint mac_length; /* Length of authentication code */
+ uint ctx_length; /* Length of algorithm context */
+ void (*init)(struct mac_context *ctx, const byte *key, uint keylen);
+ void (*update)(struct mac_context *ctx, const byte *data, uint datalen);
+ byte *(*final)(struct mac_context *ctx);
+
+ uint hash_size; /* Hash length, for hash-based MACs */
+ uint block_size; /* Hash block size, for hash-based MACs */
+ void (*hash_init)(struct hash_context *ctx);
+ void (*hash_update)(struct hash_context *ctx, const byte *data, uint datalen);
+ byte *(*hash_final)(struct hash_context *ctx);
+};
+
+extern const struct mac_desc mac_table[ALG_MAX];
+
+static inline const char *mac_type_name(uint id)
+{ return mac_table[id].name; }
+
+static inline uint mac_type_length(uint id)
+{ return mac_table[id].mac_length; }
+
+static inline const char *mac_get_name(struct mac_context *ctx)
+{ return ctx->type->name; }
+
+static inline uint mac_get_length(struct mac_context *ctx)
+{ return ctx->type->mac_length; }
+
+void mac_init(struct mac_context *ctx, uint id, const byte *key, uint keylen);
+
+static inline void mac_update(struct mac_context *ctx, const byte *data, uint datalen)
+{ ctx->type->update(ctx, data, datalen); }
+
+static inline byte *mac_final(struct mac_context *ctx)
+{ return ctx->type->final(ctx); }
+
+static inline void mac_cleanup(struct mac_context *ctx)
+{ memset(ctx, 0, ctx->type->ctx_length); }
+
+void mac_fill(uint id, const byte *key, uint keylen, const byte *data, uint datalen, byte *mac);
+int mac_verify(uint id, const byte *key, uint keylen, const byte *data, uint datalen, const byte *mac);
+
+
+#endif /* _BIRD_MAC_H_ */
diff --git a/lib/mac_test.c b/lib/mac_test.c
new file mode 100644
index 00000000..806fe3e4
--- /dev/null
+++ b/lib/mac_test.c
@@ -0,0 +1,1159 @@
+/*
+ * BIRD Library -- SHA and HMAC-SHA functions tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "test/bt-utils.h"
+
+#include "lib/mac.h"
+
+
+#define define_test_hash_fn(name,id) \
+static int \
+test_##name(void *out_, const void *in_, const void *expected_out_) \
+{ \
+ char *out = out_; \
+ const char *in = in_; \
+ const char *expected_out = expected_out_; \
+ \
+ struct mac_context ctx; \
+ mac_init(&ctx, id, NULL, 0); \
+ mac_update(&ctx, in, strlen(in)); \
+ byte *out_bin = mac_final(&ctx); \
+ \
+ uint len = mac_type_length(id); \
+ bt_bytes_to_hex(out, out_bin, len); \
+ \
+ return strncmp(out, expected_out, 2*len+1) == 0; \
+}
+
+define_test_hash_fn(md5, ALG_MD5)
+define_test_hash_fn(sha1, ALG_SHA1)
+define_test_hash_fn(sha224, ALG_SHA224)
+define_test_hash_fn(sha256, ALG_SHA256)
+define_test_hash_fn(sha384, ALG_SHA384)
+define_test_hash_fn(sha512, ALG_SHA512)
+
+
+static int
+t_md5(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "d41d8cd98f00b204e9800998ecf8427e",
+ },
+ {
+ .in = "a",
+ .out = "0cc175b9c0f1b6a831c399e269772661",
+ },
+ {
+ .in = "abc",
+ .out = "900150983cd24fb0d6963f7d28e17f72",
+ },
+ {
+ .in = "message digest",
+ .out = "f96b697d7cb7938d525a2f31aaf161d0",
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = "c3fcd3d76192e4007dfb496cca67e13b",
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = "d174ab98d277d9f5a5611c2c9f419d9f",
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = "57edf4a22be3c955ac49da2e2107b67a",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_md5, bt_fmt_str, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx functions
+ */
+
+
+static int
+t_sha1(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ },
+ {
+ .in = "a",
+ .out = "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
+ },
+ {
+ .in = "abc",
+ .out = "a9993e364706816aba3e25717850c26c9cd0d89d",
+ },
+ {
+ .in = "message digest",
+ .out = "c12252ceda8be8994d5fa0290a47231c1d16aae3",
+ },
+ {
+ .in = "abcdefghijklmnopqrstuvwxyz",
+ .out = "32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
+ },
+ {
+ .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ .out = "761c457bf73b14d27e9e9265c46f4b4dda11f940",
+ },
+ {
+ .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ .out = "50abf5706a150990a08b2c5ea40fa0e585554732",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "6a64fcc1fb970f7339ce886601775d2efea5cd4b",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha1, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha224(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
+ },
+ {
+ .in = "a",
+ .out = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5",
+ },
+ {
+ .in = "abc",
+ .out = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "cca7dd1a332a17775d8b0429bdb45055c2d4368ebaab0c7cf385586e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha224, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha256(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ },
+ {
+ .in = "a",
+ .out = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
+ },
+ {
+ .in = "abc",
+ .out = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "bf18b43b61652b5d73f41ebf3d72e5e43aebf5076f497dde31ea3de9de4998ef",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha256, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha384(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+ },
+ {
+ .in = "a",
+ .out = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
+ },
+ {
+ .in = "abc",
+ .out = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "6452928a62ca915a60f2d16ea22cc832d8ecb35443d78a3ff6986e7def9174a1dc16ce2ff65d3ed1666db98357f3c05e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha384, bt_fmt_str, bt_fmt_str);
+}
+
+static int
+t_sha512(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = "",
+ .out = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+ },
+ {
+ .in = "a",
+ .out = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+ },
+ {
+ .in = "abc",
+ .out = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+ },
+ {
+ .in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ .out = "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445",
+ },
+ {
+ .in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ .out = "415509a1c345371acb3e27a88b3835e3b6dfebcbbab5134850596f4db64d7bb22ac42c3cd179446a80c92b8be955460eb536eac01389a7e1fdf09d1dca83922f",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha512, bt_fmt_str, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx HMAC functions
+ */
+
+#define HMAC_BUFFER_SIZE 160
+struct hmac_data_in {
+ byte key[HMAC_BUFFER_SIZE];
+ uint key_len;
+ byte data[HMAC_BUFFER_SIZE];
+ uint data_len;
+};
+
+static void
+hmac_in_fmt(char *buf, size_t size, const void *data_)
+{
+ uint i;
+ const struct hmac_data_in *data = data_;
+
+ snprintf(buf, size, "data: '");
+ for (i = 0; i < data->data_len; i++)
+ snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(data->data[i]) ? "%c" : " 0x%02x", data->data[i]);
+
+ snprintf(buf+strlen(buf), size-strlen(buf), "', key: '");
+ for (i = 0; i < data->key_len; i++)
+ snprintf(buf+strlen(buf), size-strlen(buf), bt_is_char(data->key[i]) ? "%c" : " 0x%02x", data->key[i]);
+ snprintf(buf+strlen(buf), size-strlen(buf), "'");
+}
+
+#define define_test_hmac_fn(name,id) \
+static int \
+test_##name##_hmac(void *out_, const void *in_, const void *expected_out_) \
+{ \
+ char *out = out_; \
+ const struct hmac_data_in *in = in_; \
+ const char *expected_out = expected_out_; \
+ \
+ struct mac_context ctx; \
+ mac_init(&ctx, id, in->key, in->key_len); \
+ mac_update(&ctx, in->data, in->data_len); \
+ byte *out_bin = mac_final(&ctx); \
+ \
+ uint len = mac_type_length(id); \
+ bt_bytes_to_hex(out, out_bin, len); \
+ \
+ return strncmp(out, expected_out, 2*len+1) == 0; \
+}
+
+define_test_hmac_fn(md5, ALG_HMAC_MD5)
+define_test_hmac_fn(sha1, ALG_HMAC_SHA1)
+define_test_hmac_fn(sha224, ALG_HMAC_SHA224)
+define_test_hmac_fn(sha256, ALG_HMAC_SHA256)
+define_test_hmac_fn(sha384, ALG_HMAC_SHA384)
+define_test_hmac_fn(sha512, ALG_HMAC_SHA512)
+
+
+static int
+t_md5_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 16,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "9294727a3638bb1c13f48ef8158bfc9d",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "750c783e6ab0b503eaa86e310a5db738",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 16,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "56be34521d144c88dbb8c733f0e8b3f6",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "697eaf0aca3a3aea3a75164746ffaa79",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 16,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "56461ef2342edc00f9bab995690efd4c",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ .data_len = 73,
+ },
+ .out = "6f630fad67cda0ee1fb1f562db3aa53e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_md5_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha1_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "b617318655057264e28bc0b6fb378c8ef146be00",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "125d7342b9ac11cd91a39af48aa17b4f63f175d3",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "4c9007f4026250c6bc8414f9bf50c86c2d7235da",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "aa4ae5e15272d00e95705637ce8a3b55ed402112",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 80,
+ .data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ .data_len = 73,
+ },
+ .out = "e8e99d0f45237d786d6bbaa7965c7808bbff1a91",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61,
+ },
+ .key_len = 64,
+ .data = "Test Using key 64 bytes sized",
+ .data_len = 29,
+ },
+ .out = "a55d4fb80962a6b3d2e720705314bee417d68cf6",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha1_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha224_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha224_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha256_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha256_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha384_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha384_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+static int
+t_sha512_hmac(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ .key_len = 20,
+ .data = "Hi There",
+ .data_len = 8,
+ },
+ .out = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = "Jefe",
+ .key_len = 4,
+ .data = "what do ya want for nothing?",
+ .data_len = 28,
+ },
+ .out = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ .key_len = 20,
+ .data = {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ },
+ .data_len = 50,
+ },
+ .out = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19,
+ },
+ .key_len = 25,
+ .data = {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ },
+ .data_len = 50,
+ },
+ .out = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ .key_len = 20,
+ .data = "Test With Truncation",
+ .data_len = 20,
+ },
+ .out = "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "Test Using Larger Than Block-Size Key - Hash Key First",
+ .data_len = 54,
+ },
+ .out = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598",
+ },
+ {
+ .in = & (struct hmac_data_in) {
+ .key = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa,
+ },
+ .key_len = 131,
+ .data = "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ .data_len = 152,
+ },
+ .out = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58",
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_sha512_hmac, hmac_in_fmt, bt_fmt_str);
+}
+
+
+/*
+ * Testing SHAxxx concating independence
+ */
+
+#include "lib/sha256.h"
+#include "lib/sha512.h"
+
+static int
+t_sha256_concating(void)
+{
+ char hash_a[SHA256_HEX_SIZE];
+ char hash_b[SHA256_HEX_SIZE];
+
+ char *str_a = "a" "bb" "ccc" "dddd" "eeeee" "ffffff";
+ char *str_b1 = "a" ;
+ char *str_b2 = "bb" ;
+ char *str_b3 = "ccc" ;
+ char *str_b4 = "dddd" ;
+ char *str_b5 = "eeeee" ;
+ char *str_b6 = "ffffff";
+
+ struct hash_context ctx_a;
+ sha256_init(&ctx_a);
+ sha256_update(&ctx_a, str_a, strlen(str_a));
+ byte *hash_a_ = sha256_final(&ctx_a);
+ bt_bytes_to_hex(hash_a, hash_a_, SHA256_SIZE);
+
+ struct hash_context ctx_b;
+ sha256_init(&ctx_b);
+ sha256_update(&ctx_b, str_b1, strlen(str_b1));
+ sha256_update(&ctx_b, str_b2, strlen(str_b2));
+ sha256_update(&ctx_b, str_b3, strlen(str_b3));
+ sha256_update(&ctx_b, str_b4, strlen(str_b4));
+ sha256_update(&ctx_b, str_b5, strlen(str_b5));
+ sha256_update(&ctx_b, str_b6, strlen(str_b6));
+ byte *hash_b_ = sha256_final(&ctx_b);
+ bt_bytes_to_hex(hash_b, hash_b_, SHA256_SIZE);
+
+ int are_hash_a_b_equal = (strncmp(hash_a, hash_b, sizeof(hash_a)) == 0);
+ bt_assert_msg(are_hash_a_b_equal, "Hashes A: %s, B: %s should be same", hash_a, hash_b);
+
+ return 1;
+}
+
+
+static int
+t_sha512_concating(void)
+{
+ char hash_a[SHA512_HEX_SIZE];
+ char hash_b[SHA512_HEX_SIZE];
+
+ char *str_a = "a" "bb" "ccc" "dddd" "eeeee" "ffffff";
+ char *str_b1 = "a" ;
+ char *str_b2 = "bb" ;
+ char *str_b3 = "ccc" ;
+ char *str_b4 = "dddd" ;
+ char *str_b5 = "eeeee" ;
+ char *str_b6 = "ffffff";
+
+ struct hash_context ctx_a;
+ sha512_init(&ctx_a);
+ sha512_update(&ctx_a, str_a, strlen(str_a));
+ byte *hash_a_ = sha512_final(&ctx_a);
+ bt_bytes_to_hex(hash_a, hash_a_, SHA512_SIZE);
+
+ struct hash_context ctx_b;
+ sha512_init(&ctx_b);
+ sha512_update(&ctx_b, str_b1, strlen(str_b1));
+ sha512_update(&ctx_b, str_b2, strlen(str_b2));
+ sha512_update(&ctx_b, str_b3, strlen(str_b3));
+ sha512_update(&ctx_b, str_b4, strlen(str_b4));
+ sha512_update(&ctx_b, str_b5, strlen(str_b5));
+ sha512_update(&ctx_b, str_b6, strlen(str_b6));
+ byte *hash_b_ = sha512_final(&ctx_b);
+ bt_bytes_to_hex(hash_b, hash_b_, SHA512_SIZE);
+
+ int are_hash_a_b_equal = (strncmp(hash_a, hash_b, sizeof(hash_a)) == 0);
+ bt_assert_msg(are_hash_a_b_equal, "Hashes A: %s, B: %s should be same", hash_a, hash_b);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_md5, "Testing MD5 by RFC 1321");
+ bt_test_suite(t_sha1, "Testing SHA-1");
+ bt_test_suite(t_sha224, "Testing SHA-224");
+ bt_test_suite(t_sha256, "Testing SHA-256");
+ bt_test_suite(t_sha384, "Testing SHA-384");
+ bt_test_suite(t_sha512, "Testing SHA-512");
+
+ bt_test_suite(t_md5_hmac, "Testing HMAC-MD5 by RFC 2202");
+ bt_test_suite(t_sha1_hmac, "Testing HMAC-SHA-1 by RFC 2202");
+ bt_test_suite(t_sha224_hmac, "Testing HMAC-SHA-224 by RFC 4231");
+ bt_test_suite(t_sha256_hmac, "Testing HMAC-SHA-256 by RFC 4231");
+ bt_test_suite(t_sha384_hmac, "Testing HMAC-SHA-384 by RFC 4231");
+ bt_test_suite(t_sha512_hmac, "Testing HMAC-SHA-512 by RFC 4231");
+
+ bt_test_suite(t_sha256_concating, "Testing concatenation input string to hash using sha256_update");
+ bt_test_suite(t_sha512_concating, "Testing concatenation input string to hash using sha512_update");
+
+ return bt_exit_value();
+}
diff --git a/lib/md5.c b/lib/md5.c
index 8efa62d6..df49de5d 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -39,8 +39,10 @@ static void md5_transform(u32 buf[4], u32 const in[16]);
* initialization constants.
*/
void
-md5_init(struct md5_context *ctx)
+md5_init(struct hash_context *CTX)
{
+ struct md5_context *ctx = (void *) CTX;
+
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
@@ -55,8 +57,9 @@ md5_init(struct md5_context *ctx)
* of bytes.
*/
void
-md5_update(struct md5_context *ctx, const byte *buf, uint len)
+md5_update(struct hash_context *CTX, const byte *buf, uint len)
{
+ struct md5_context *ctx = (void *) CTX;
u32 t;
/* Update bitcount */
@@ -105,8 +108,9 @@ md5_update(struct md5_context *ctx, const byte *buf, uint len)
* 1 0* (64-bit count of bits processed, MSB-first)
*/
byte *
-md5_final(struct md5_context *ctx)
+md5_final(struct hash_context *CTX)
{
+ struct md5_context *ctx = (void *) CTX;
uint count;
byte *p;
@@ -149,13 +153,6 @@ md5_final(struct md5_context *ctx)
return (byte*) ctx->buf;
}
-/* I am a hard paranoid */
-void
-md5_erase_ctx(struct md5_context *ctx)
-{
- memset((char *) ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
-}
-
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
@@ -256,67 +253,3 @@ md5_transform(u32 buf[4], u32 const in[16])
buf[2] += c;
buf[3] += d;
}
-
-
-/*
- * MD5-HMAC
- */
-
-static void
-md5_hash_buffer(byte *outbuf, const byte *buffer, size_t length)
-{
- struct md5_context hd_tmp;
-
- md5_init(&hd_tmp);
- md5_update(&hd_tmp, buffer, length);
- memcpy(outbuf, md5_final(&hd_tmp), MD5_SIZE);
-}
-
-void
-md5_hmac_init(struct md5_hmac_context *ctx, const byte *key, size_t keylen)
-{
- byte keybuf[MD5_BLOCK_SIZE], buf[MD5_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= MD5_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- bzero(keybuf + keylen, MD5_BLOCK_SIZE - keylen);
- }
- else
- {
- md5_hash_buffer(keybuf, key, keylen);
- bzero(keybuf + MD5_SIZE, MD5_BLOCK_SIZE - MD5_SIZE);
- }
-
- /* Initialize the inner digest */
- md5_init(&ctx->ictx);
- int i;
- for (i = 0; i < MD5_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- md5_update(&ctx->ictx, buf, MD5_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- md5_init(&ctx->octx);
- for (i = 0; i < MD5_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- md5_update(&ctx->octx, buf, MD5_BLOCK_SIZE);
-}
-
-void
-md5_hmac_update(struct md5_hmac_context *ctx, const byte *buf, size_t buflen)
-{
- /* Just update the inner digest */
- md5_update(&ctx->ictx, buf, buflen);
-}
-
-byte *
-md5_hmac_final(struct md5_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = md5_final(&ctx->ictx);
-
- /* Finish the outer digest */
- md5_update(&ctx->octx, isha, MD5_SIZE);
- return md5_final(&ctx->octx);
-}
diff --git a/lib/md5.h b/lib/md5.h
index 034d764c..4e001851 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -19,29 +19,18 @@
#define MD5_BLOCK_SIZE 64
+struct hash_context;
+
struct md5_context {
u32 buf[4];
u32 bits[2];
byte in[64];
};
-void md5_init(struct md5_context *ctx);
-void md5_update(struct md5_context *ctx, const byte *buf, uint len);
-byte *md5_final(struct md5_context *ctx);
-
-
-/*
- * HMAC-MD5
- */
-
-struct md5_hmac_context {
- struct md5_context ictx;
- struct md5_context octx;
-};
-void md5_hmac_init(struct md5_hmac_context *ctx, const byte *key, size_t keylen);
-void md5_hmac_update(struct md5_hmac_context *ctx, const byte *buf, size_t buflen);
-byte *md5_hmac_final(struct md5_hmac_context *ctx);
+void md5_init(struct hash_context *ctx);
+void md5_update(struct hash_context *ctx, const byte *buf, uint len);
+byte *md5_final(struct hash_context *ctx);
#endif /* _BIRD_MD5_H_ */
diff --git a/lib/net.c b/lib/net.c
index 55eec4b5..53991b4c 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -109,6 +109,24 @@ net_compare(const net_addr *a, const net_addr *b)
return 0;
}
+#define NET_HASH(a,t) net_hash_##t((const net_addr_##t *) a)
+
+u32
+net_hash(const net_addr *n)
+{
+ switch (n->type)
+ {
+ case NET_IP4: return NET_HASH(n, ip4);
+ case NET_IP6: return NET_HASH(n, ip6);
+ case NET_VPN4: return NET_HASH(n, vpn4);
+ case NET_VPN6: return NET_HASH(n, vpn6);
+ case NET_ROA4: return NET_HASH(n, roa4);
+ case NET_ROA6: return NET_HASH(n, roa6);
+ default: bug("invalid type");
+ }
+}
+
+
int
net_validate(const net_addr *N)
{
diff --git a/lib/net.h b/lib/net.h
index 3deedb1f..e8310894 100644
--- a/lib/net.h
+++ b/lib/net.h
@@ -324,6 +324,8 @@ static inline u32 net_hash_roa4(const net_addr_roa4 *n)
static inline u32 net_hash_roa6(const net_addr_roa6 *n)
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+u32 net_hash(const net_addr *a);
+
static inline int net_validate_ip4(const net_addr_ip4 *n)
{
diff --git a/lib/patmatch_test.c b/lib/patmatch_test.c
new file mode 100644
index 00000000..d65f316f
--- /dev/null
+++ b/lib/patmatch_test.c
@@ -0,0 +1,149 @@
+/*
+ * BIRD Library -- Pattern Matching Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "nest/bird.h"
+#include "lib/string.h"
+
+#define MATCH (int) { 1 }
+#define NOMATCH (int) { 0 }
+
+struct match_pair {
+ byte *pattern;
+ byte *data;
+};
+
+static int
+test_matching(void *out_, const void *in_, const void *expected_out_)
+{
+ int *out = out_;
+ const struct match_pair *in = in_;
+ const int *expected_out = expected_out_;
+
+ *out = patmatch(in->pattern, in->data);
+
+ return *out == *expected_out;
+}
+
+static void
+fmt_match_pair(char *buf, size_t size, const void *data)
+{
+ const struct match_pair *mp = data;
+ snprintf(buf, size, "pattern: '%s', subject: '%s'", mp->pattern, mp->data);
+}
+
+static void
+fmt_match_result(char *buf, size_t size, const void *data)
+{
+ const int *result = data;
+ snprintf(buf, size, *result ? "match" : "no-match");
+}
+
+static int
+t_matching(void)
+{
+ struct bt_pair test_vectors[] = {
+ {
+ .in = & (struct match_pair) {
+ .pattern = "",
+ .data = "",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "*",
+ .data = "",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "\\*",
+ .data = "*",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "\\*",
+ .data = "a",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "?",
+ .data = "",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqrstuvwxyz",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "??????????????????????????",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "*abcdefghijklmnopqrstuvwxyz*",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "ab?defg*jklmnop*stu*wxy*z",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & MATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqrstuvwxyz",
+ .data = "abcdefghijklmnopqrtuvwxyz",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "abcdefghijklmnopqr?uvwxyz",
+ .data = "abcdefghijklmnopqrstuvwxyz",
+ },
+ .out = & NOMATCH,
+ },
+ {
+ .in = & (struct match_pair) {
+ .pattern = "aa*aaaaa?aaaaaaaaaaaaaaaaaaa",
+ .data = "aaaaaaaaaaaaaaaaaaaaaaaaaa",
+ },
+ .out = & NOMATCH,
+ },
+ };
+
+ return bt_assert_batch(test_vectors, test_matching, fmt_match_pair, fmt_match_result);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_matching, "Pattern matching");
+
+ return bt_exit_value();
+}
diff --git a/lib/printf.c b/lib/printf.c
index 844f5969..1632b5f3 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -169,7 +169,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
- }
+ }
/* get field width */
field_width = -1;
diff --git a/lib/printf_test.c b/lib/printf_test.c
new file mode 100644
index 00000000..3981d3da
--- /dev/null
+++ b/lib/printf_test.c
@@ -0,0 +1,70 @@
+/*
+ * BIRD Library -- String Functions Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/string.h"
+
+#define BSPRINTF(nw, res, buf, fmt, ...) \
+ do { \
+ int n = bsprintf(buf, fmt, ##__VA_ARGS__); \
+ bt_assert_msg(n == nw, "fmt=\"%s\" returns n=%d, want %d", fmt, n, nw); \
+ bt_assert_msg(buf[n] == 0, "fmt=\"%s\" buf[%d] should be \'\\0\', found 0x%02x", fmt, n, buf[n]); \
+ bt_assert_msg(memcmp(buf, res, nw) == 0, "fmt=\"%s\" writes \"%*s\", want \"%*s\"", fmt, (n < nw ? n : nw), buf, nw, res); \
+ } while (0)
+
+static int
+t_simple(void)
+{
+ char buf[256];
+ memset(buf, 0xa5, 256);
+
+ BSPRINTF(0, "", buf, "", NULL);
+ BSPRINTF(1, "%", buf, "%%", NULL);
+ BSPRINTF(2, "%%", buf, "%%%%", NULL);
+
+ BSPRINTF(1, "\x00", buf, "%c", 0);
+ BSPRINTF(1, "@", buf, "@", 64);
+ BSPRINTF(1, "\xff", buf, "%c", 0xff);
+
+ errno = 5;
+ BSPRINTF(18, "Input/output error", buf, "%m");
+ errno = 0;
+
+ BSPRINTF(18, "Input/output error", buf, "%M", 5);
+
+ BSPRINTF(11, "TeSt%StRiNg", buf, "%s", "TeSt%StRiNg");
+
+ if (sizeof(void *) == 4)
+ BSPRINTF(8, "1a15600d", buf, "%p", (void *) 0x1a15600d);
+ else
+ BSPRINTF(16, "00000fee1a15600d", buf, "%p", (void *) 0xfee1a15600d);
+
+ long ln = 0;
+ BSPRINTF(10, "TeStStRiNg", buf, "TeStS%lntRiNg", &ln);
+ bt_assert_msg(ln == 5, "fmt=\"TeStS%%lntRiNg\", &ln makes ln=%ld, want 5", ln);
+
+ BSPRINTF(2, "%d", buf, "%%d", 1);
+ BSPRINTF(1, "1", buf, "%d", 1);
+ BSPRINTF(2, "+1", buf, "%+d", 1);
+ BSPRINTF(2, " 1", buf, "% d", 1);
+ BSPRINTF(2, "-1", buf, "%d", -1);
+ BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_simple, "printf without varargs");
+
+ return bt_exit_value();
+}
diff --git a/lib/sha1.c b/lib/sha1.c
index 73b4b280..d6298b89 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -1,5 +1,5 @@
/*
- * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174) and HMAC-SHA-1
+ * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174)
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -17,8 +17,10 @@
void
-sha1_init(struct sha1_context *ctx)
+sha1_init(struct hash_context *CTX)
{
+ struct sha1_context *ctx = (void *) CTX;
+
ctx->h0 = 0x67452301;
ctx->h1 = 0xefcdab89;
ctx->h2 = 0x98badcfe;
@@ -167,8 +169,10 @@ sha1_transform(struct sha1_context *ctx, const byte *data)
* Update the message digest with the contents of BUF with length LEN.
*/
void
-sha1_update(struct sha1_context *ctx, const byte *buf, uint len)
+sha1_update(struct hash_context *CTX, const byte *buf, uint len)
{
+ struct sha1_context *ctx = (void *) CTX;
+
if (ctx->count)
{
/* Fill rest of internal buffer */
@@ -209,11 +213,12 @@ sha1_update(struct sha1_context *ctx, const byte *buf, uint len)
* Returns: 20 bytes representing the digest.
*/
byte *
-sha1_final(struct sha1_context *ctx)
+sha1_final(struct hash_context *CTX)
{
+ struct sha1_context *ctx = (void *) CTX;
u32 t, msb, lsb;
- sha1_update(ctx, NULL, 0); /* flush */
+ sha1_update(CTX, NULL, 0); /* flush */
t = ctx->nblocks;
/* multiply by 64 to make a byte count */
@@ -242,7 +247,7 @@ sha1_final(struct sha1_context *ctx)
ctx->buf[ctx->count++] = 0x80; /* pad character */
while (ctx->count < 64)
ctx->buf[ctx->count++] = 0;
- sha1_update(ctx, NULL, 0); /* flush */
+ sha1_update(CTX, NULL, 0); /* flush */
memset(ctx->buf, 0, 56); /* fill next block with zeroes */
}
@@ -268,81 +273,3 @@ sha1_final(struct sha1_context *ctx)
return ctx->buf;
}
-
-
-/*
- * SHA1-HMAC
- */
-
-/*
- * Shortcut function which puts the hash value of the supplied buffer
- * into outbuf which must have a size of 20 bytes.
- */
-void
-sha1_hash_buffer(byte *outbuf, const byte *buffer, uint length)
-{
- struct sha1_context ctx;
-
- sha1_init(&ctx);
- sha1_update(&ctx, buffer, length);
- memcpy(outbuf, sha1_final(&ctx), SHA1_SIZE);
-}
-
-void
-sha1_hmac_init(struct sha1_hmac_context *ctx, const byte *key, uint keylen)
-{
- byte keybuf[SHA1_BLOCK_SIZE], buf[SHA1_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= SHA1_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- memset(keybuf + keylen, 0, SHA1_BLOCK_SIZE - keylen);
- }
- else
- {
- sha1_hash_buffer(keybuf, key, keylen);
- memset(keybuf + SHA1_SIZE, 0, SHA1_BLOCK_SIZE - SHA1_SIZE);
- }
-
- /* Initialize the inner digest */
- sha1_init(&ctx->ictx);
- int i;
- for (i = 0; i < SHA1_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- sha1_update(&ctx->ictx, buf, SHA1_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- sha1_init(&ctx->octx);
- for (i = 0; i < SHA1_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- sha1_update(&ctx->octx, buf, SHA1_BLOCK_SIZE);
-}
-
-void
-sha1_hmac_update(struct sha1_hmac_context *ctx, const byte *data, uint datalen)
-{
- /* Just update the inner digest */
- sha1_update(&ctx->ictx, data, datalen);
-}
-
-byte *
-sha1_hmac_final(struct sha1_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = sha1_final(&ctx->ictx);
-
- /* Finish the outer digest */
- sha1_update(&ctx->octx, isha, SHA1_SIZE);
- return sha1_final(&ctx->octx);
-}
-
-void
-sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen)
-{
- struct sha1_hmac_context ctx;
-
- sha1_hmac_init(&ctx, key, keylen);
- sha1_hmac_update(&ctx, data, datalen);
- memcpy(outbuf, sha1_hmac_final(&ctx), SHA1_SIZE);
-}
diff --git a/lib/sha1.h b/lib/sha1.h
index c019bb49..8666a651 100644
--- a/lib/sha1.h
+++ b/lib/sha1.h
@@ -1,5 +1,5 @@
/*
- * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174) and HMAC-SHA-1
+ * BIRD Library -- SHA-1 Hash Function (FIPS 180-1, RFC 3174)
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -27,6 +27,8 @@
* Internal SHA1 state.
* You should use it just as an opaque handle only.
*/
+struct hash_context;
+
struct sha1_context {
u32 h0, h1, h2, h3, h4;
byte buf[SHA1_BLOCK_SIZE];
@@ -34,15 +36,14 @@ struct sha1_context {
uint count;
};
-
-void sha1_init(struct sha1_context *ctx); /* Initialize new algorithm run in the @ctx context. **/
+void sha1_init(struct hash_context *ctx); /* Initialize new algorithm run in the @ctx context. **/
/*
* Push another @len bytes of data pointed to by @buf onto the SHA1 hash
* currently in @ctx. You can call this any times you want on the same hash (and
* you do not need to reinitialize it by @sha1_init()). It has the same effect
* as concatenating all the data together and passing them at once.
*/
-void sha1_update(struct sha1_context *ctx, const byte *buf, uint len);
+void sha1_update(struct hash_context *ctx, const byte *buf, uint len);
/*
* No more @sha1_update() calls will be done. This terminates the hash and
* returns a pointer to it.
@@ -50,7 +51,7 @@ void sha1_update(struct sha1_context *ctx, const byte *buf, uint len);
* Note that the pointer points into data in the @ctx context. If it ceases to
* exist, the pointer becomes invalid.
*/
-byte *sha1_final(struct sha1_context *ctx);
+byte *sha1_final(struct hash_context *ctx);
/*
* A convenience one-shot function for SHA1 hash. It is equivalent to this
@@ -63,24 +64,5 @@ byte *sha1_final(struct sha1_context *ctx);
*/
void sha1_hash_buffer(byte *outbuf, const byte *buffer, uint length);
-/*
- * SHA1 HMAC message authentication. If you provide @key and @data, the result
- * will be stored in @outbuf.
- */
-void sha1_hmac(byte *outbuf, const byte *key, uint keylen, const byte *data, uint datalen);
-
-/*
- * The HMAC also exists in a stream version in a way analogous to the plain
- * SHA1. Pass this as a context.
- */
-struct sha1_hmac_context {
- struct sha1_context ictx;
- struct sha1_context octx;
-};
-
-void sha1_hmac_init(struct sha1_hmac_context *ctx, const byte *key, uint keylen); /* Initialize HMAC with context @ctx and the given key. See sha1_init(). */
-void sha1_hmac_update(struct sha1_hmac_context *ctx, const byte *data, uint datalen); /* Hash another @datalen bytes of data. See sha1_update(). */
-byte *sha1_hmac_final(struct sha1_hmac_context *ctx); /* Terminate the HMAC and return a pointer to the allocated hash. See sha1_final(). */
-
#endif /* _BIRD_SHA1_H_ */
diff --git a/lib/sha256.c b/lib/sha256.c
index 440245d5..11ff2b05 100644
--- a/lib/sha256.c
+++ b/lib/sha256.c
@@ -1,6 +1,5 @@
/*
- * BIRD Library -- SHA-256 and SHA-224 Hash Functions,
- * HMAC-SHA-256 and HMAC-SHA-224 Functions
+ * BIRD Library -- SHA-256 and SHA-224 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -17,8 +16,10 @@
// #define SHA256_UNROLLED
void
-sha256_init(struct sha256_context *ctx)
+sha256_init(struct hash_context *CTX)
{
+ struct sha256_context *ctx = (void *) CTX;
+
ctx->h0 = 0x6a09e667;
ctx->h1 = 0xbb67ae85;
ctx->h2 = 0x3c6ef372;
@@ -33,8 +34,10 @@ sha256_init(struct sha256_context *ctx)
}
void
-sha224_init(struct sha224_context *ctx)
+sha224_init(struct hash_context *CTX)
{
+ struct sha224_context *ctx = (void *) CTX;
+
ctx->h0 = 0xc1059ed8;
ctx->h1 = 0x367cd507;
ctx->h2 = 0x3070dd17;
@@ -219,8 +222,10 @@ sha256_transform(struct sha256_context *ctx, const byte *data)
not have any meaning but writing after finalize is sometimes
helpful to mitigate timing attacks. */
void
-sha256_update(struct sha256_context *ctx, const byte *buf, size_t len)
+sha256_update(struct hash_context *CTX, const byte *buf, uint len)
{
+ struct sha256_context *ctx = (void *) CTX;
+
if (ctx->count)
{
/* Fill rest of internal buffer */
@@ -261,11 +266,12 @@ sha256_update(struct sha256_context *ctx, const byte *buf, size_t len)
* Returns: 32 bytes with the message the digest. 28 bytes for SHA-224.
*/
byte *
-sha256_final(struct sha256_context *ctx)
+sha256_final(struct hash_context *CTX)
{
+ struct sha256_context *ctx = (void *) CTX;
u32 t, th, msb, lsb;
- sha256_update(ctx, NULL, 0); /* flush */
+ sha256_update(CTX, NULL, 0); /* flush */
t = ctx->nblocks;
th = 0;
@@ -296,7 +302,7 @@ sha256_final(struct sha256_context *ctx)
ctx->buf[ctx->count++] = 0x80; /* pad character */
while (ctx->count < 64)
ctx->buf[ctx->count++] = 0;
- sha256_update(ctx, NULL, 0); /* flush */;
+ sha256_update(CTX, NULL, 0); /* flush */;
memset(ctx->buf, 0, 56 ); /* fill next block with zeroes */
}
@@ -319,131 +325,3 @@ sha256_final(struct sha256_context *ctx)
return ctx->buf;
}
-
-
-/*
- * SHA256-HMAC
- */
-
-static void
-sha256_hash_buffer(byte *outbuf, const byte *buffer, size_t length)
-{
- struct sha256_context ctx;
-
- sha256_init(&ctx);
- sha256_update(&ctx, buffer, length);
- memcpy(outbuf, sha256_final(&ctx), SHA256_SIZE);
-}
-
-void
-sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen)
-{
- byte keybuf[SHA256_BLOCK_SIZE], buf[SHA256_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= SHA256_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- memset(keybuf + keylen, 0, SHA256_BLOCK_SIZE - keylen);
- }
- else
- {
- sha256_hash_buffer(keybuf, key, keylen);
- memset(keybuf + SHA256_SIZE, 0, SHA256_BLOCK_SIZE - SHA256_SIZE);
- }
-
- /* Initialize the inner digest */
- sha256_init(&ctx->ictx);
- int i;
- for (i = 0; i < SHA256_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- sha256_update(&ctx->ictx, buf, SHA256_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- sha256_init(&ctx->octx);
- for (i = 0; i < SHA256_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- sha256_update(&ctx->octx, buf, SHA256_BLOCK_SIZE);
-}
-
-void
-sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen)
-{
- /* Just update the inner digest */
- sha256_update(&ctx->ictx, buf, buflen);
-}
-
-byte *
-sha256_hmac_final(struct sha256_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = sha256_final(&ctx->ictx);
-
- /* Finish the outer digest */
- sha256_update(&ctx->octx, isha, SHA256_SIZE);
- return sha256_final(&ctx->octx);
-}
-
-
-/*
- * SHA224-HMAC
- */
-
-static void
-sha224_hash_buffer(byte *outbuf, const byte *buffer, size_t length)
-{
- struct sha224_context ctx;
-
- sha224_init(&ctx);
- sha224_update(&ctx, buffer, length);
- memcpy(outbuf, sha224_final(&ctx), SHA224_SIZE);
-}
-
-void
-sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen)
-{
- byte keybuf[SHA224_BLOCK_SIZE], buf[SHA224_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= SHA224_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- memset(keybuf + keylen, 0, SHA224_BLOCK_SIZE - keylen);
- }
- else
- {
- sha224_hash_buffer(keybuf, key, keylen);
- memset(keybuf + SHA224_SIZE, 0, SHA224_BLOCK_SIZE - SHA224_SIZE);
- }
-
- /* Initialize the inner digest */
- sha224_init(&ctx->ictx);
- int i;
- for (i = 0; i < SHA224_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- sha224_update(&ctx->ictx, buf, SHA224_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- sha224_init(&ctx->octx);
- for (i = 0; i < SHA224_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- sha224_update(&ctx->octx, buf, SHA224_BLOCK_SIZE);
-}
-
-void
-sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen)
-{
- /* Just update the inner digest */
- sha256_update(&ctx->ictx, buf, buflen);
-}
-
-byte *
-sha224_hmac_final(struct sha224_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = sha224_final(&ctx->ictx);
-
- /* Finish the outer digest */
- sha224_update(&ctx->octx, isha, SHA224_SIZE);
- return sha224_final(&ctx->octx);
-}
diff --git a/lib/sha256.h b/lib/sha256.h
index 381200a9..88a948eb 100644
--- a/lib/sha256.h
+++ b/lib/sha256.h
@@ -1,6 +1,5 @@
/*
- * BIRD Library -- SHA-256 and SHA-224 Hash Functions,
- * HMAC-SHA-256 and HMAC-SHA-224 Functions
+ * BIRD Library -- SHA-256 and SHA-224 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -25,6 +24,8 @@
#define SHA256_BLOCK_SIZE 64
+struct hash_context;
+
struct sha256_context {
u32 h0, h1, h2, h3, h4, h5, h6, h7;
byte buf[SHA256_BLOCK_SIZE];
@@ -35,39 +36,14 @@ struct sha256_context {
#define sha224_context sha256_context
-void sha256_init(struct sha256_context *ctx);
-void sha224_init(struct sha224_context *ctx);
-
-void sha256_update(struct sha256_context *ctx, const byte *buf, size_t len);
-static inline void sha224_update(struct sha224_context *ctx, const byte *buf, size_t len)
-{ sha256_update(ctx, buf, len); }
-
-byte *sha256_final(struct sha256_context *ctx);
-static inline byte *sha224_final(struct sha224_context *ctx)
-{ return sha256_final(ctx); }
-
-
-/*
- * HMAC-SHA256, HMAC-SHA224
- */
-
-struct sha256_hmac_context
-{
- struct sha256_context ictx;
- struct sha256_context octx;
-};
-
-#define sha224_hmac_context sha256_hmac_context
-
-
-void sha256_hmac_init(struct sha256_hmac_context *ctx, const byte *key, size_t keylen);
-void sha224_hmac_init(struct sha224_hmac_context *ctx, const byte *key, size_t keylen);
+void sha256_init(struct hash_context *ctx);
+void sha224_init(struct hash_context *ctx);
-void sha256_hmac_update(struct sha256_hmac_context *ctx, const byte *buf, size_t buflen);
-void sha224_hmac_update(struct sha224_hmac_context *ctx, const byte *buf, size_t buflen);
+void sha256_update(struct hash_context *ctx, const byte *buf, uint len);
+#define sha224_update sha256_update
-byte *sha256_hmac_final(struct sha256_hmac_context *ctx);
-byte *sha224_hmac_final(struct sha224_hmac_context *ctx);
+byte *sha256_final(struct hash_context *ctx);
+#define sha224_final sha256_final
#endif /* _BIRD_SHA256_H_ */
diff --git a/lib/sha512.c b/lib/sha512.c
index 37e660f7..576ae1e8 100644
--- a/lib/sha512.c
+++ b/lib/sha512.c
@@ -1,6 +1,5 @@
/*
- * BIRD Library -- SHA-512 and SHA-384 Hash Functions,
- * HMAC-SHA-512 and HMAC-SHA-384 Functions
+ * BIRD Library -- SHA-512 and SHA-384 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -17,8 +16,10 @@
// #define SHA512_UNROLLED
void
-sha512_init(struct sha512_context *ctx)
+sha512_init(struct hash_context *CTX)
{
+ struct sha512_context *ctx = (void *) CTX;
+
ctx->h0 = U64(0x6a09e667f3bcc908);
ctx->h1 = U64(0xbb67ae8584caa73b);
ctx->h2 = U64(0x3c6ef372fe94f82b);
@@ -33,8 +34,10 @@ sha512_init(struct sha512_context *ctx)
}
void
-sha384_init(struct sha384_context *ctx)
+sha384_init(struct hash_context *CTX)
{
+ struct sha384_context *ctx = (void *) CTX;
+
ctx->h0 = U64(0xcbbb9d5dc1059ed8);
ctx->h1 = U64(0x629a292a367cd507);
ctx->h2 = U64(0x9159015a3070dd17);
@@ -389,8 +392,10 @@ sha512_transform(struct sha512_context *ctx, const byte *data)
}
void
-sha512_update(struct sha512_context *ctx, const byte *buf, size_t len)
+sha512_update(struct hash_context *CTX, const byte *buf, uint len)
{
+ struct sha512_context *ctx = (void *) CTX;
+
if (ctx->count)
{
/* Fill rest of internal buffer */
@@ -432,11 +437,12 @@ sha512_update(struct sha512_context *ctx, const byte *buf, size_t len)
* first 48 of those bytes.
*/
byte *
-sha512_final(struct sha512_context *ctx)
+sha512_final(struct hash_context *CTX)
{
+ struct sha512_context *ctx = (void *) CTX;
u64 t, th, msb, lsb;
- sha512_update(ctx, NULL, 0); /* flush */
+ sha512_update(CTX, NULL, 0); /* flush */
t = ctx->nblocks;
th = 0;
@@ -467,7 +473,7 @@ sha512_final(struct sha512_context *ctx)
ctx->buf[ctx->count++] = 0x80; /* pad character */
while(ctx->count < 128)
ctx->buf[ctx->count++] = 0;
- sha512_update(ctx, NULL, 0); /* flush */
+ sha512_update(CTX, NULL, 0); /* flush */
memset(ctx->buf, 0, 112); /* fill next block with zeroes */
}
@@ -490,131 +496,3 @@ sha512_final(struct sha512_context *ctx)
return ctx->buf;
}
-
-
-/*
- * SHA512-HMAC
- */
-
-static void
-sha512_hash_buffer(byte *outbuf, const byte *buffer, size_t length)
-{
- struct sha512_context ctx;
-
- sha512_init(&ctx);
- sha512_update(&ctx, buffer, length);
- memcpy(outbuf, sha512_final(&ctx), SHA512_SIZE);
-}
-
-void
-sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen)
-{
- byte keybuf[SHA512_BLOCK_SIZE], buf[SHA512_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= SHA512_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- memset(keybuf + keylen, 0, SHA512_BLOCK_SIZE - keylen);
- }
- else
- {
- sha512_hash_buffer(keybuf, key, keylen);
- memset(keybuf + SHA512_SIZE, 0, SHA512_BLOCK_SIZE - SHA512_SIZE);
- }
-
- /* Initialize the inner digest */
- sha512_init(&ctx->ictx);
- int i;
- for (i = 0; i < SHA512_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- sha512_update(&ctx->ictx, buf, SHA512_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- sha512_init(&ctx->octx);
- for (i = 0; i < SHA512_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- sha512_update(&ctx->octx, buf, SHA512_BLOCK_SIZE);
-}
-
-void
-sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen)
-{
- /* Just update the inner digest */
- sha512_update(&ctx->ictx, buf, buflen);
-}
-
-byte *
-sha512_hmac_final(struct sha512_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = sha512_final(&ctx->ictx);
-
- /* Finish the outer digest */
- sha512_update(&ctx->octx, isha, SHA512_SIZE);
- return sha512_final(&ctx->octx);
-}
-
-
-/*
- * SHA384-HMAC
- */
-
-static void
-sha384_hash_buffer(byte *outbuf, const byte *buffer, size_t length)
-{
- struct sha384_context ctx;
-
- sha384_init(&ctx);
- sha384_update(&ctx, buffer, length);
- memcpy(outbuf, sha384_final(&ctx), SHA384_SIZE);
-}
-
-void
-sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen)
-{
- byte keybuf[SHA384_BLOCK_SIZE], buf[SHA384_BLOCK_SIZE];
-
- /* Hash the key if necessary */
- if (keylen <= SHA384_BLOCK_SIZE)
- {
- memcpy(keybuf, key, keylen);
- memset(keybuf + keylen, 0, SHA384_BLOCK_SIZE - keylen);
- }
- else
- {
- sha384_hash_buffer(keybuf, key, keylen);
- memset(keybuf + SHA384_SIZE, 0, SHA384_BLOCK_SIZE - SHA384_SIZE);
- }
-
- /* Initialize the inner digest */
- sha384_init(&ctx->ictx);
- int i;
- for (i = 0; i < SHA384_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x36;
- sha384_update(&ctx->ictx, buf, SHA384_BLOCK_SIZE);
-
- /* Initialize the outer digest */
- sha384_init(&ctx->octx);
- for (i = 0; i < SHA384_BLOCK_SIZE; i++)
- buf[i] = keybuf[i] ^ 0x5c;
- sha384_update(&ctx->octx, buf, SHA384_BLOCK_SIZE);
-}
-
-void
-sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen)
-{
- /* Just update the inner digest */
- sha384_update(&ctx->ictx, buf, buflen);
-}
-
-byte *
-sha384_hmac_final(struct sha384_hmac_context *ctx)
-{
- /* Finish the inner digest */
- byte *isha = sha384_final(&ctx->ictx);
-
- /* Finish the outer digest */
- sha384_update(&ctx->octx, isha, SHA384_SIZE);
- return sha384_final(&ctx->octx);
-}
diff --git a/lib/sha512.h b/lib/sha512.h
index 1614a3ac..02220c93 100644
--- a/lib/sha512.h
+++ b/lib/sha512.h
@@ -1,6 +1,5 @@
/*
- * BIRD Library -- SHA-512 and SHA-384 Hash Functions,
- * HMAC-SHA-512 and HMAC-SHA-384 Functions
+ * BIRD Library -- SHA-512 and SHA-384 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
@@ -25,8 +24,10 @@
#define SHA512_BLOCK_SIZE 128
+struct hash_context;
+
struct sha512_context {
- u64 h0, h1, h2, h3, h4, h5, h6, h7;
+ u64 h0, h1, h2, h3, h4, h5, h6, h7;
byte buf[SHA512_BLOCK_SIZE];
uint nblocks;
uint count;
@@ -35,39 +36,14 @@ struct sha512_context {
#define sha384_context sha512_context
-void sha512_init(struct sha512_context *ctx);
-void sha384_init(struct sha384_context *ctx);
-
-void sha512_update(struct sha512_context *ctx, const byte *buf, size_t len);
-static inline void sha384_update(struct sha384_context *ctx, const byte *buf, size_t len)
-{ sha512_update(ctx, buf, len); }
-
-byte *sha512_final(struct sha512_context *ctx);
-static inline byte *sha384_final(struct sha384_context *ctx)
-{ return sha512_final(ctx); }
-
-
-/*
- * HMAC-SHA512, HMAC-SHA384
- */
-
-struct sha512_hmac_context
-{
- struct sha512_context ictx;
- struct sha512_context octx;
-};
-
-#define sha384_hmac_context sha512_hmac_context
-
-
-void sha512_hmac_init(struct sha512_hmac_context *ctx, const byte *key, size_t keylen);
-void sha384_hmac_init(struct sha384_hmac_context *ctx, const byte *key, size_t keylen);
+void sha512_init(struct hash_context *ctx);
+void sha384_init(struct hash_context *ctx);
-void sha512_hmac_update(struct sha512_hmac_context *ctx, const byte *buf, size_t buflen);
-void sha384_hmac_update(struct sha384_hmac_context *ctx, const byte *buf, size_t buflen);
+void sha512_update(struct hash_context *ctx, const byte *buf, uint len);
+#define sha384_update sha512_update
-byte *sha512_hmac_final(struct sha512_hmac_context *ctx);
-byte *sha384_hmac_final(struct sha384_hmac_context *ctx);
+byte *sha512_final(struct hash_context *ctx);
+#define sha384_final sha512_final
#endif /* _BIRD_SHA512_H_ */
diff --git a/lib/slist_test.c b/lib/slist_test.c
new file mode 100644
index 00000000..069e361c
--- /dev/null
+++ b/lib/slist_test.c
@@ -0,0 +1,384 @@
+/*
+ * BIRD Library -- Safe Linked Lists Tests
+ *
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "lib/slists.h"
+
+#define MAX_NUM 1000
+
+static snode nodes[MAX_NUM];
+static slist lst;
+
+static void
+show_list(void)
+{
+ bt_debug("\n");
+ bt_debug("list.null is at %p and point to %p \n", &lst.null, lst.null);
+ bt_debug("list.head is at %p and point to %p \n", &lst.head, lst.head);
+ bt_debug("list.tail is at %p and point to %p \n", &lst.tail, lst.tail);
+ bt_debug("list.tail_readers is at %p and point to %p \n", &lst.tail_readers, lst.tail_readers);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ bt_debug("n[%3i] is at %p, .prev (%p) points to %p, .next (%p) points to %p, .readers (%p) points to %p \n",
+ i, &nodes[i], &(nodes[i].prev), nodes[i].prev, &(nodes[i].next), nodes[i].next, &(nodes[i].readers), nodes[i].readers);
+}
+
+static int
+is_filled_list_well_linked(void)
+{
+ int i;
+ bt_assert(lst.head == &nodes[0]);
+ bt_assert(lst.tail == &nodes[MAX_NUM-1]);
+ bt_assert((void *) nodes[0].prev == (void *) &lst.head);
+ bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &lst.null);
+
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ if (i < (MAX_NUM-1))
+ bt_assert(nodes[i].next == &nodes[i+1]);
+
+ if (i > 0)
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+
+ return 1;
+}
+
+static int
+is_empty_list_well_unlinked(void)
+{
+ bt_assert(lst.head == SNODE &lst.null);
+ bt_assert(lst.tail == SNODE &lst.head);
+
+ bt_assert(EMPTY_SLIST(lst));
+
+ return 1;
+}
+
+static void
+init_list__(slist *l, struct snode nodes[])
+{
+ s_init_list(l);
+
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ nodes[i].next = NULL;
+ nodes[i].prev = NULL;
+ }
+}
+
+static void
+init_list_(void)
+{
+ init_list__(&lst, nodes);
+}
+
+static int
+t_add_tail(void)
+{
+ int i;
+
+ init_list_();
+ for (i = 0; i < MAX_NUM; i++)
+ {
+ s_add_tail(&lst, &nodes[i]);
+ bt_debug(".");
+ bt_assert(lst.tail == &nodes[i]);
+ bt_assert(lst.head == &nodes[0]);
+ bt_assert((void *) nodes[i].next == (void *) &lst.null);
+ if (i > 0)
+ {
+ bt_assert(nodes[i-1].next == &nodes[i]);
+ bt_assert(nodes[i].prev == &nodes[i-1]);
+ }
+ }
+
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static int
+t_add_head(void)
+{
+ int i;
+
+ init_list_();
+ for (i = MAX_NUM-1; i >= 0; i--)
+ {
+ s_add_head(&lst, &nodes[i]);
+ bt_debug(".");
+ bt_assert(lst.head == &nodes[i]);
+ bt_assert(lst.tail == &nodes[MAX_NUM-1]);
+ if (i < MAX_NUM-1)
+ {
+ bt_assert(nodes[i+1].prev == &nodes[i]);
+ bt_assert(nodes[i].next == &nodes[i+1]);
+ }
+ }
+
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static void
+insert_node_(snode *n, snode *after)
+{
+ s_insert_node(n, after);
+ bt_debug(".");
+}
+
+static int
+t_insert_node(void)
+{
+ int i;
+
+ init_list_();
+
+ // add first node
+ insert_node_(&nodes[0], SNODE &lst.head);
+
+ // add odd nodes
+ for (i = 2; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-2]);
+
+ // add even nodes
+ for (i = 1; i < MAX_NUM; i+=2)
+ insert_node_(&nodes[i], &nodes[i-1]);
+
+ bt_debug("\n");
+ bt_assert(is_filled_list_well_linked());
+
+ return 1;
+}
+
+static void
+fill_list2(slist *l, snode nodes[])
+{
+ int i;
+ for (i = 0; i < MAX_NUM; i++)
+ s_add_tail(l, &nodes[i]);
+}
+
+static void
+fill_list(void)
+{
+ fill_list2(&lst, SNODE nodes);
+}
+
+
+static int
+t_remove_node(void)
+{
+ int i;
+
+ init_list_();
+
+ /* Fill & Remove & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i++)
+ s_rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ /* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
+ fill_list();
+ for (i = 0; i < MAX_NUM; i+=2)
+ s_rem_node(&nodes[i]);
+
+ int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
+ bt_assert(lst.head == &nodes[1]);
+ bt_assert(lst.tail == &nodes[tail_node_index]);
+ bt_assert(nodes[tail_node_index].next == SNODE &lst.null);
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ {
+ if (i > 1)
+ bt_assert(nodes[i].prev == &nodes[i-2]);
+ if (i < tail_node_index)
+ bt_assert(nodes[i].next == &nodes[i+2]);
+ }
+
+ for (i = 1; i < MAX_NUM; i+=2)
+ s_rem_node(&nodes[i]);
+ bt_assert(is_empty_list_well_unlinked());
+
+ return 1;
+}
+
+static int
+t_add_tail_list(void)
+{
+ snode nodes2[MAX_NUM];
+ slist l2;
+
+ init_list__(&lst, SNODE &nodes);
+ fill_list2(&lst, SNODE &nodes);
+
+ init_list__(&l2, SNODE &nodes2);
+ fill_list2(&l2, SNODE &nodes2);
+
+ s_add_tail_list(&lst, &l2);
+
+ bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
+ bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
+ bt_assert(lst.tail == &nodes2[MAX_NUM-1]);
+
+ return 1;
+}
+
+void
+dump(const char *str, slist *a)
+{
+ snode *x;
+
+ bt_debug("%s \n", str);
+ for (x = SHEAD(*a); x; x = x->next)
+ {
+ siterator *i, *j;
+ bt_debug("%p", x);
+ j = (siterator *) x;
+ for (i = x->readers; i; i = i->next)
+ {
+ if (i->prev != j)
+ bt_debug(" ???");
+ j = i;
+ bt_debug(" [%p:%p]", i, i->node);
+ }
+ bt_debug("\n");
+ }
+ bt_debug("---\n");
+}
+
+static int
+t_iterator_walk(void)
+{
+ snode *node;
+ siterator iter;
+
+ init_list_();
+ fill_list();
+
+ int k;
+ int i = 0;
+
+ show_list();
+
+ s_init(&iter, &lst);
+ WALK_SLIST(node, lst)
+ {
+ s_get(&iter);
+ s_put(&iter, node);
+ bt_debug("node->readers: %p, iter: %p, nodes[%d].readers: %p, node: %p, nodes[i]: %p, node->next: %p \n",
+ node->readers, &iter, i, nodes[i].readers, node, &(nodes[i]), node->next);
+ bt_assert(node->readers == &iter);
+ bt_assert(node->readers == nodes[i].readers);
+ bt_assert(node == &(nodes[i]));
+ for (k = 0; k < MAX_NUM; k++)
+ if (k != i)
+ bt_assert(nodes[k].readers == NULL);
+
+ dump("",&lst);
+ i++;
+ }
+
+ return 1;
+}
+
+static int
+t_original(void)
+{
+ slist a, b;
+ snode *x, *y;
+ siterator i, j;
+
+ s_init_list(&a);
+ s_init_list(&b);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&a, x);
+ dump("1", &a);
+
+ s_init(&i, &a);
+ s_init(&j, &a);
+ dump("2", &a);
+
+ x = s_get(&i);
+ bt_debug("Got %p\n", x);
+ dump("3", &a);
+
+ s_put(&i, x->next);
+ dump("4", &a);
+
+ y = s_get(&j);
+ while (y)
+ {
+ s_put(&j, y);
+ dump("5*", &a);
+ y = s_get(&j)->next;
+ }
+
+ dump("5 done", &a);
+
+ s_rem_node(a.head->next);
+ dump("6 (deletion)", &a);
+
+ s_put(&i, s_get(&i)->next);
+ dump("6 (relink)", &a);
+
+ x = xmalloc(sizeof(*x));
+ s_add_tail(&b, x);
+ dump("7 (second list)", &b);
+
+ s_add_tail_list(&b, &a);
+ dump("8 (after merge)", &b);
+
+ return 1;
+}
+
+static int
+t_safe_del_walk(void)
+{
+ init_list_();
+ fill_list();
+
+ show_list();
+
+ snode *node, *node_next;
+ WALK_SLIST_DELSAFE(node,node_next, lst)
+ {
+ bt_debug("Will remove node %p \n", node);
+ s_rem_node(SNODE node);
+ }
+ bt_assert(is_empty_list_well_unlinked());
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_add_tail, "Adding nodes to tail of list");
+ bt_test_suite(t_add_head, "Adding nodes to head of list");
+ bt_test_suite(t_insert_node, "Inserting nodes to list");
+ bt_test_suite(t_remove_node, "Removing nodes from list");
+ bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
+ bt_test_suite(t_iterator_walk, "Iterator walk");
+ bt_test_suite(t_safe_del_walk, "WALK_SLIST_DELSAFE and s_rem_node all nodes");
+ bt_test_suite(t_original, "The original BIRD test suit for SLIST");
+
+ return bt_exit_value();
+}
diff --git a/lib/slists.c b/lib/slists.c
index 6e0df39e..00f3c84f 100644
--- a/lib/slists.c
+++ b/lib/slists.c
@@ -150,85 +150,3 @@ s_add_tail_list(slist *to, slist *l)
to->tail = q;
s_merge((snode *) &l->null, (snode *) &to->null);
}
-
-#ifdef TEST
-
-#include "lib/resource.h"
-#include <stdio.h>
-
-void dump(char *c, slist *a)
-{
- snode *x;
-
- puts(c);
- for(x=SHEAD(*a); x; x=x->next)
- {
- siterator *i, *j;
- printf("%p", x);
- j = (siterator *) x;
- for(i=x->readers; i; i=i->next)
- {
- if (i->prev != j)
- printf(" ???");
- j = i;
- printf(" [%p:%p]", i, i->node);
- }
- putchar('\n');
- }
- puts("---");
-}
-
-int main(void)
-{
- slist a, b;
- snode *x, *y;
- siterator i, j;
-
- s_init_list(&a);
- s_init_list(&b);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- x = xmalloc(sizeof(*x));
- s_add_tail(&a, x);
- dump("1", &a);
-
- s_init(&i, &a);
- s_init(&j, &a);
- dump("2", &a);
-
- x = s_get(&i);
- printf("Got %p\n", x);
- dump("3", &a);
-
- s_put(&i, x->next);
- dump("4", &a);
-
- y = s_get(&j);
- while (y)
- {
- s_put(&j, y);
- dump("5*", &a);
- y = s_get(&j)->next;
- }
-
- dump("5 done", &a);
-
- s_rem_node(a.head->next);
- dump("6 (deletion)", &a);
-
- s_put(&i, s_get(&i)->next);
- dump("6 (relink)", &a);
-
- x = xmalloc(sizeof(*x));
- s_add_tail(&b, x);
- dump("7 (second list)", &b);
-
- s_add_tail_list(&b, &a);
- dump("8 (after merge)", &b);
-
- return 0;
-}
-
-#endif
diff --git a/lib/socket.h b/lib/socket.h
index 99bac6f8..d5281b83 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -54,7 +54,7 @@ typedef struct birdsock {
byte *rbuf, *rpos; /* NULL=allocate automatically */
uint fast_rx; /* RX has higher priority in event loop */
uint rbsize;
- int (*rx_hook)(struct birdsock *, int size); /* NULL=receiving turned off, returns 1 to clear rx buffer */
+ int (*rx_hook)(struct birdsock *, uint size); /* NULL=receiving turned off, returns 1 to clear rx buffer */
byte *tbuf, *tpos; /* NULL=allocate automatically */
byte *ttx; /* Internal */
diff --git a/lib/string.h b/lib/string.h
index 9af49b9e..0d34f9c5 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -13,6 +13,8 @@
#include <string.h>
#include <strings.h>
+#include "lib/resource.h"
+
int bsprintf(char *str, const char *fmt, ...);
int bvsprintf(char *str, const char *fmt, va_list args);
int bsnprintf(char *str, int size, const char *fmt, ...);
@@ -30,6 +32,34 @@ static inline char *xbasename(const char *str)
return s ? s+1 : (char *) str;
}
+static inline char *
+xstrdup(const char *c)
+{
+ size_t l = strlen(c) + 1;
+ char *z = xmalloc(l);
+ memcpy(z, c, l);
+ return z;
+}
+
+static inline char *
+lp_strdup(linpool *lp, const char *c)
+{
+ size_t l = strlen(c) + 1;
+ char *z = lp_allocu(lp, l);
+ memcpy(z, c, l);
+ return z;
+}
+
+static inline void
+memset32(void *D, u32 val, uint n)
+{
+ u32 *dst = D;
+ uint i;
+
+ for (i = 0; i < n; i++)
+ dst[i] = val;
+}
+
#define ROUTER_ID_64_LENGTH 23
#endif
diff --git a/lib/unaligned.h b/lib/unaligned.h
index ad5811ab..4e841f3a 100644
--- a/lib/unaligned.h
+++ b/lib/unaligned.h
@@ -69,4 +69,22 @@ put_u64(void *p, u64 x)
memcpy(p+4, &xl, 4);
}
+static inline void
+get_u32s(const void *p, u32 *x, int n)
+{
+ int i;
+ memcpy(x, p, 4*n);
+ for (i = 0; i < n; i++)
+ x[i] = ntohl(x[i]);
+}
+
+static inline void
+put_u32s(void *p, const u32 *x, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ put_u32((byte *) p + 4*i, x[i]);
+}
+
+
#endif