Merge remote-tracking branch 'origin/mq-static-analysis'
This commit is contained in:
commit
048eb2ddf1
35 changed files with 253 additions and 251 deletions
|
@ -184,6 +184,15 @@ check: tests tests_run
|
|||
tests: $(tests_targets)
|
||||
tests_run: $(tests_targets_ok)
|
||||
|
||||
STATIC_CHECKERS_ENABLE := nullability.NullableDereferenced nullability.NullablePassedToNonnull nullability.NullableReturnedFromNonnull optin.portability.UnixAPI valist.CopyToSelf valist.Uninitialized valist.Unterminated
|
||||
STATIC_CHECKERS_DISABLE := deadcode.DeadStores
|
||||
STATIC_SCAN_FLAGS := -o $(objdir)/static-scan/ $(addprefix -enable-checker ,$(STATIC_CHECKERS_ENABLE)) $(addprefix -disable-checker ,$(STATIC_CHECKERS_DISABLE))
|
||||
|
||||
static-scan:
|
||||
$(E)echo Running static code analysis
|
||||
$(Q)$(MAKE) clean
|
||||
$(Q)scan-build $(STATIC_SCAN_FLAGS) $(MAKE) -$(MAKEFLAGS)
|
||||
|
||||
tags:
|
||||
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ WHITE [ \t]
|
|||
|
||||
errno = 0;
|
||||
l = bstrtoul10(yytext, &e);
|
||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
|
||||
if (!e || (*e != ':') || (errno == ERANGE) || (l >> 32))
|
||||
cf_error("ASN out of range");
|
||||
|
||||
if (l >> 16)
|
||||
|
@ -187,7 +187,7 @@ WHITE [ \t]
|
|||
|
||||
errno = 0;
|
||||
l = bstrtoul10(e+1, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||
if (!e || *e || (errno == ERANGE) || (l >> len2))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
|
||||
|
@ -214,13 +214,13 @@ WHITE [ \t]
|
|||
|
||||
errno = 0;
|
||||
l = bstrtoul10(yytext+2, &e);
|
||||
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
|
||||
if (!e || (*e != ':') || (errno == ERANGE) || (l >> len1))
|
||||
cf_error("ASN out of range");
|
||||
cf_lval.i64 |= ((u64) l) << len2;
|
||||
|
||||
errno = 0;
|
||||
l = bstrtoul10(e+1, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> len2))
|
||||
if (!e || *e || (errno == ERANGE) || (l >> len2))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
|
||||
|
@ -242,7 +242,7 @@ WHITE [ \t]
|
|||
|
||||
errno = 0;
|
||||
l = bstrtoul10(e, &e);
|
||||
if (e && *e || (errno == ERANGE) || (l >> 16))
|
||||
if (!e || *e || (errno == ERANGE) || (l >> 16))
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i64 |= l;
|
||||
|
||||
|
@ -266,7 +266,7 @@ WHITE [ \t]
|
|||
unsigned long int l;
|
||||
errno = 0;
|
||||
l = bstrtoul16(yytext+2, &e);
|
||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
if (!e || *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i = l;
|
||||
return NUM;
|
||||
|
@ -277,7 +277,7 @@ WHITE [ \t]
|
|||
unsigned long int l;
|
||||
errno = 0;
|
||||
l = bstrtoul10(yytext, &e);
|
||||
if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
if (!e || *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
|
||||
cf_error("Number out of range");
|
||||
cf_lval.i = l;
|
||||
return NUM;
|
||||
|
|
13
configure.ac
13
configure.ac
|
@ -24,6 +24,12 @@ AC_ARG_ENABLE([debug-generated],
|
|||
[enable_debug_generated=no]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([debug-expensive],
|
||||
[AS_HELP_STRING([--enable-debug-expensive], [enable expensive consistency checks (implies --enable-debug) @<:@no@:>@])],
|
||||
[],
|
||||
[enable_debug_expensive=no]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([memcheck],
|
||||
[AS_HELP_STRING([--enable-memcheck], [check memory allocations when debugging @<:@yes@:>@])],
|
||||
[],
|
||||
|
@ -72,6 +78,9 @@ AC_ARG_VAR([FLEX], [location of the Flex program])
|
|||
AC_ARG_VAR([BISON], [location of the Bison program])
|
||||
AC_ARG_VAR([M4], [location of the M4 program])
|
||||
|
||||
if test "$enable_debug_expensive" = yes; then
|
||||
enable_debug=yes
|
||||
fi
|
||||
|
||||
if test "$srcdir" = . ; then
|
||||
# Building in current directory => create obj directory holding all objects
|
||||
|
@ -388,6 +397,10 @@ if test "$enable_debug" = yes ; then
|
|||
AC_CHECK_LIB([efence], [malloc])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "enable_debug_expensive" = yes ; then
|
||||
AC_DEFINE([ENABLE_EXPENSIVE_CHECKS], [1], [Define to 1 if you want to run expensive consistency checks.])
|
||||
fi
|
||||
fi
|
||||
|
||||
CLIENT=birdcl
|
||||
|
|
153
filter/config.Y
153
filter/config.Y
|
@ -185,159 +185,6 @@ f_generate_empty(struct f_dynamic_attr dyn)
|
|||
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static inline struct f_inst *
|
||||
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
|
||||
{
|
||||
struct f_inst *rv;
|
||||
|
||||
if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
|
||||
if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
|
||||
cf_error( "Can't operate with value of non-integer type in pair constructor");
|
||||
|
||||
check_u16(t1->a[1].i);
|
||||
check_u16(t2->a[1].i);
|
||||
|
||||
rv = f_new_inst(FI_CONSTANT);
|
||||
rv->val = (struct f_val) {
|
||||
.type = T_PAIR,
|
||||
.val.i = pair(t1->a[1].i, t2->a[1].i),
|
||||
};
|
||||
}
|
||||
else {
|
||||
rv = f_new_inst(FI_PAIR_CONSTRUCT);
|
||||
rv->a[0].p = t1;
|
||||
rv->a[1].p = t2;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline struct f_inst *
|
||||
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
|
||||
{
|
||||
struct f_inst *rv;
|
||||
int c1 = 0, c2 = 0, ipv4_used = 0;
|
||||
u32 key = 0, val2 = 0;
|
||||
|
||||
if (tk->fi_code == FI_CONSTANT) {
|
||||
c1 = 1;
|
||||
struct f_val *val = &(tk->val);
|
||||
|
||||
if (val->type == T_INT) {
|
||||
ipv4_used = 0; key = val->val.i;
|
||||
}
|
||||
else if (tk->val.type == T_QUAD) {
|
||||
ipv4_used = 1; key = val->val.i;
|
||||
}
|
||||
else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
|
||||
ipv4_used = 1; key = ipa_to_u32(val->val.ip);
|
||||
}
|
||||
else
|
||||
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
|
||||
}
|
||||
|
||||
if (tv->fi_code == FI_CONSTANT) {
|
||||
if (tv->val.type != T_INT)
|
||||
cf_error("Can't operate with value of non-integer type in EC constructor");
|
||||
c2 = 1;
|
||||
val2 = tv->val.val.i;
|
||||
}
|
||||
|
||||
if (c1 && c2) {
|
||||
u64 ec;
|
||||
|
||||
if (kind == EC_GENERIC) {
|
||||
ec = ec_generic(key, val2);
|
||||
}
|
||||
else if (ipv4_used) {
|
||||
check_u16(val2);
|
||||
ec = ec_ip4(kind, key, val2);
|
||||
}
|
||||
else if (key < 0x10000) {
|
||||
ec = ec_as2(kind, key, val2);
|
||||
}
|
||||
else {
|
||||
check_u16(val2);
|
||||
ec = ec_as4(kind, key, val2);
|
||||
}
|
||||
|
||||
rv = f_new_inst(FI_CONSTANT);
|
||||
rv->val = (struct f_val) {
|
||||
.type = T_EC,
|
||||
.val.ec = ec,
|
||||
};
|
||||
}
|
||||
else {
|
||||
rv = f_new_inst(FI_EC_CONSTRUCT);
|
||||
rv->aux = kind;
|
||||
rv->a[0].p = tk;
|
||||
rv->a[1].p = tv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline struct f_inst *
|
||||
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
|
||||
{
|
||||
struct f_inst *rv;
|
||||
|
||||
if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
|
||||
if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
|
||||
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
|
||||
|
||||
rv = f_new_inst(FI_CONSTANT);
|
||||
rv->val = (struct f_val) {
|
||||
.type = T_LC,
|
||||
.val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = f_new_inst(FI_LC_CONSTRUCT);
|
||||
rv->a[0].p = t1;
|
||||
rv->a[1].p = t2;
|
||||
rv->a[2].p = t3;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline struct f_inst *
|
||||
f_generate_path_mask(struct f_inst *t)
|
||||
{
|
||||
uint len = 0;
|
||||
uint dyn = 0;
|
||||
for (const struct f_inst *tt = t; tt; tt = tt->next) {
|
||||
if (tt->fi_code != FI_CONSTANT)
|
||||
dyn++;
|
||||
len++;
|
||||
}
|
||||
|
||||
if (dyn) {
|
||||
struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
|
||||
pmc->a[0].p = t;
|
||||
pmc->a[1].i = len;
|
||||
return pmc;
|
||||
}
|
||||
|
||||
struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
|
||||
|
||||
uint i = 0;
|
||||
for (const struct f_inst *tt = t; tt; tt = tt->next)
|
||||
pm->item[i++] = tt->val.val.pmi;
|
||||
|
||||
pm->len = i;
|
||||
struct f_inst *pmc = f_new_inst(FI_CONSTANT);
|
||||
pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
|
||||
|
||||
return pmc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Remove all new lines and doubled whitespaces
|
||||
* and convert all tabulators to spaces
|
||||
|
|
|
@ -138,7 +138,7 @@ FID_IFCONST([[
|
|||
}
|
||||
FID_IFCONST([[
|
||||
const struct f_inst **items = NULL;
|
||||
if (constargs) {
|
||||
if (constargs && whati->varcount) {
|
||||
items = alloca(whati->varcount * sizeof(struct f_inst *));
|
||||
const struct f_inst *child = fvar;
|
||||
for (uint i=0; child; i++)
|
||||
|
|
|
@ -261,7 +261,7 @@
|
|||
|
||||
FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, "ec subtype %s", ec_subtype_str(item->ecs));
|
||||
|
||||
int check, ipv4_used;
|
||||
int ipv4_used;
|
||||
u32 key, val;
|
||||
|
||||
if (v1.type == T_INT) {
|
||||
|
@ -279,21 +279,20 @@
|
|||
|
||||
val = v2.val.i;
|
||||
|
||||
if (ecs == EC_GENERIC) {
|
||||
check = 0; RESULT(T_EC, ec, ec_generic(key, val));
|
||||
}
|
||||
else if (ipv4_used) {
|
||||
check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
|
||||
}
|
||||
else if (key < 0x10000) {
|
||||
check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
|
||||
}
|
||||
else {
|
||||
check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
|
||||
}
|
||||
|
||||
if (check && (val > 0xFFFF))
|
||||
runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
|
||||
if (ecs == EC_GENERIC)
|
||||
RESULT(T_EC, ec, ec_generic(key, val));
|
||||
else if (ipv4_used)
|
||||
if (val <= 0xFFFF)
|
||||
RESULT(T_EC, ec, ec_ip4(ecs, key, val));
|
||||
else
|
||||
runtime("4-byte value %u can't be used with IP-address key in extended community", val);
|
||||
else if (key < 0x10000)
|
||||
RESULT(T_EC, ec, ec_as2(ecs, key, val));
|
||||
else
|
||||
if (val <= 0xFFFF)
|
||||
RESULT(T_EC, ec, ec_as4(ecs, key, val));
|
||||
else
|
||||
runtime("4-byte value %u can't be used with 4-byte ASN in extended community", val);
|
||||
}
|
||||
|
||||
INST(FI_LC_CONSTRUCT, 3, 1) {
|
||||
|
|
|
@ -72,6 +72,7 @@ static inline int u64_cmp(u64 i1, u64 i2)
|
|||
#define NORET __attribute__((noreturn))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#define PACKED __attribute__((packed))
|
||||
#define NONNULL(...) __attribute__((nonnull((__VA_ARGS__))))
|
||||
|
||||
#ifndef HAVE_THREAD_LOCAL
|
||||
#define _Thread_local
|
||||
|
@ -162,12 +163,23 @@ void debug(const char *msg, ...); /* Printf to debug output */
|
|||
#define DBG(x, y...) do { } while(0)
|
||||
#endif
|
||||
|
||||
#define ASSERT_DIE(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
|
||||
|
||||
#define EXPENSIVE_CHECK(x) /* intentionally left blank */
|
||||
|
||||
#ifdef DEBUGGING
|
||||
#define ASSERT(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
|
||||
#define ASSERT(x) ASSERT_DIE(x)
|
||||
#define ASSUME(x) ASSERT_DIE(x)
|
||||
#ifdef ENABLE_EXPENSIVE_CHECKS
|
||||
#undef EXPENSIVE_CHECK
|
||||
#define EXPENSIVE_CHECK(x) ASSERT_DIE(x)
|
||||
#endif
|
||||
#else
|
||||
#define ASSERT(x) do { if (!(x)) log(L_BUG "Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
|
||||
#define ASSUME(x) /* intentionally left blank */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUGGING
|
||||
asm(
|
||||
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
|
||||
|
|
5
lib/ip.c
5
lib/ip.c
|
@ -264,6 +264,9 @@ ip6_pton(const char *a, ip6_addr *o)
|
|||
int i, j, k, l, hfil;
|
||||
const char *start;
|
||||
|
||||
if (!a[0]) /* Empty string check */
|
||||
return 0;
|
||||
|
||||
if (a[0] == ':') /* Leading :: */
|
||||
{
|
||||
if (a[1] != ':')
|
||||
|
@ -333,6 +336,8 @@ ip6_pton(const char *a, ip6_addr *o)
|
|||
for (; i>=hfil; i--)
|
||||
words[i] = 0;
|
||||
}
|
||||
else if (i != 8) /* Incomplete address */
|
||||
return 0;
|
||||
|
||||
/* Convert the address to ip6_addr format */
|
||||
for (i=0; i<4; i++)
|
||||
|
|
|
@ -13,26 +13,39 @@
|
|||
#define IP4_MAX_LEN 16
|
||||
|
||||
static int
|
||||
test_ipa_pton(void *out_, const void *in_, const void *expected_out_)
|
||||
test_ip4_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_;
|
||||
ip4_addr ip4;
|
||||
|
||||
if (expected_out)
|
||||
{
|
||||
bt_assert(ip4_pton(in, &ip4));
|
||||
*out = ipa_from_ip4(ip4);
|
||||
return ipa_equal(*out, *expected_out);
|
||||
}
|
||||
else
|
||||
return !ip4_pton(in, &ip4);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
test_ip6_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
|
||||
if (expected_out)
|
||||
{
|
||||
bt_assert(ip6_pton(in, out));
|
||||
/* ip_addr == ip6_addr */
|
||||
}
|
||||
|
||||
return ipa_equal(*out, *expected_out);
|
||||
}
|
||||
else
|
||||
return !ip6_pton(in, out);
|
||||
}
|
||||
|
||||
static int
|
||||
t_ip4_pton(void)
|
||||
|
@ -52,7 +65,7 @@ t_ip4_pton(void)
|
|||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
return bt_assert_batch(test_vectors, test_ip4_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -87,9 +100,17 @@ t_ip6_pton(void)
|
|||
.in = "2605:2700:0:3::4713:93e3",
|
||||
.out = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
|
||||
},
|
||||
{
|
||||
.in = "2605:2700:0:3:4713:93e3",
|
||||
.out = NULL,
|
||||
},
|
||||
{
|
||||
.in = "2",
|
||||
.out = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
return bt_assert_batch(test_vectors, test_ip6_pton, bt_fmt_str, bt_fmt_ipa);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
79
lib/lists.c
79
lib/lists.c
|
@ -29,6 +29,42 @@
|
|||
#include "nest/bird.h"
|
||||
#include "lib/lists.h"
|
||||
|
||||
LIST_INLINE int
|
||||
check_list(list *l, node *n)
|
||||
{
|
||||
if (!l)
|
||||
{
|
||||
ASSERT_DIE(n);
|
||||
ASSERT_DIE(n->prev);
|
||||
|
||||
do { n = n->prev; } while (n->prev);
|
||||
|
||||
l = SKIP_BACK(list, head_node, n);
|
||||
}
|
||||
|
||||
int seen = 0;
|
||||
|
||||
ASSERT_DIE(l->null == NULL);
|
||||
ASSERT_DIE(l->head != NULL);
|
||||
ASSERT_DIE(l->tail != NULL);
|
||||
|
||||
node *prev = &l->head_node, *cur = l->head, *next = l->head->next;
|
||||
while (next)
|
||||
{
|
||||
if (cur == n)
|
||||
seen++;
|
||||
ASSERT_DIE(cur->prev == prev);
|
||||
prev = cur;
|
||||
cur = next;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
ASSERT_DIE(cur == &(l->tail_node));
|
||||
ASSERT_DIE(!n || (seen == 1));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_tail - append a node to a list
|
||||
* @l: linked list
|
||||
|
@ -39,6 +75,10 @@
|
|||
LIST_INLINE void
|
||||
add_tail(list *l, node *n)
|
||||
{
|
||||
EXPENSIVE_CHECK(check_list(l, NULL));
|
||||
ASSUME(n->prev == NULL);
|
||||
ASSUME(n->next == NULL);
|
||||
|
||||
node *z = l->tail;
|
||||
|
||||
n->next = &l->tail_node;
|
||||
|
@ -57,6 +97,10 @@ add_tail(list *l, node *n)
|
|||
LIST_INLINE void
|
||||
add_head(list *l, node *n)
|
||||
{
|
||||
EXPENSIVE_CHECK(check_list(l, NULL));
|
||||
ASSUME(n->prev == NULL);
|
||||
ASSUME(n->next == NULL);
|
||||
|
||||
node *z = l->head;
|
||||
|
||||
n->next = z;
|
||||
|
@ -76,6 +120,10 @@ add_head(list *l, node *n)
|
|||
LIST_INLINE void
|
||||
insert_node(node *n, node *after)
|
||||
{
|
||||
EXPENSIVE_CHECK(check_list(l, after));
|
||||
ASSUME(n->prev == NULL);
|
||||
ASSUME(n->next == NULL);
|
||||
|
||||
node *z = after->next;
|
||||
|
||||
n->next = z;
|
||||
|
@ -93,6 +141,8 @@ insert_node(node *n, node *after)
|
|||
LIST_INLINE void
|
||||
rem_node(node *n)
|
||||
{
|
||||
EXPENSIVE_CHECK(check_list(NULL, n));
|
||||
|
||||
node *z = n->prev;
|
||||
node *x = n->next;
|
||||
|
||||
|
@ -103,24 +153,20 @@ rem_node(node *n)
|
|||
}
|
||||
|
||||
/**
|
||||
* replace_node - replace a node in a list with another one
|
||||
* @old: node to be removed
|
||||
* @new: node to be inserted
|
||||
* update_node - update node after calling realloc on it
|
||||
* @n: node to be updated
|
||||
*
|
||||
* Replaces node @old in the list it's linked in with node @new. Node
|
||||
* @old may be a copy of the original node, which is not accessed
|
||||
* through the list. The function could be called with @old == @new,
|
||||
* which just fixes neighbors' pointers in the case that the node
|
||||
* was reallocated.
|
||||
* Fixes neighbor pointers.
|
||||
*/
|
||||
LIST_INLINE void
|
||||
replace_node(node *old, node *new)
|
||||
update_node(node *n)
|
||||
{
|
||||
old->next->prev = new;
|
||||
old->prev->next = new;
|
||||
ASSUME(n->next->prev == n->prev->next);
|
||||
|
||||
new->prev = old->prev;
|
||||
new->next = old->next;
|
||||
n->next->prev = n;
|
||||
n->prev->next = n;
|
||||
|
||||
EXPENSIVE_CHECK(check_list(NULL, n));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,6 +195,9 @@ init_list(list *l)
|
|||
LIST_INLINE void
|
||||
add_tail_list(list *to, list *l)
|
||||
{
|
||||
EXPENSIVE_CHECK(check_list(to, NULL));
|
||||
EXPENSIVE_CHECK(check_list(l, NULL));
|
||||
|
||||
node *p = to->tail;
|
||||
node *q = l->head;
|
||||
|
||||
|
@ -157,6 +206,8 @@ add_tail_list(list *to, list *l)
|
|||
q = l->tail;
|
||||
q->next = &to->tail_node;
|
||||
to->tail = q;
|
||||
|
||||
EXPENSIVE_CHECK(check_list(to, NULL));
|
||||
}
|
||||
|
||||
LIST_INLINE uint
|
||||
|
@ -165,6 +216,8 @@ list_length(list *l)
|
|||
uint len = 0;
|
||||
node *n;
|
||||
|
||||
EXPENSIVE_CHECK(check_list(l, NULL));
|
||||
|
||||
WALK_LIST(n, *l)
|
||||
len++;
|
||||
|
||||
|
|
|
@ -222,26 +222,29 @@ t_remove_node(void)
|
|||
}
|
||||
|
||||
static int
|
||||
t_replace_node(void)
|
||||
t_update_node(void)
|
||||
{
|
||||
node head, inside, tail;
|
||||
|
||||
init_list_();
|
||||
fill_list();
|
||||
|
||||
replace_node(&nodes[0], &head);
|
||||
head = nodes[0];
|
||||
update_node(&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);
|
||||
inside = nodes[MAX_NUM/2];
|
||||
update_node(&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);
|
||||
tail = nodes[MAX_NUM-1];
|
||||
update_node(&tail);
|
||||
bt_assert(l.tail == &tail);
|
||||
bt_assert(tail.prev == &nodes[MAX_NUM-2]);
|
||||
bt_assert(tail.next == NODE &l.null);
|
||||
|
@ -280,7 +283,7 @@ main(int argc, char *argv[])
|
|||
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_update_node, "Updating nodes in list");
|
||||
bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
|
||||
|
||||
return bt_exit_value();
|
||||
|
|
|
@ -340,6 +340,7 @@ mb_alloc(pool *p, unsigned size)
|
|||
struct mblock *b = xmalloc(sizeof(struct mblock) + size);
|
||||
|
||||
b->r.class = &mb_class;
|
||||
b->r.n = (node) {};
|
||||
add_tail(&p->inside, &b->r.n);
|
||||
b->size = size;
|
||||
return b->data;
|
||||
|
@ -387,7 +388,7 @@ mb_realloc(void *m, unsigned size)
|
|||
struct mblock *b = SKIP_BACK(struct mblock, data, m);
|
||||
|
||||
b = xrealloc(b, sizeof(struct mblock) + size);
|
||||
replace_node(&b->r.n, &b->r.n);
|
||||
update_node(&b->r.n);
|
||||
b->size = size;
|
||||
return b->data;
|
||||
}
|
||||
|
|
|
@ -216,8 +216,11 @@ sl_new_head(slab *s)
|
|||
struct sl_obj *no;
|
||||
uint n = s->objs_per_slab;
|
||||
|
||||
h->first_free = o;
|
||||
h->num_full = 0;
|
||||
*h = (struct sl_head) {
|
||||
.first_free = o,
|
||||
.num_full = 0,
|
||||
};
|
||||
|
||||
while (n--)
|
||||
{
|
||||
o->slab = h;
|
||||
|
|
|
@ -72,6 +72,15 @@ bstrcmp(const char *s1, const char *s2)
|
|||
return !s2 - !s1;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
bmemcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
if (n)
|
||||
return memcpy(dest, src, n);
|
||||
else
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define ROUTER_ID_64_LENGTH 23
|
||||
|
||||
#endif
|
||||
|
|
|
@ -255,7 +255,7 @@ timer_init(void)
|
|||
btime
|
||||
tm_parse_time(const char *x)
|
||||
{
|
||||
struct tm tm;
|
||||
struct tm tm = {};
|
||||
int usec, n1, n2, n3, r;
|
||||
|
||||
r = sscanf(x, "%d-%d-%d%n %d:%d:%d%n.%d%n",
|
||||
|
|
|
@ -80,7 +80,7 @@ struct protocol {
|
|||
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
|
||||
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
|
||||
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
|
||||
int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
|
||||
int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
|
||||
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
|
||||
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
|
||||
};
|
||||
|
|
|
@ -577,7 +577,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
|
|||
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
|
||||
uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
|
||||
ea_list *ea_append(ea_list *to, ea_list *what);
|
||||
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
|
||||
void ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
|
||||
|
||||
#define ea_normalize(ea) do { \
|
||||
if (ea->next) { \
|
||||
|
|
|
@ -278,18 +278,22 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin
|
|||
while ((x || y) && max--)
|
||||
{
|
||||
int cmp = nexthop_compare_node(x, y);
|
||||
|
||||
if (cmp < 0)
|
||||
{
|
||||
ASSUME(x);
|
||||
*n = rx ? x : nexthop_copy_node(x, lp);
|
||||
x = x->next;
|
||||
}
|
||||
else if (cmp > 0)
|
||||
{
|
||||
ASSUME(y);
|
||||
*n = ry ? y : nexthop_copy_node(y, lp);
|
||||
y = y->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSUME(x && y);
|
||||
*n = rx ? x : (ry ? y : nexthop_copy_node(x, lp));
|
||||
x = x->next;
|
||||
y = y->next;
|
||||
|
@ -786,7 +790,7 @@ ea_free(ea_list *o)
|
|||
}
|
||||
|
||||
static int
|
||||
get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
|
||||
get_generic_attr(const eattr *a, byte **buf, int buflen UNUSED)
|
||||
{
|
||||
if (a->id == EA_GEN_IGP_METRIC)
|
||||
{
|
||||
|
@ -798,7 +802,7 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
|
|||
}
|
||||
|
||||
void
|
||||
ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
|
||||
ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
|
||||
{
|
||||
byte *bound = buf + bufsize - 32;
|
||||
u32 data = a->u.data;
|
||||
|
@ -894,7 +898,7 @@ ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte
|
|||
* get_attr() hook, it's consulted first.
|
||||
*/
|
||||
void
|
||||
ea_show(struct cli *c, eattr *e)
|
||||
ea_show(struct cli *c, const eattr *e)
|
||||
{
|
||||
struct protocol *p;
|
||||
int status = GA_UNKNOWN;
|
||||
|
|
|
@ -104,6 +104,12 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
|||
rte *e, *ee;
|
||||
byte ia[NET_MAX_TEXT_LENGTH+1];
|
||||
struct channel *ec = d->tab->export_channel;
|
||||
|
||||
/* The Clang static analyzer complains that ec may be NULL.
|
||||
* It should be ensured to be not NULL by rt_show_prepare_tables() */
|
||||
if (d->export_mode)
|
||||
ASSUME(ec);
|
||||
|
||||
int first = 1;
|
||||
int pass = 0;
|
||||
|
||||
|
|
|
@ -2304,7 +2304,7 @@ rt_commit(struct config *new, struct config *old)
|
|||
WALK_LIST(r, new->tables)
|
||||
if (!r->table)
|
||||
{
|
||||
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
||||
rtable *t = mb_allocz(rt_table_pool, sizeof(struct rtable));
|
||||
DBG("\t%s: created\n", r->name);
|
||||
rt_setup(rt_table_pool, t, r);
|
||||
add_tail(&routing_tables, &t->n);
|
||||
|
|
|
@ -1852,7 +1852,7 @@ babel_get_route_info(rte *rte, byte *buf)
|
|||
}
|
||||
|
||||
static int
|
||||
babel_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||
babel_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ struct bgp_attr_desc {
|
|||
void (*export)(struct bgp_export_state *s, eattr *a);
|
||||
int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
|
||||
void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
|
||||
void (*format)(eattr *ea, byte *buf, uint size);
|
||||
void (*format)(const eattr *ea, byte *buf, uint size);
|
||||
};
|
||||
|
||||
static const struct bgp_attr_desc bgp_attr_table[];
|
||||
|
@ -396,7 +396,7 @@ bgp_decode_origin(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
|
|||
}
|
||||
|
||||
static void
|
||||
bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
|
||||
bgp_format_origin(const eattr *a, byte *buf, uint size UNUSED)
|
||||
{
|
||||
static const char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
|
||||
|
||||
|
@ -510,7 +510,7 @@ bgp_decode_next_hop(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUS
|
|||
|
||||
/* TODO: This function should use AF-specific hook */
|
||||
static void
|
||||
bgp_format_next_hop(eattr *a, byte *buf, uint size UNUSED)
|
||||
bgp_format_next_hop(const eattr *a, byte *buf, uint size UNUSED)
|
||||
{
|
||||
ip_addr *nh = (void *) a->u.ptr->data;
|
||||
uint len = a->u.ptr->length;
|
||||
|
@ -601,7 +601,7 @@ bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, b
|
|||
}
|
||||
|
||||
static void
|
||||
bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED)
|
||||
bgp_format_aggregator(const eattr *a, byte *buf, uint size UNUSED)
|
||||
{
|
||||
const byte *data = a->u.ptr->data;
|
||||
|
||||
|
@ -676,7 +676,7 @@ bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags,
|
|||
}
|
||||
|
||||
static void
|
||||
bgp_format_cluster_list(eattr *a, byte *buf, uint size)
|
||||
bgp_format_cluster_list(const eattr *a, byte *buf, uint size)
|
||||
{
|
||||
/* Truncates cluster lists larger than buflen, probably not a problem */
|
||||
int_set_format(a->u.ptr, 0, -1, buf, size);
|
||||
|
@ -831,7 +831,7 @@ bgp_decode_aigp(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *d
|
|||
}
|
||||
|
||||
static void
|
||||
bgp_format_aigp(eattr *a, byte *buf, uint size UNUSED)
|
||||
bgp_format_aigp(const eattr *a, byte *buf, uint size UNUSED)
|
||||
{
|
||||
const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
|
||||
|
||||
|
@ -909,7 +909,7 @@ bgp_decode_mpls_label_stack(struct bgp_parse_state *s, uint code UNUSED, uint fl
|
|||
}
|
||||
|
||||
static void
|
||||
bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
|
||||
bgp_format_mpls_label_stack(const eattr *a, byte *buf, uint size)
|
||||
{
|
||||
u32 *labels = (u32 *) a->u.ptr->data;
|
||||
uint lnum = a->u.ptr->length / 4;
|
||||
|
@ -2293,7 +2293,7 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
|
|||
}
|
||||
|
||||
int
|
||||
bgp_get_attr(eattr *a, byte *buf, int buflen)
|
||||
bgp_get_attr(const eattr *a, byte *buf, int buflen)
|
||||
{
|
||||
uint i = EA_ID(a->id);
|
||||
const struct bgp_attr_desc *d;
|
||||
|
|
|
@ -552,7 +552,7 @@ static inline void
|
|||
bgp_set_attr_data(ea_list **to, struct linpool *pool, uint code, uint flags, void *data, uint len)
|
||||
{
|
||||
struct adata *a = lp_alloc_adata(pool, len);
|
||||
memcpy(a->data, data, len);
|
||||
bmemcpy(a->data, data, len);
|
||||
bgp_set_attr(to, pool, code, flags, (uintptr_t) a);
|
||||
}
|
||||
|
||||
|
@ -581,7 +581,7 @@ int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_be
|
|||
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
|
||||
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
|
||||
int bgp_preexport(struct proto *, struct rte **, struct linpool *);
|
||||
int bgp_get_attr(struct eattr *e, byte *buf, int buflen);
|
||||
int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
|
||||
void bgp_get_route_info(struct rte *, byte *buf);
|
||||
int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
|
||||
|
||||
|
|
|
@ -650,19 +650,20 @@ void
|
|||
ospf_dr_election(struct ospf_iface *ifa)
|
||||
{
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_neighbor *neigh, *ndr, *nbdr, me;
|
||||
struct ospf_neighbor *neigh, *ndr, *nbdr;
|
||||
u32 myid = p->router_id;
|
||||
|
||||
DBG("(B)DR election.\n");
|
||||
|
||||
me.state = NEIGHBOR_2WAY;
|
||||
me.rid = myid;
|
||||
me.priority = ifa->priority;
|
||||
me.ip = ifa->addr->ip;
|
||||
|
||||
me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
|
||||
me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
|
||||
me.iface_id = ifa->iface_id;
|
||||
struct ospf_neighbor me = {
|
||||
.state = NEIGHBOR_2WAY,
|
||||
.rid = myid,
|
||||
.priority = ifa->priority,
|
||||
.ip = ifa->addr->ip,
|
||||
.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid,
|
||||
.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid,
|
||||
.iface_id = ifa->iface_id,
|
||||
};
|
||||
|
||||
add_tail(&ifa->neigh_list, NODE & me);
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ ospf_get_route_info(rte * rte, byte * buf)
|
|||
}
|
||||
|
||||
static int
|
||||
ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
|
||||
ospf_get_attr(const eattr * a, byte * buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
@ -1244,7 +1244,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
|||
|
||||
uint num = p->gr->hash_entries;
|
||||
struct top_hash_entry *hea[num];
|
||||
struct top_hash_entry *hex[verbose ? num : 0];
|
||||
struct top_hash_entry **hex = verbose ? alloca(num * sizeof(struct top_hash_entry *)) : NULL;
|
||||
struct top_hash_entry *he;
|
||||
struct top_hash_entry *cnode = NULL;
|
||||
|
||||
|
@ -1289,6 +1289,8 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
|||
|
||||
lsa_compare_ospf3 = !ospf2;
|
||||
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
|
||||
|
||||
if (verbose)
|
||||
qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
|
||||
|
||||
/*
|
||||
|
|
|
@ -329,6 +329,14 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
|
|||
en->next_lsa_opts = 0;
|
||||
}
|
||||
|
||||
/* The static analyzer complains here that en->lsa_body may be NULL.
|
||||
* Yes, it may if ospf_hash_get() creates a new struct top_hash_entry.
|
||||
* In this case, also en->lsa.length must be 0 and lsa_length is never
|
||||
* equal to 0 while sizeof(struct ospf_lsa_header) is non-zero.
|
||||
* Therefore memcmp() is never executed with NULL here.
|
||||
* */
|
||||
ASSUME((en->lsa.length == 0) == (en->lsa_body == NULL));
|
||||
|
||||
/* Ignore the the new LSA if is the same as the current one */
|
||||
if ((en->lsa.age < LSA_MAXAGE) &&
|
||||
(lsa_length == en->lsa.length) &&
|
||||
|
|
|
@ -740,7 +740,7 @@ radv_pref_str(u32 pref)
|
|||
|
||||
/* The buffer has some minimal size */
|
||||
static int
|
||||
radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||
radv_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
|
|
@ -1190,7 +1190,7 @@ rip_get_route_info(rte *rte, byte *buf)
|
|||
}
|
||||
|
||||
static int
|
||||
rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||
rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
|
|
@ -1011,6 +1011,7 @@ rpki_send_error_pdu(struct rpki_cache *cache, const enum pdu_error_type error_co
|
|||
{
|
||||
va_start(args, fmt);
|
||||
msg_len = bvsnprintf(msg, sizeof(msg), fmt, args) + 1;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
u32 pdu_size = 16 + err_pdu_len + msg_len;
|
||||
|
|
|
@ -46,7 +46,7 @@ static inline void krt_sys_io_init(void) { }
|
|||
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
|
||||
static inline void krt_sys_postconfig(struct krt_config *x UNUSED) { }
|
||||
|
||||
static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { return GA_UNKNOWN; }
|
||||
static inline int krt_sys_get_attr(const eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { return GA_UNKNOWN; }
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2065,7 +2065,7 @@ static const char *krt_features_names[KRT_FEATURES_MAX] = {
|
|||
};
|
||||
|
||||
int
|
||||
krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||
krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
|
|
@ -1495,7 +1495,9 @@ sk_open_unix(sock *s, char *name)
|
|||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
return -1;
|
||||
|
||||
/* Path length checked in test_old_bird() */
|
||||
/* Path length checked in test_old_bird() but we may need unix sockets for other reasons in future */
|
||||
ASSERT_DIE(strlen(name) < sizeof(sa.sun_path));
|
||||
|
||||
sa.sun_family = AF_UNIX;
|
||||
strcpy(sa.sun_path, name);
|
||||
|
||||
|
|
|
@ -1156,7 +1156,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
|
|||
}
|
||||
|
||||
static int
|
||||
krt_get_attr(eattr *a, byte *buf, int buflen)
|
||||
krt_get_attr(const eattr *a, byte *buf, int buflen)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
|
|
|
@ -141,7 +141,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
|
|||
int krt_capable(rte *e);
|
||||
void krt_do_scan(struct krt_proto *);
|
||||
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old);
|
||||
int krt_sys_get_attr(eattr *a, byte *buf, int buflen);
|
||||
int krt_sys_get_attr(const eattr *a, byte *buf, int buflen);
|
||||
|
||||
|
||||
/* kif sysdep */
|
||||
|
|
|
@ -495,7 +495,10 @@ void
|
|||
bt_fmt_ipa(char *buf, size_t size, const void *data)
|
||||
{
|
||||
const ip_addr *ip = data;
|
||||
if (data)
|
||||
bsnprintf(buf, size, "%I", *ip);
|
||||
else
|
||||
bsnprintf(buf, size, "(null)");
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in a new issue