Bug Summary

File:src/usr.sbin/eigrpd/interface.c
Warning:line 240, column 7
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name interface.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/eigrpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/eigrpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/eigrpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/eigrpd/interface.c
1/* $OpenBSD: interface.c,v 1.25 2019/06/28 13:32:47 deraadt Exp $ */
2
3/*
4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/ioctl.h>
24#include <arpa/inet.h>
25
26#include <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include "eigrpd.h"
32#include "eigrpe.h"
33#include "log.h"
34
35static __inline int iface_id_compare(struct eigrp_iface *,
36 struct eigrp_iface *);
37static struct iface *if_new(struct eigrpd_conf *, struct kif *);
38static void if_del(struct iface *);
39static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
40static void eigrp_if_start(struct eigrp_iface *);
41static void eigrp_if_reset(struct eigrp_iface *);
42static void eigrp_if_hello_timer(int, short, void *);
43static void eigrp_if_start_hello_timer(struct eigrp_iface *);
44static void eigrp_if_stop_hello_timer(struct eigrp_iface *);
45static int if_join_ipv4_group(struct iface *, struct in_addr *);
46static int if_leave_ipv4_group(struct iface *, struct in_addr *);
47static int if_join_ipv6_group(struct iface *, struct in6_addr *);
48static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
49
50RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare)void iface_id_head_RB_INSERT_COLOR(struct iface_id_head *head
, struct eigrp_iface *elm) { struct eigrp_iface *parent, *gparent
, *tmp; while ((parent = (elm)->id_tree.rbe_parent) &&
(parent)->id_tree.rbe_color == 1) { gparent = (parent)->
id_tree.rbe_parent; if (parent == (gparent)->id_tree.rbe_left
) { tmp = (gparent)->id_tree.rbe_right; if (tmp &&
(tmp)->id_tree.rbe_color == 1) { (tmp)->id_tree.rbe_color
= 0; do { (parent)->id_tree.rbe_color = 0; (gparent)->
id_tree.rbe_color = 1; } while (0); elm = gparent; continue; }
if ((parent)->id_tree.rbe_right == elm) { do { (tmp) = (parent
)->id_tree.rbe_right; if (((parent)->id_tree.rbe_right =
(tmp)->id_tree.rbe_left)) { ((tmp)->id_tree.rbe_left)->
id_tree.rbe_parent = (parent); } do {} while (0); if (((tmp)->
id_tree.rbe_parent = (parent)->id_tree.rbe_parent)) { if (
(parent) == ((parent)->id_tree.rbe_parent)->id_tree.rbe_left
) ((parent)->id_tree.rbe_parent)->id_tree.rbe_left = (tmp
); else ((parent)->id_tree.rbe_parent)->id_tree.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->id_tree
.rbe_left = (parent); (parent)->id_tree.rbe_parent = (tmp)
; do {} while (0); if (((tmp)->id_tree.rbe_parent)) do {} while
(0); } while (0); tmp = parent; parent = elm; elm = tmp; } do
{ (parent)->id_tree.rbe_color = 0; (gparent)->id_tree.
rbe_color = 1; } while (0); do { (tmp) = (gparent)->id_tree
.rbe_left; if (((gparent)->id_tree.rbe_left = (tmp)->id_tree
.rbe_right)) { ((tmp)->id_tree.rbe_right)->id_tree.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->id_tree.rbe_parent
= (gparent)->id_tree.rbe_parent)) { if ((gparent) == ((gparent
)->id_tree.rbe_parent)->id_tree.rbe_left) ((gparent)->
id_tree.rbe_parent)->id_tree.rbe_left = (tmp); else ((gparent
)->id_tree.rbe_parent)->id_tree.rbe_right = (tmp); } else
(head)->rbh_root = (tmp); (tmp)->id_tree.rbe_right = (
gparent); (gparent)->id_tree.rbe_parent = (tmp); do {} while
(0); if (((tmp)->id_tree.rbe_parent)) do {} while (0); } while
(0); } else { tmp = (gparent)->id_tree.rbe_left; if (tmp &&
(tmp)->id_tree.rbe_color == 1) { (tmp)->id_tree.rbe_color
= 0; do { (parent)->id_tree.rbe_color = 0; (gparent)->
id_tree.rbe_color = 1; } while (0); elm = gparent; continue; }
if ((parent)->id_tree.rbe_left == elm) { do { (tmp) = (parent
)->id_tree.rbe_left; if (((parent)->id_tree.rbe_left = (
tmp)->id_tree.rbe_right)) { ((tmp)->id_tree.rbe_right)->
id_tree.rbe_parent = (parent); } do {} while (0); if (((tmp)->
id_tree.rbe_parent = (parent)->id_tree.rbe_parent)) { if (
(parent) == ((parent)->id_tree.rbe_parent)->id_tree.rbe_left
) ((parent)->id_tree.rbe_parent)->id_tree.rbe_left = (tmp
); else ((parent)->id_tree.rbe_parent)->id_tree.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->id_tree
.rbe_right = (parent); (parent)->id_tree.rbe_parent = (tmp
); do {} while (0); if (((tmp)->id_tree.rbe_parent)) do {}
while (0); } while (0); tmp = parent; parent = elm; elm = tmp
; } do { (parent)->id_tree.rbe_color = 0; (gparent)->id_tree
.rbe_color = 1; } while (0); do { (tmp) = (gparent)->id_tree
.rbe_right; if (((gparent)->id_tree.rbe_right = (tmp)->
id_tree.rbe_left)) { ((tmp)->id_tree.rbe_left)->id_tree
.rbe_parent = (gparent); } do {} while (0); if (((tmp)->id_tree
.rbe_parent = (gparent)->id_tree.rbe_parent)) { if ((gparent
) == ((gparent)->id_tree.rbe_parent)->id_tree.rbe_left)
((gparent)->id_tree.rbe_parent)->id_tree.rbe_left = (tmp
); else ((gparent)->id_tree.rbe_parent)->id_tree.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->id_tree
.rbe_left = (gparent); (gparent)->id_tree.rbe_parent = (tmp
); do {} while (0); if (((tmp)->id_tree.rbe_parent)) do {}
while (0); } while (0); } } (head->rbh_root)->id_tree.
rbe_color = 0; } void iface_id_head_RB_REMOVE_COLOR(struct iface_id_head
*head, struct eigrp_iface *parent, struct eigrp_iface *elm) {
struct eigrp_iface *tmp; while ((elm == ((void *)0) || (elm)
->id_tree.rbe_color == 0) && elm != (head)->rbh_root
) { if ((parent)->id_tree.rbe_left == elm) { tmp = (parent
)->id_tree.rbe_right; if ((tmp)->id_tree.rbe_color == 1
) { do { (tmp)->id_tree.rbe_color = 0; (parent)->id_tree
.rbe_color = 1; } while (0); do { (tmp) = (parent)->id_tree
.rbe_right; if (((parent)->id_tree.rbe_right = (tmp)->id_tree
.rbe_left)) { ((tmp)->id_tree.rbe_left)->id_tree.rbe_parent
= (parent); } do {} while (0); if (((tmp)->id_tree.rbe_parent
= (parent)->id_tree.rbe_parent)) { if ((parent) == ((parent
)->id_tree.rbe_parent)->id_tree.rbe_left) ((parent)->
id_tree.rbe_parent)->id_tree.rbe_left = (tmp); else ((parent
)->id_tree.rbe_parent)->id_tree.rbe_right = (tmp); } else
(head)->rbh_root = (tmp); (tmp)->id_tree.rbe_left = (parent
); (parent)->id_tree.rbe_parent = (tmp); do {} while (0); if
(((tmp)->id_tree.rbe_parent)) do {} while (0); } while (0
); tmp = (parent)->id_tree.rbe_right; } if (((tmp)->id_tree
.rbe_left == ((void *)0) || ((tmp)->id_tree.rbe_left)->
id_tree.rbe_color == 0) && ((tmp)->id_tree.rbe_right
== ((void *)0) || ((tmp)->id_tree.rbe_right)->id_tree.
rbe_color == 0)) { (tmp)->id_tree.rbe_color = 1; elm = parent
; parent = (elm)->id_tree.rbe_parent; } else { if ((tmp)->
id_tree.rbe_right == ((void *)0) || ((tmp)->id_tree.rbe_right
)->id_tree.rbe_color == 0) { struct eigrp_iface *oleft; if
((oleft = (tmp)->id_tree.rbe_left)) (oleft)->id_tree.rbe_color
= 0; (tmp)->id_tree.rbe_color = 1; do { (oleft) = (tmp)->
id_tree.rbe_left; if (((tmp)->id_tree.rbe_left = (oleft)->
id_tree.rbe_right)) { ((oleft)->id_tree.rbe_right)->id_tree
.rbe_parent = (tmp); } do {} while (0); if (((oleft)->id_tree
.rbe_parent = (tmp)->id_tree.rbe_parent)) { if ((tmp) == (
(tmp)->id_tree.rbe_parent)->id_tree.rbe_left) ((tmp)->
id_tree.rbe_parent)->id_tree.rbe_left = (oleft); else ((tmp
)->id_tree.rbe_parent)->id_tree.rbe_right = (oleft); } else
(head)->rbh_root = (oleft); (oleft)->id_tree.rbe_right
= (tmp); (tmp)->id_tree.rbe_parent = (oleft); do {} while
(0); if (((oleft)->id_tree.rbe_parent)) do {} while (0); }
while (0); tmp = (parent)->id_tree.rbe_right; } (tmp)->
id_tree.rbe_color = (parent)->id_tree.rbe_color; (parent)->
id_tree.rbe_color = 0; if ((tmp)->id_tree.rbe_right) ((tmp
)->id_tree.rbe_right)->id_tree.rbe_color = 0; do { (tmp
) = (parent)->id_tree.rbe_right; if (((parent)->id_tree
.rbe_right = (tmp)->id_tree.rbe_left)) { ((tmp)->id_tree
.rbe_left)->id_tree.rbe_parent = (parent); } do {} while (
0); if (((tmp)->id_tree.rbe_parent = (parent)->id_tree.
rbe_parent)) { if ((parent) == ((parent)->id_tree.rbe_parent
)->id_tree.rbe_left) ((parent)->id_tree.rbe_parent)->
id_tree.rbe_left = (tmp); else ((parent)->id_tree.rbe_parent
)->id_tree.rbe_right = (tmp); } else (head)->rbh_root =
(tmp); (tmp)->id_tree.rbe_left = (parent); (parent)->id_tree
.rbe_parent = (tmp); do {} while (0); if (((tmp)->id_tree.
rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root
; break; } } else { tmp = (parent)->id_tree.rbe_left; if (
(tmp)->id_tree.rbe_color == 1) { do { (tmp)->id_tree.rbe_color
= 0; (parent)->id_tree.rbe_color = 1; } while (0); do { (
tmp) = (parent)->id_tree.rbe_left; if (((parent)->id_tree
.rbe_left = (tmp)->id_tree.rbe_right)) { ((tmp)->id_tree
.rbe_right)->id_tree.rbe_parent = (parent); } do {} while (
0); if (((tmp)->id_tree.rbe_parent = (parent)->id_tree.
rbe_parent)) { if ((parent) == ((parent)->id_tree.rbe_parent
)->id_tree.rbe_left) ((parent)->id_tree.rbe_parent)->
id_tree.rbe_left = (tmp); else ((parent)->id_tree.rbe_parent
)->id_tree.rbe_right = (tmp); } else (head)->rbh_root =
(tmp); (tmp)->id_tree.rbe_right = (parent); (parent)->
id_tree.rbe_parent = (tmp); do {} while (0); if (((tmp)->id_tree
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
id_tree.rbe_left; } if (((tmp)->id_tree.rbe_left == ((void
*)0) || ((tmp)->id_tree.rbe_left)->id_tree.rbe_color ==
0) && ((tmp)->id_tree.rbe_right == ((void *)0) ||
((tmp)->id_tree.rbe_right)->id_tree.rbe_color == 0)) {
(tmp)->id_tree.rbe_color = 1; elm = parent; parent = (elm
)->id_tree.rbe_parent; } else { if ((tmp)->id_tree.rbe_left
== ((void *)0) || ((tmp)->id_tree.rbe_left)->id_tree.rbe_color
== 0) { struct eigrp_iface *oright; if ((oright = (tmp)->
id_tree.rbe_right)) (oright)->id_tree.rbe_color = 0; (tmp)
->id_tree.rbe_color = 1; do { (oright) = (tmp)->id_tree
.rbe_right; if (((tmp)->id_tree.rbe_right = (oright)->id_tree
.rbe_left)) { ((oright)->id_tree.rbe_left)->id_tree.rbe_parent
= (tmp); } do {} while (0); if (((oright)->id_tree.rbe_parent
= (tmp)->id_tree.rbe_parent)) { if ((tmp) == ((tmp)->id_tree
.rbe_parent)->id_tree.rbe_left) ((tmp)->id_tree.rbe_parent
)->id_tree.rbe_left = (oright); else ((tmp)->id_tree.rbe_parent
)->id_tree.rbe_right = (oright); } else (head)->rbh_root
= (oright); (oright)->id_tree.rbe_left = (tmp); (tmp)->
id_tree.rbe_parent = (oright); do {} while (0); if (((oright)
->id_tree.rbe_parent)) do {} while (0); } while (0); tmp =
(parent)->id_tree.rbe_left; } (tmp)->id_tree.rbe_color
= (parent)->id_tree.rbe_color; (parent)->id_tree.rbe_color
= 0; if ((tmp)->id_tree.rbe_left) ((tmp)->id_tree.rbe_left
)->id_tree.rbe_color = 0; do { (tmp) = (parent)->id_tree
.rbe_left; if (((parent)->id_tree.rbe_left = (tmp)->id_tree
.rbe_right)) { ((tmp)->id_tree.rbe_right)->id_tree.rbe_parent
= (parent); } do {} while (0); if (((tmp)->id_tree.rbe_parent
= (parent)->id_tree.rbe_parent)) { if ((parent) == ((parent
)->id_tree.rbe_parent)->id_tree.rbe_left) ((parent)->
id_tree.rbe_parent)->id_tree.rbe_left = (tmp); else ((parent
)->id_tree.rbe_parent)->id_tree.rbe_right = (tmp); } else
(head)->rbh_root = (tmp); (tmp)->id_tree.rbe_right = (
parent); (parent)->id_tree.rbe_parent = (tmp); do {} while
(0); if (((tmp)->id_tree.rbe_parent)) do {} while (0); } while
(0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->
id_tree.rbe_color = 0; } struct eigrp_iface * iface_id_head_RB_REMOVE
(struct iface_id_head *head, struct eigrp_iface *elm) { struct
eigrp_iface *child, *parent, *old = elm; int color; if ((elm
)->id_tree.rbe_left == ((void *)0)) child = (elm)->id_tree
.rbe_right; else if ((elm)->id_tree.rbe_right == ((void *)
0)) child = (elm)->id_tree.rbe_left; else { struct eigrp_iface
*left; elm = (elm)->id_tree.rbe_right; while ((left = (elm
)->id_tree.rbe_left)) elm = left; child = (elm)->id_tree
.rbe_right; parent = (elm)->id_tree.rbe_parent; color = (elm
)->id_tree.rbe_color; if (child) (child)->id_tree.rbe_parent
= parent; if (parent) { if ((parent)->id_tree.rbe_left ==
elm) (parent)->id_tree.rbe_left = child; else (parent)->
id_tree.rbe_right = child; do {} while (0); } else (head)->
rbh_root = child; if ((elm)->id_tree.rbe_parent == old) parent
= elm; (elm)->id_tree = (old)->id_tree; if ((old)->
id_tree.rbe_parent) { if (((old)->id_tree.rbe_parent)->
id_tree.rbe_left == old) ((old)->id_tree.rbe_parent)->id_tree
.rbe_left = elm; else ((old)->id_tree.rbe_parent)->id_tree
.rbe_right = elm; do {} while (0); } else (head)->rbh_root
= elm; ((old)->id_tree.rbe_left)->id_tree.rbe_parent =
elm; if ((old)->id_tree.rbe_right) ((old)->id_tree.rbe_right
)->id_tree.rbe_parent = elm; if (parent) { left = parent; do
{ do {} while (0); } while ((left = (left)->id_tree.rbe_parent
)); } goto color; } parent = (elm)->id_tree.rbe_parent; color
= (elm)->id_tree.rbe_color; if (child) (child)->id_tree
.rbe_parent = parent; if (parent) { if ((parent)->id_tree.
rbe_left == elm) (parent)->id_tree.rbe_left = child; else (
parent)->id_tree.rbe_right = child; do {} while (0); } else
(head)->rbh_root = child; color: if (color == 0) iface_id_head_RB_REMOVE_COLOR
(head, parent, child); return (old); } struct eigrp_iface * iface_id_head_RB_INSERT
(struct iface_id_head *head, struct eigrp_iface *elm) { struct
eigrp_iface *tmp; struct eigrp_iface *parent = ((void *)0); int
comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp
; comp = (iface_id_compare)(elm, parent); if (comp < 0) tmp
= (tmp)->id_tree.rbe_left; else if (comp > 0) tmp = (tmp
)->id_tree.rbe_right; else return (tmp); } do { (elm)->
id_tree.rbe_parent = parent; (elm)->id_tree.rbe_left = (elm
)->id_tree.rbe_right = ((void *)0); (elm)->id_tree.rbe_color
= 1; } while (0); if (parent != ((void *)0)) { if (comp <
0) (parent)->id_tree.rbe_left = elm; else (parent)->id_tree
.rbe_right = elm; do {} while (0); } else (head)->rbh_root
= elm; iface_id_head_RB_INSERT_COLOR(head, elm); return (((void
*)0)); } struct eigrp_iface * iface_id_head_RB_FIND(struct iface_id_head
*head, struct eigrp_iface *elm) { struct eigrp_iface *tmp = (
head)->rbh_root; int comp; while (tmp) { comp = iface_id_compare
(elm, tmp); if (comp < 0) tmp = (tmp)->id_tree.rbe_left
; else if (comp > 0) tmp = (tmp)->id_tree.rbe_right; else
return (tmp); } return (((void *)0)); } struct eigrp_iface *
iface_id_head_RB_NFIND(struct iface_id_head *head, struct eigrp_iface
*elm) { struct eigrp_iface *tmp = (head)->rbh_root; struct
eigrp_iface *res = ((void *)0); int comp; while (tmp) { comp
= iface_id_compare(elm, tmp); if (comp < 0) { res = tmp; tmp
= (tmp)->id_tree.rbe_left; } else if (comp > 0) tmp = (
tmp)->id_tree.rbe_right; else return (tmp); } return (res)
; } struct eigrp_iface * iface_id_head_RB_NEXT(struct eigrp_iface
*elm) { if ((elm)->id_tree.rbe_right) { elm = (elm)->id_tree
.rbe_right; while ((elm)->id_tree.rbe_left) elm = (elm)->
id_tree.rbe_left; } else { if ((elm)->id_tree.rbe_parent &&
(elm == ((elm)->id_tree.rbe_parent)->id_tree.rbe_left)
) elm = (elm)->id_tree.rbe_parent; else { while ((elm)->
id_tree.rbe_parent && (elm == ((elm)->id_tree.rbe_parent
)->id_tree.rbe_right)) elm = (elm)->id_tree.rbe_parent;
elm = (elm)->id_tree.rbe_parent; } } return (elm); } struct
eigrp_iface * iface_id_head_RB_PREV(struct eigrp_iface *elm)
{ if ((elm)->id_tree.rbe_left) { elm = (elm)->id_tree.
rbe_left; while ((elm)->id_tree.rbe_right) elm = (elm)->
id_tree.rbe_right; } else { if ((elm)->id_tree.rbe_parent &&
(elm == ((elm)->id_tree.rbe_parent)->id_tree.rbe_right
)) elm = (elm)->id_tree.rbe_parent; else { while ((elm)->
id_tree.rbe_parent && (elm == ((elm)->id_tree.rbe_parent
)->id_tree.rbe_left)) elm = (elm)->id_tree.rbe_parent; elm
= (elm)->id_tree.rbe_parent; } } return (elm); } struct eigrp_iface
* iface_id_head_RB_MINMAX(struct iface_id_head *head, int val
) { struct eigrp_iface *tmp = (head)->rbh_root; struct eigrp_iface
*parent = ((void *)0); while (tmp) { parent = tmp; if (val <
0) tmp = (tmp)->id_tree.rbe_left; else tmp = (tmp)->id_tree
.rbe_right; } return (parent); }
51
52struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id){ ((void *)0) };
53
54static __inline int
55iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b)
56{
57 return (a->ifaceid - b->ifaceid);
58}
59
60static struct iface *
61if_new(struct eigrpd_conf *xconf, struct kif *kif)
62{
63 struct iface *iface;
64
65 if ((iface = calloc(1, sizeof(*iface))) == NULL((void *)0))
66 fatal("if_new: calloc");
67
68 TAILQ_INIT(&iface->ei_list)do { (&iface->ei_list)->tqh_first = ((void *)0); (&
iface->ei_list)->tqh_last = &(&iface->ei_list
)->tqh_first; } while (0)
;
69 TAILQ_INIT(&iface->addr_list)do { (&iface->addr_list)->tqh_first = ((void *)0); (
&iface->addr_list)->tqh_last = &(&iface->
addr_list)->tqh_first; } while (0)
;
70
71 strlcpy(iface->name, kif->ifname, sizeof(iface->name));
72
73 /* get type */
74 if (kif->flags & IFF_POINTOPOINT0x10)
75 iface->type = IF_TYPE_POINTOPOINT;
76 if (kif->flags & IFF_BROADCAST0x2 &&
77 kif->flags & IFF_MULTICAST0x8000)
78 iface->type = IF_TYPE_BROADCAST;
79 if (kif->flags & IFF_LOOPBACK0x8)
80 iface->type = IF_TYPE_POINTOPOINT;
81
82 /* get index and flags */
83 iface->mtu = kif->mtu;
84 iface->ifindex = kif->ifindex;
85 iface->rdomain = kif->rdomain;
86 iface->flags = kif->flags;
87 iface->linkstate = kif->link_state;
88 iface->if_type = kif->if_type;
89 iface->baudrate = kif->baudrate;
90
91 TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry)do { (iface)->entry.tqe_next = ((void *)0); (iface)->entry
.tqe_prev = (&xconf->iface_list)->tqh_last; *(&
xconf->iface_list)->tqh_last = (iface); (&xconf->
iface_list)->tqh_last = &(iface)->entry.tqe_next; }
while (0)
;
92
93 return (iface);
94}
95
96static void
97if_del(struct iface *iface)
98{
99 struct if_addr *if_addr;
100
101 log_debug("%s: interface %s", __func__, iface->name);
102
103 while ((if_addr = TAILQ_FIRST(&iface->addr_list)((&iface->addr_list)->tqh_first)) != NULL((void *)0)) {
104 TAILQ_REMOVE(&iface->addr_list, if_addr, entry)do { if (((if_addr)->entry.tqe_next) != ((void *)0)) (if_addr
)->entry.tqe_next->entry.tqe_prev = (if_addr)->entry
.tqe_prev; else (&iface->addr_list)->tqh_last = (if_addr
)->entry.tqe_prev; *(if_addr)->entry.tqe_prev = (if_addr
)->entry.tqe_next; ; ; } while (0)
;
105 free(if_addr);
106 }
107
108 TAILQ_REMOVE(&econf->iface_list, iface, entry)do { if (((iface)->entry.tqe_next) != ((void *)0)) (iface)
->entry.tqe_next->entry.tqe_prev = (iface)->entry.tqe_prev
; else (&econf->iface_list)->tqh_last = (iface)->
entry.tqe_prev; *(iface)->entry.tqe_prev = (iface)->entry
.tqe_next; ; ; } while (0)
;
109 free(iface);
110}
111
112struct iface *
113if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex)
114{
115 struct iface *iface;
116
117 TAILQ_FOREACH(iface, &xconf->iface_list, entry)for((iface) = ((&xconf->iface_list)->tqh_first); (iface
) != ((void *)0); (iface) = ((iface)->entry.tqe_next))
118 if (iface->ifindex == ifindex)
119 return (iface);
120
121 return (NULL((void *)0));
122}
123
124void
125if_addr_new(struct iface *iface, struct kaddr *ka)
126{
127 struct if_addr *if_addr;
128 struct eigrp_iface *ei;
129
130 if (ka->af == AF_INET624 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)(((&ka->addr.v6)->__u6_addr.__u6_addr8[0] == 0xfe) &&
(((&ka->addr.v6)->__u6_addr.__u6_addr8[1] & 0xc0
) == 0x80))
) {
131 iface->linklocal = ka->addr.v6;
132 if_update(iface, AF_INET624);
133 return;
134 }
135
136 if (if_addr_lookup(&iface->addr_list, ka) != NULL((void *)0))
137 return;
138
139 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL((void *)0))
140 fatal("if_addr_new: calloc");
141 if_addr->af = ka->af;
142 if_addr->addr = ka->addr;
143 if_addr->prefixlen = ka->prefixlen;
144 if_addr->dstbrd = ka->dstbrd;
145 TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry)do { (if_addr)->entry.tqe_next = ((void *)0); (if_addr)->
entry.tqe_prev = (&iface->addr_list)->tqh_last; *(&
iface->addr_list)->tqh_last = (if_addr); (&iface->
addr_list)->tqh_last = &(if_addr)->entry.tqe_next; }
while (0)
;
146
147 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)for((ei) = ((&iface->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->i_entry.tqe_next))
148 if (ei->state == IF_STA_ACTIVE0x02 && ei->eigrp->af == if_addr->af)
149 eigrpe_orig_local_route(ei, if_addr, 0);
150
151 if (if_addr->af == AF_INET2)
152 if_update(iface, AF_INET2);
153}
154
155void
156if_addr_del(struct iface *iface, struct kaddr *ka)
157{
158 struct if_addr *if_addr;
159 struct eigrp_iface *ei;
160 int af = ka->af;
161
162 if (ka->af == AF_INET624 &&
1
Assuming field 'af' is not equal to AF_INET6
163 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)(memcmp(&(&iface->linklocal)->__u6_addr.__u6_addr8
[0], &(&ka->addr.v6)->__u6_addr.__u6_addr8[0], sizeof
(struct in6_addr)) == 0)
) {
164 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
165 if_update(iface, AF_INET624);
166 return;
167 }
168
169 if_addr = if_addr_lookup(&iface->addr_list, ka);
2
Calling 'if_addr_lookup'
9
Returning from 'if_addr_lookup'
170 if (if_addr
9.1
'if_addr' is not equal to NULL
== NULL((void *)0))
10
Taking false branch
171 return;
172
173 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)for((ei) = ((&iface->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->i_entry.tqe_next))
11
Assuming 'ei' is equal to null
12
Loop condition is false. Execution continues on line 177
174 if (ei->state == IF_STA_ACTIVE0x02 && ei->eigrp->af == if_addr->af)
175 eigrpe_orig_local_route(ei, if_addr, 1);
176
177 TAILQ_REMOVE(&iface->addr_list, if_addr, entry)do { if (((if_addr)->entry.tqe_next) != ((void *)0)) (if_addr
)->entry.tqe_next->entry.tqe_prev = (if_addr)->entry
.tqe_prev; else (&iface->addr_list)->tqh_last = (if_addr
)->entry.tqe_prev; *(if_addr)->entry.tqe_prev = (if_addr
)->entry.tqe_next; ; ; } while (0)
;
13
Assuming field 'tqe_next' is equal to null
14
Taking false branch
15
Loop condition is false. Exiting loop
178 free(if_addr);
16
Memory is released
179
180 if (af == AF_INET2)
17
Assuming 'af' is equal to AF_INET
18
Taking true branch
181 if_update(iface, AF_INET2);
19
Calling 'if_update'
182}
183
184static struct if_addr *
185if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
186{
187 struct if_addr *if_addr;
188 int af = ka->af;
189
190 TAILQ_FOREACH(if_addr, addr_list, entry)for((if_addr) = ((addr_list)->tqh_first); (if_addr) != ((void
*)0); (if_addr) = ((if_addr)->entry.tqe_next))
3
Assuming 'if_addr' is not equal to null
4
Loop condition is true. Entering loop body
191 if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) &&
5
Assuming the condition is true
8
Taking true branch
192 if_addr->prefixlen == ka->prefixlen &&
6
Assuming 'if_addr->prefixlen' is equal to 'ka->prefixlen'
193 !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
7
Assuming the condition is true
194 return (if_addr);
195
196 return (NULL((void *)0));
197}
198
199in_addr_t
200if_primary_addr(struct iface *iface)
201{
202 struct if_addr *if_addr;
203
204 TAILQ_FOREACH(if_addr, &iface->addr_list, entry)for((if_addr) = ((&iface->addr_list)->tqh_first); (
if_addr) != ((void *)0); (if_addr) = ((if_addr)->entry.tqe_next
))
205 if (if_addr->af == AF_INET2)
206 return (if_addr->addr.v4.s_addr);
207
208 return (INADDR_ANY((u_int32_t)(0x00000000)));
209}
210
211uint8_t
212if_primary_addr_prefixlen(struct iface *iface)
213{
214 struct if_addr *if_addr;
215
216 TAILQ_FOREACH(if_addr, &iface->addr_list, entry)for((if_addr) = ((&iface->addr_list)->tqh_first); (
if_addr) != ((void *)0); (if_addr) = ((if_addr)->entry.tqe_next
))
217 if (if_addr->af == AF_INET2)
218 return (if_addr->prefixlen);
219
220 return (0);
221}
222
223/* up/down events */
224void
225if_update(struct iface *iface, int af)
226{
227 struct eigrp_iface *ei;
228 int link_ok;
229 int addr_ok, addr4_ok = 0, addr6_ok = 0;
230 struct if_addr *if_addr;
231
232 link_ok = (iface->flags & IFF_UP0x1) &&
20
Assuming the condition is false
233 LINK_STATE_IS_UP(iface->linkstate)((iface->linkstate) >= 4 || (iface->linkstate) == 0);
234
235 /*
236 * NOTE: for EIGRPv4, each interface should have at least one valid
237 * IP address otherwise they can not be enabled in the routing domain.
238 */
239 TAILQ_FOREACH(if_addr, &iface->addr_list, entry)for((if_addr) = ((&iface->addr_list)->tqh_first); (
if_addr) != ((void *)0); (if_addr) = ((if_addr)->entry.tqe_next
))
{
21
Loop condition is true. Entering loop body
240 if (if_addr->af == AF_INET2) {
22
Use of memory after it is freed
241 addr4_ok = 1;
242 break;
243 }
244 }
245 /* for IPv6 the link-local address is enough. */
246 if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal)(((&iface->linklocal)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&iface->linklocal)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
)
247 addr6_ok = 1;
248
249 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)for((ei) = ((&iface->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->i_entry.tqe_next))
{
250 if (af != AF_UNSPEC0 && ei->eigrp->af != af)
251 continue;
252
253 switch (ei->eigrp->af) {
254 case AF_INET2:
255 addr_ok = addr4_ok;
256 break;
257 case AF_INET624:
258 addr_ok = addr6_ok;
259 break;
260 default:
261 fatalx("if_update: unknown af");
262 }
263
264 if (ei->state == IF_STA_DOWN0x01) {
265 if (!link_ok || !addr_ok)
266 continue;
267 ei->state = IF_STA_ACTIVE0x02;
268 eigrp_if_start(ei);
269 } else if (ei->state == IF_STA_ACTIVE0x02) {
270 if (link_ok && addr_ok)
271 continue;
272 ei->state = IF_STA_DOWN0x01;
273 eigrp_if_reset(ei);
274 }
275 }
276}
277
278struct eigrp_iface *
279eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif)
280{
281 struct iface *iface;
282 struct eigrp_iface *ei;
283 static uint32_t ifacecnt = 1;
284
285 iface = if_lookup(xconf, kif->ifindex);
286 if (iface == NULL((void *)0))
287 iface = if_new(xconf, kif);
288
289 if ((ei = calloc(1, sizeof(*ei))) == NULL((void *)0))
290 fatal("eigrp_if_new: calloc");
291
292 ei->state = IF_STA_DOWN0x01;
293 /* get next unused ifaceid */
294 while (eigrp_if_lookup_id(ifacecnt++))
295 ;
296 ei->ifaceid = ifacecnt;
297 ei->eigrp = eigrp;
298 ei->iface = iface;
299 if (ei->iface->flags & IFF_LOOPBACK0x8)
300 ei->passive = 1;
301
302 TAILQ_INIT(&ei->nbr_list)do { (&ei->nbr_list)->tqh_first = ((void *)0); (&
ei->nbr_list)->tqh_last = &(&ei->nbr_list)->
tqh_first; } while (0)
;
303 TAILQ_INIT(&ei->update_list)do { (&ei->update_list)->tqh_first = ((void *)0); (
&ei->update_list)->tqh_last = &(&ei->update_list
)->tqh_first; } while (0)
;
304 TAILQ_INIT(&ei->query_list)do { (&ei->query_list)->tqh_first = ((void *)0); (&
ei->query_list)->tqh_last = &(&ei->query_list
)->tqh_first; } while (0)
;
305 TAILQ_INIT(&ei->summary_list)do { (&ei->summary_list)->tqh_first = ((void *)0); (
&ei->summary_list)->tqh_last = &(&ei->summary_list
)->tqh_first; } while (0)
;
306 TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry)do { (ei)->i_entry.tqe_next = ((void *)0); (ei)->i_entry
.tqe_prev = (&iface->ei_list)->tqh_last; *(&iface
->ei_list)->tqh_last = (ei); (&iface->ei_list)->
tqh_last = &(ei)->i_entry.tqe_next; } while (0)
;
307 TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry)do { (ei)->e_entry.tqe_next = ((void *)0); (ei)->e_entry
.tqe_prev = (&eigrp->ei_list)->tqh_last; *(&eigrp
->ei_list)->tqh_last = (ei); (&eigrp->ei_list)->
tqh_last = &(ei)->e_entry.tqe_next; } while (0)
;
308 if (RB_INSERT(iface_id_head, &ifaces_by_id, ei)iface_id_head_RB_INSERT(&ifaces_by_id, ei) != NULL((void *)0))
309 fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed");
310
311 return (ei);
312}
313
314void
315eigrp_if_del(struct eigrp_iface *ei)
316{
317 struct summary_addr *summary;
318
319 RB_REMOVE(iface_id_head, &ifaces_by_id, ei)iface_id_head_RB_REMOVE(&ifaces_by_id, ei);
320 TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry)do { if (((ei)->e_entry.tqe_next) != ((void *)0)) (ei)->
e_entry.tqe_next->e_entry.tqe_prev = (ei)->e_entry.tqe_prev
; else (&ei->eigrp->ei_list)->tqh_last = (ei)->
e_entry.tqe_prev; *(ei)->e_entry.tqe_prev = (ei)->e_entry
.tqe_next; ; ; } while (0)
;
321 TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry)do { if (((ei)->i_entry.tqe_next) != ((void *)0)) (ei)->
i_entry.tqe_next->i_entry.tqe_prev = (ei)->i_entry.tqe_prev
; else (&ei->iface->ei_list)->tqh_last = (ei)->
i_entry.tqe_prev; *(ei)->i_entry.tqe_prev = (ei)->i_entry
.tqe_next; ; ; } while (0)
;
322 while ((summary = TAILQ_FIRST(&ei->summary_list)((&ei->summary_list)->tqh_first)) != NULL((void *)0)) {
323 TAILQ_REMOVE(&ei->summary_list, summary, entry)do { if (((summary)->entry.tqe_next) != ((void *)0)) (summary
)->entry.tqe_next->entry.tqe_prev = (summary)->entry
.tqe_prev; else (&ei->summary_list)->tqh_last = (summary
)->entry.tqe_prev; *(summary)->entry.tqe_prev = (summary
)->entry.tqe_next; ; ; } while (0)
;
324 free(summary);
325 }
326 message_list_clr(&ei->query_list);
327 message_list_clr(&ei->update_list);
328
329 if (ei->state == IF_STA_ACTIVE0x02)
330 eigrp_if_reset(ei);
331
332 if (TAILQ_EMPTY(&ei->iface->ei_list)(((&ei->iface->ei_list)->tqh_first) == ((void *)
0))
)
333 if_del(ei->iface);
334
335 free(ei);
336}
337
338struct eigrp_iface *
339eigrp_if_lookup(struct iface *iface, int af, uint16_t as)
340{
341 struct eigrp_iface *ei;
342
343 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)for((ei) = ((&iface->ei_list)->tqh_first); (ei) != (
(void *)0); (ei) = ((ei)->i_entry.tqe_next))
344 if (ei->eigrp->af == af &&
345 ei->eigrp->as == as)
346 return (ei);
347
348 return (NULL((void *)0));
349}
350
351struct eigrp_iface *
352eigrp_if_lookup_id(uint32_t ifaceid)
353{
354 struct eigrp_iface e;
355 e.ifaceid = ifaceid;
356 return (RB_FIND(iface_id_head, &ifaces_by_id, &e)iface_id_head_RB_FIND(&ifaces_by_id, &e));
357}
358
359static void
360eigrp_if_start(struct eigrp_iface *ei)
361{
362 struct eigrp *eigrp = ei->eigrp;
363 struct timeval now;
364 struct if_addr *if_addr;
365 union eigrpd_addr addr;
366
367 log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
368 eigrp->as, af_name(eigrp->af));
369
370 gettimeofday(&now, NULL((void *)0));
371 ei->uptime = now.tv_sec;
372
373 /* init the dummy self neighbor */
374 memset(&addr, 0, sizeof(addr));
375 ei->self = nbr_new(ei, &addr, 0, 1);
376 nbr_init(ei->self);
377
378 TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry)for((if_addr) = ((&ei->iface->addr_list)->tqh_first
); (if_addr) != ((void *)0); (if_addr) = ((if_addr)->entry
.tqe_next))
{
379 if (if_addr->af != eigrp->af)
380 continue;
381
382 eigrpe_orig_local_route(ei, if_addr, 0);
383 }
384
385 if (ei->passive)
386 return;
387
388 switch (eigrp->af) {
389 case AF_INET2:
390 if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4))
391 return;
392 break;
393 case AF_INET624:
394 if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6))
395 return;
396 break;
397 default:
398 fatalx("eigrp_if_start: unknown af");
399 }
400
401 evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei)event_set(&ei->hello_timer, -1, 0, eigrp_if_hello_timer
, ei)
;
402 eigrp_if_start_hello_timer(ei);
403}
404
405static void
406eigrp_if_reset(struct eigrp_iface *ei)
407{
408 struct eigrp *eigrp = ei->eigrp;
409 struct nbr *nbr;
410
411 log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
412 eigrp->as, af_name(eigrp->af));
413
414 /* the rde will withdraw the connected route for us */
415
416 while ((nbr = TAILQ_FIRST(&ei->nbr_list)((&ei->nbr_list)->tqh_first)) != NULL((void *)0))
417 nbr_del(nbr);
418
419 if (ei->passive)
420 return;
421
422 /* try to cleanup */
423 switch (eigrp->af) {
424 case AF_INET2:
425 if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4);
426 break;
427 case AF_INET624:
428 if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6);
429 break;
430 default:
431 fatalx("eigrp_if_reset: unknown af");
432 }
433
434 eigrp_if_stop_hello_timer(ei);
435}
436
437/* timers */
438/* ARGSUSED */
439static void
440eigrp_if_hello_timer(int fd, short event, void *arg)
441{
442 struct eigrp_iface *ei = arg;
443 struct timeval tv;
444
445 send_hello(ei, NULL((void *)0), 0);
446
447 /* reschedule hello_timer */
448 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
449 tv.tv_sec = ei->hello_interval;
450 if (evtimer_add(&ei->hello_timer, &tv)event_add(&ei->hello_timer, &tv) == -1)
451 fatal("eigrp_if_hello_timer");
452}
453
454static void
455eigrp_if_start_hello_timer(struct eigrp_iface *ei)
456{
457 struct timeval tv;
458
459 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
460 tv.tv_sec = ei->hello_interval;
461 if (evtimer_add(&ei->hello_timer, &tv)event_add(&ei->hello_timer, &tv) == -1)
462 fatal("eigrp_if_start_hello_timer");
463}
464
465static void
466eigrp_if_stop_hello_timer(struct eigrp_iface *ei)
467{
468 if (evtimer_pending(&ei->hello_timer, NULL)event_pending(&ei->hello_timer, 0x01, ((void *)0)) &&
469 evtimer_del(&ei->hello_timer)event_del(&ei->hello_timer) == -1)
470 fatal("eigrp_if_stop_hello_timer");
471}
472
473struct ctl_iface *
474if_to_ctl(struct eigrp_iface *ei)
475{
476 static struct ctl_iface ictl;
477 struct timeval now;
478 struct nbr *nbr;
479
480 ictl.af = ei->eigrp->af;
481 ictl.as = ei->eigrp->as;
482 memcpy(ictl.name, ei->iface->name, sizeof(ictl.name));
483 ictl.ifindex = ei->iface->ifindex;
484 switch (ei->eigrp->af) {
485 case AF_INET2:
486 ictl.addr.v4.s_addr = if_primary_addr(ei->iface);
487 ictl.prefixlen = if_primary_addr_prefixlen(ei->iface);
488 break;
489 case AF_INET624:
490 ictl.addr.v6 = ei->iface->linklocal;
491 if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal)((*(const u_int32_t *)(const void *)(&(&ei->iface->
linklocal)->__u6_addr.__u6_addr8[0]) == 0) && (*(const
u_int32_t *)(const void *)(&(&ei->iface->linklocal
)->__u6_addr.__u6_addr8[4]) == 0) && (*(const u_int32_t
*)(const void *)(&(&ei->iface->linklocal)->
__u6_addr.__u6_addr8[8]) == 0) && (*(const u_int32_t *
)(const void *)(&(&ei->iface->linklocal)->__u6_addr
.__u6_addr8[12]) == 0))
)
492 ictl.prefixlen = 64;
493 else
494 ictl.prefixlen = 0;
495 break;
496 default:
497 fatalx("if_to_ctl: unknown af");
498 }
499 ictl.flags = ei->iface->flags;
500 ictl.linkstate = ei->iface->linkstate;
501 ictl.mtu = ei->iface->mtu;
502 ictl.type = ei->iface->type;
503 ictl.if_type = ei->iface->if_type;
504 ictl.baudrate = ei->iface->baudrate;
505 ictl.delay = ei->delay;
506 ictl.bandwidth = ei->bandwidth;
507 ictl.hello_holdtime = ei->hello_holdtime;
508 ictl.hello_interval = ei->hello_interval;
509 ictl.splithorizon = ei->splithorizon;
510 ictl.passive = ei->passive;
511 ictl.nbr_cnt = 0;
512
513 gettimeofday(&now, NULL((void *)0));
514 if (ei->state != IF_STA_DOWN0x01 && ei->uptime != 0)
515 ictl.uptime = now.tv_sec - ei->uptime;
516 else
517 ictl.uptime = 0;
518
519 TAILQ_FOREACH(nbr, &ei->nbr_list, entry)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != (
(void *)0); (nbr) = ((nbr)->entry.tqe_next))
520 if (!(nbr->flags & (F_EIGRP_NBR_PENDING0x02|F_EIGRP_NBR_SELF0x01)))
521 ictl.nbr_cnt++;
522
523 return (&ictl);
524}
525
526/* misc */
527void
528if_set_sockbuf(int fd)
529{
530 int bsize;
531
532 bsize = 65535;
533 while (setsockopt(fd, SOL_SOCKET0xffff, SO_RCVBUF0x1002, &bsize,
534 sizeof(bsize)) == -1)
535 bsize /= 2;
536
537 if (bsize != 65535)
538 log_warnx("%s: recvbuf size only %d", __func__, bsize);
539
540 bsize = 65535;
541 while (setsockopt(fd, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &bsize,
542 sizeof(bsize)) == -1)
543 bsize /= 2;
544
545 if (bsize != 65535)
546 log_warnx("%s: sendbuf size only %d", __func__, bsize);
547}
548
549static int
550if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
551{
552 struct ip_mreq mreq;
553
554 if (iface->group_count_v4++ != 0)
555 /* already joined */
556 return (0);
557
558 log_debug("%s: interface %s addr %s", __func__, iface->name,
559 inet_ntoa(*addr));
560
561 mreq.imr_multiaddr = *addr;
562 mreq.imr_interface.s_addr = if_primary_addr(iface);
563
564 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP0, IP_ADD_MEMBERSHIP12,
565 (void *)&mreq, sizeof(mreq)) == -1) {
566 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
567 __func__, iface->name, inet_ntoa(*addr));
568 return (-1);
569 }
570
571 return (0);
572}
573
574static int
575if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
576{
577 struct ip_mreq mreq;
578
579 if (--iface->group_count_v4 != 0)
580 /* others still joined */
581 return (0);
582
583 log_debug("%s: interface %s addr %s", __func__, iface->name,
584 inet_ntoa(*addr));
585
586 mreq.imr_multiaddr = *addr;
587 mreq.imr_interface.s_addr = if_primary_addr(iface);
588
589 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP0, IP_DROP_MEMBERSHIP13,
590 (void *)&mreq, sizeof(mreq)) == -1) {
591 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
592 "address %s", iface->name, __func__, inet_ntoa(*addr));
593 return (-1);
594 }
595
596 return (0);
597}
598
599int
600if_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
601{
602 if (setsockopt(fd, IPPROTO_IP0, IP_MULTICAST_TTL10,
603 (char *)&ttl, sizeof(ttl)) == -1) {
604 log_warn("%s: error setting IP_MULTICAST_TTL to %d",
605 __func__, ttl);
606 return (-1);
607 }
608
609 return (0);
610}
611
612int
613if_set_ipv4_mcast(struct iface *iface)
614{
615 in_addr_t addr;
616
617 addr = if_primary_addr(iface);
618
619 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP0, IP_MULTICAST_IF9,
620 &addr, sizeof(addr)) == -1) {
621 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
622 __func__, iface->name);
623 return (-1);
624 }
625
626 return (0);
627}
628
629int
630if_set_ipv4_mcast_loop(int fd)
631{
632 uint8_t loop = 0;
633
634 if (setsockopt(fd, IPPROTO_IP0, IP_MULTICAST_LOOP11,
635 (char *)&loop, sizeof(loop)) == -1) {
636 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
637 return (-1);
638 }
639
640 return (0);
641}
642
643int
644if_set_ipv4_recvif(int fd, int enable)
645{
646 if (setsockopt(fd, IPPROTO_IP0, IP_RECVIF30, &enable,
647 sizeof(enable)) == -1) {
648 log_warn("%s: error setting IP_RECVIF", __func__);
649 return (-1);
650 }
651 return (0);
652}
653
654int
655if_set_ipv4_hdrincl(int fd)
656{
657 int hincl = 1;
658
659 if (setsockopt(fd, IPPROTO_IP0, IP_HDRINCL2, &hincl, sizeof(hincl)) == -1) {
660 log_warn("%s: error setting IP_HDRINCL", __func__);
661 return (-1);
662 }
663
664 return (0);
665}
666
667static int
668if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
669{
670 struct ipv6_mreq mreq;
671
672 if (iface->group_count_v6++ != 0)
673 /* already joined */
674 return (0);
675
676 log_debug("%s: interface %s addr %s", __func__, iface->name,
677 log_in6addr(addr));
678
679 mreq.ipv6mr_multiaddr = *addr;
680 mreq.ipv6mr_interface = iface->ifindex;
681
682 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV641, IPV6_JOIN_GROUP12,
683 &mreq, sizeof(mreq)) == -1) {
684 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
685 __func__, iface->name, log_in6addr(addr));
686 return (-1);
687 }
688
689 return (0);
690}
691
692static int
693if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
694{
695 struct ipv6_mreq mreq;
696
697 if (--iface->group_count_v6 != 0)
698 /* others still joined */
699 return (0);
700
701 log_debug("%s: interface %s addr %s", __func__, iface->name,
702 log_in6addr(addr));
703
704 mreq.ipv6mr_multiaddr = *addr;
705 mreq.ipv6mr_interface = iface->ifindex;
706
707 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV641, IPV6_LEAVE_GROUP13,
708 (void *)&mreq, sizeof(mreq)) == -1) {
709 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
710 __func__, iface->name, log_in6addr(addr));
711 return (-1);
712 }
713
714 return (0);
715}
716
717int
718if_set_ipv6_mcast(struct iface *iface)
719{
720 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV641, IPV6_MULTICAST_IF9,
721 &iface->ifindex, sizeof(iface->ifindex)) == -1) {
722 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
723 __func__, iface->name);
724 return (-1);
725 }
726
727 return (0);
728}
729
730int
731if_set_ipv6_mcast_loop(int fd)
732{
733 unsigned int loop = 0;
734
735 if (setsockopt(fd, IPPROTO_IPV641, IPV6_MULTICAST_LOOP11,
736 (unsigned int *)&loop, sizeof(loop)) == -1) {
737 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
738 return (-1);
739 }
740
741 return (0);
742}
743
744int
745if_set_ipv6_pktinfo(int fd, int enable)
746{
747 if (setsockopt(fd, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &enable,
748 sizeof(enable)) == -1) {
749 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
750 return (-1);
751 }
752
753 return (0);
754}
755
756int
757if_set_ipv6_dscp(int fd, int dscp)
758{
759 if (setsockopt(fd, IPPROTO_IPV641, IPV6_TCLASS61, &dscp,
760 sizeof(dscp)) == -1) {
761 log_warn("%s: error setting IPV6_TCLASS", __func__);
762 return (-1);
763 }
764
765 return (0);
766}