xref: /openbsd-src/usr.sbin/ldpd/interface.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: interface.c,v 1.52 2023/03/08 04:43:13 guenther Exp $ */
2ab0c2486Smichele 
3ab0c2486Smichele /*
45dc9330aSrenato  * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5ab0c2486Smichele  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6ab0c2486Smichele  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7ab0c2486Smichele  *
8ab0c2486Smichele  * Permission to use, copy, modify, and distribute this software for any
9ab0c2486Smichele  * purpose with or without fee is hereby granted, provided that the above
10ab0c2486Smichele  * copyright notice and this permission notice appear in all copies.
11ab0c2486Smichele  *
12ab0c2486Smichele  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13ab0c2486Smichele  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14ab0c2486Smichele  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15ab0c2486Smichele  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16ab0c2486Smichele  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17ab0c2486Smichele  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18ab0c2486Smichele  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19ab0c2486Smichele  */
20ab0c2486Smichele 
21ab0c2486Smichele #include <sys/types.h>
22ab0c2486Smichele #include <sys/time.h>
23ab0c2486Smichele #include <arpa/inet.h>
24ab0c2486Smichele #include <stdlib.h>
25ab0c2486Smichele #include <string.h>
26ab0c2486Smichele 
27ab0c2486Smichele #include "ldpd.h"
28ab0c2486Smichele #include "ldpe.h"
295411bbb6Srenato #include "log.h"
30ab0c2486Smichele 
31c28a25a1Srenato static struct if_addr	*if_addr_new(struct kaddr *);
32c28a25a1Srenato static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
33c28a25a1Srenato static int		 if_start(struct iface *, int);
34c28a25a1Srenato static int		 if_reset(struct iface *, int);
35c28a25a1Srenato static void		 if_update_af(struct iface_af *, int);
36c28a25a1Srenato static void		 if_hello_timer(int, short, void *);
37c28a25a1Srenato static void		 if_start_hello_timer(struct iface_af *);
38c28a25a1Srenato static void		 if_stop_hello_timer(struct iface_af *);
39c28a25a1Srenato static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
40c28a25a1Srenato static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
41c28a25a1Srenato static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
42c28a25a1Srenato static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
43ab0c2486Smichele 
44ab0c2486Smichele struct iface *
if_new(struct kif * kif)45814e607dSclaudio if_new(struct kif *kif)
46ab0c2486Smichele {
47ab0c2486Smichele 	struct iface		*iface;
48ab0c2486Smichele 
49ab0c2486Smichele 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
50d99a8fc3Srenato 		fatal("if_new: calloc");
51ab0c2486Smichele 
52ab0c2486Smichele 	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
53ab0c2486Smichele 
54ab0c2486Smichele 	/* get type */
55ab0c2486Smichele 	if (kif->flags & IFF_POINTOPOINT)
56ab0c2486Smichele 		iface->type = IF_TYPE_POINTOPOINT;
57ab0c2486Smichele 	if (kif->flags & IFF_BROADCAST &&
58ab0c2486Smichele 	    kif->flags & IFF_MULTICAST)
59ab0c2486Smichele 		iface->type = IF_TYPE_BROADCAST;
60ab0c2486Smichele 
612a261b04Sclaudio 	/* get index and flags */
62a8c39dc0Srenato 	LIST_INIT(&iface->addr_list);
63ab0c2486Smichele 	iface->ifindex = kif->ifindex;
648622bd53Srenato 	iface->rdomain = kif->rdomain;
65ab0c2486Smichele 	iface->flags = kif->flags;
66ab0c2486Smichele 	iface->linkstate = kif->link_state;
670f882be7Sstsp 	iface->if_type = kif->if_type;
68ab0c2486Smichele 
69a8c39dc0Srenato 	/* ipv4 */
70a8c39dc0Srenato 	iface->ipv4.af = AF_INET;
71a8c39dc0Srenato 	iface->ipv4.iface = iface;
72a8c39dc0Srenato 	iface->ipv4.enabled = 0;
73a8c39dc0Srenato 	iface->ipv4.state = IF_STA_DOWN;
74a8c39dc0Srenato 	LIST_INIT(&iface->ipv4.adj_list);
75a8c39dc0Srenato 
76a8c39dc0Srenato 	/* ipv6 */
77a8c39dc0Srenato 	iface->ipv6.af = AF_INET6;
78a8c39dc0Srenato 	iface->ipv6.iface = iface;
79a8c39dc0Srenato 	iface->ipv6.enabled = 0;
80a8c39dc0Srenato 	iface->ipv6.state = IF_STA_DOWN;
81a8c39dc0Srenato 	LIST_INIT(&iface->ipv6.adj_list);
82a8c39dc0Srenato 
83ab0c2486Smichele 	return (iface);
84ab0c2486Smichele }
85ab0c2486Smichele 
86ab0c2486Smichele void
if_exit(struct iface * iface)87d3e006a4Srenato if_exit(struct iface *iface)
88ab0c2486Smichele {
89814e607dSclaudio 	struct if_addr		*if_addr;
90814e607dSclaudio 
91b7b4db73Srenato 	log_debug("%s: interface %s", __func__, iface->name);
92ab0c2486Smichele 
93a8c39dc0Srenato 	if (iface->ipv4.state == IF_STA_ACTIVE)
94a8c39dc0Srenato 		if_reset(iface, AF_INET);
95a8c39dc0Srenato 	if (iface->ipv6.state == IF_STA_ACTIVE)
96a8c39dc0Srenato 		if_reset(iface, AF_INET6);
97a8c39dc0Srenato 
98b9b5a6c8Srenato 	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
99b9b5a6c8Srenato 		LIST_REMOVE(if_addr, entry);
100b9b5a6c8Srenato 		free(if_addr);
101b9b5a6c8Srenato 	}
102814e607dSclaudio }
103814e607dSclaudio 
10402a212eeSrenato struct iface *
if_lookup(struct ldpd_conf * xconf,unsigned short ifindex)10502a212eeSrenato if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
10602a212eeSrenato {
10702a212eeSrenato 	struct iface *iface;
10802a212eeSrenato 
10902a212eeSrenato 	LIST_FOREACH(iface, &xconf->iface_list, entry)
11002a212eeSrenato 		if (iface->ifindex == ifindex)
11102a212eeSrenato 			return (iface);
11202a212eeSrenato 
11302a212eeSrenato 	return (NULL);
11402a212eeSrenato }
11502a212eeSrenato 
116a8c39dc0Srenato struct iface_af *
iface_af_get(struct iface * iface,int af)117a8c39dc0Srenato iface_af_get(struct iface *iface, int af)
118a8c39dc0Srenato {
119a8c39dc0Srenato 	switch (af) {
120a8c39dc0Srenato 	case AF_INET:
121a8c39dc0Srenato 		return (&iface->ipv4);
122a8c39dc0Srenato 	case AF_INET6:
123a8c39dc0Srenato 		return (&iface->ipv6);
124a8c39dc0Srenato 	default:
125a8c39dc0Srenato 		fatalx("iface_af_get: unknown af");
126a8c39dc0Srenato 	}
127a8c39dc0Srenato }
128a8c39dc0Srenato 
129c28a25a1Srenato static struct if_addr *
if_addr_new(struct kaddr * ka)1302d825b92Srenato if_addr_new(struct kaddr *ka)
131b9b5a6c8Srenato {
132b9b5a6c8Srenato 	struct if_addr	*if_addr;
133b9b5a6c8Srenato 
134b9b5a6c8Srenato 	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
135b7b4db73Srenato 		fatal(__func__);
136b9b5a6c8Srenato 
137a8c39dc0Srenato 	if_addr->af = ka->af;
1387aa09c5dSrenato 	if_addr->addr = ka->addr;
139a8c39dc0Srenato 	if_addr->prefixlen = ka->prefixlen;
1407aa09c5dSrenato 	if_addr->dstbrd = ka->dstbrd;
141b9b5a6c8Srenato 
142b9b5a6c8Srenato 	return (if_addr);
143b9b5a6c8Srenato }
144b9b5a6c8Srenato 
145c28a25a1Srenato static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)1462d825b92Srenato if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
147b9b5a6c8Srenato {
148b9b5a6c8Srenato 	struct if_addr	*if_addr;
149a8c39dc0Srenato 	int		 af = ka->af;
150b9b5a6c8Srenato 
151b9b5a6c8Srenato 	LIST_FOREACH(if_addr, addr_list, entry)
152a8c39dc0Srenato 		if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
153a8c39dc0Srenato 		    if_addr->prefixlen == ka->prefixlen &&
154a8c39dc0Srenato 		    !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
155b9b5a6c8Srenato 			return (if_addr);
156b9b5a6c8Srenato 
157b9b5a6c8Srenato 	return (NULL);
158b9b5a6c8Srenato }
159b9b5a6c8Srenato 
160ab0c2486Smichele void
if_addr_add(struct kaddr * ka)16133f6ccfeSrenato if_addr_add(struct kaddr *ka)
162ab0c2486Smichele {
16333f6ccfeSrenato 	struct iface		*iface;
16433f6ccfeSrenato 	struct if_addr		*if_addr;
16533f6ccfeSrenato 	struct nbr		*nbr;
166ab0c2486Smichele 
16733f6ccfeSrenato 	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
16833f6ccfeSrenato 		if_addr = if_addr_new(ka);
169ab0c2486Smichele 
17033f6ccfeSrenato 		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
17133f6ccfeSrenato 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
17233f6ccfeSrenato 			if (nbr->state != NBR_STA_OPER)
17333f6ccfeSrenato 				continue;
174a8c39dc0Srenato 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
175a8c39dc0Srenato 				continue;
176a8c39dc0Srenato 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
177a8c39dc0Srenato 				continue;
17833f6ccfeSrenato 
179397583bcSrenato 			send_address_single(nbr, if_addr, 0);
18033f6ccfeSrenato 		}
18133f6ccfeSrenato 	}
18233f6ccfeSrenato 
18333f6ccfeSrenato 	iface = if_lookup(leconf, ka->ifindex);
184a8c39dc0Srenato 	if (iface) {
185a8c39dc0Srenato 		if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
186a8c39dc0Srenato 			iface->linklocal = ka->addr.v6;
187a8c39dc0Srenato 
188a8c39dc0Srenato 		if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
18933f6ccfeSrenato 			if_addr = if_addr_new(ka);
19033f6ccfeSrenato 			LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
191a8c39dc0Srenato 			if_update(iface, if_addr->af);
192a8c39dc0Srenato 		}
19333f6ccfeSrenato 	}
194ab0c2486Smichele }
195ab0c2486Smichele 
196ab0c2486Smichele void
if_addr_del(struct kaddr * ka)19733f6ccfeSrenato if_addr_del(struct kaddr *ka)
198ab0c2486Smichele {
19933f6ccfeSrenato 	struct iface		*iface;
20033f6ccfeSrenato 	struct if_addr		*if_addr;
20133f6ccfeSrenato 	struct nbr		*nbr;
202ab0c2486Smichele 
20333f6ccfeSrenato 	iface = if_lookup(leconf, ka->ifindex);
20433f6ccfeSrenato 	if (iface) {
205a8c39dc0Srenato 		if (ka->af == AF_INET6 &&
206a8c39dc0Srenato 		    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
207a8c39dc0Srenato 			memset(&iface->linklocal, 0, sizeof(iface->linklocal));
208a8c39dc0Srenato 
20933f6ccfeSrenato 		if_addr = if_addr_lookup(&iface->addr_list, ka);
21033f6ccfeSrenato 		if (if_addr) {
21133f6ccfeSrenato 			LIST_REMOVE(if_addr, entry);
212a8c39dc0Srenato 			if_update(iface, if_addr->af);
21333f6ccfeSrenato 			free(if_addr);
21433f6ccfeSrenato 		}
215ab0c2486Smichele 	}
216ab0c2486Smichele 
21733f6ccfeSrenato 	if_addr = if_addr_lookup(&global.addr_list, ka);
21833f6ccfeSrenato 	if (if_addr) {
21933f6ccfeSrenato 		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
22033f6ccfeSrenato 			if (nbr->state != NBR_STA_OPER)
22133f6ccfeSrenato 				continue;
222a8c39dc0Srenato 			if (if_addr->af == AF_INET && !nbr->v4_enabled)
223a8c39dc0Srenato 				continue;
224a8c39dc0Srenato 			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
225a8c39dc0Srenato 				continue;
226397583bcSrenato 			send_address_single(nbr, if_addr, 1);
22733f6ccfeSrenato 		}
22833f6ccfeSrenato 		LIST_REMOVE(if_addr, entry);
22933f6ccfeSrenato 		free(if_addr);
23033f6ccfeSrenato 	}
231ab0c2486Smichele }
232ab0c2486Smichele 
233c28a25a1Srenato static int
if_start(struct iface * iface,int af)234a8c39dc0Srenato if_start(struct iface *iface, int af)
235ab0c2486Smichele {
236a8c39dc0Srenato 	struct iface_af		*ia;
237ab0c2486Smichele 	struct timeval		 now;
238ab0c2486Smichele 
239a8c39dc0Srenato 	log_debug("%s: %s address-family %s", __func__, iface->name,
240a8c39dc0Srenato 	    af_name(af));
241a8c39dc0Srenato 
242a8c39dc0Srenato 	ia = iface_af_get(iface, af);
24355f31565Srenato 
244ab0c2486Smichele 	gettimeofday(&now, NULL);
245a8c39dc0Srenato 	ia->uptime = now.tv_sec;
246ab0c2486Smichele 
247a8c39dc0Srenato 	switch (af) {
248a8c39dc0Srenato 	case AF_INET:
249a8c39dc0Srenato 		if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
250ab0c2486Smichele 			return (-1);
251a8c39dc0Srenato 		break;
252a8c39dc0Srenato 	case AF_INET6:
253a8c39dc0Srenato 		if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
254a8c39dc0Srenato 			return (-1);
255a8c39dc0Srenato 		break;
256a8c39dc0Srenato 	default:
257a8c39dc0Srenato 		fatalx("if_start: unknown af");
258a8c39dc0Srenato 	}
259ab0c2486Smichele 
260a8c39dc0Srenato 	send_hello(HELLO_LINK, ia, NULL);
261b5921293Srenato 
262a8c39dc0Srenato 	evtimer_set(&ia->hello_timer, if_hello_timer, ia);
263a8c39dc0Srenato 	if_start_hello_timer(ia);
264ab0c2486Smichele 	return (0);
265ab0c2486Smichele }
266ab0c2486Smichele 
267c28a25a1Srenato static int
if_reset(struct iface * iface,int af)268a8c39dc0Srenato if_reset(struct iface *iface, int af)
269ab0c2486Smichele {
270a8c39dc0Srenato 	struct iface_af		*ia;
2712751b1ccSrenato 	struct adj		*adj;
2722751b1ccSrenato 
273a8c39dc0Srenato 	log_debug("%s: %s address-family %s", __func__, iface->name,
274a8c39dc0Srenato 	    af_name(af));
27555f31565Srenato 
276a8c39dc0Srenato 	ia = iface_af_get(iface, af);
277a8c39dc0Srenato 	if_stop_hello_timer(ia);
278a8c39dc0Srenato 
279a8c39dc0Srenato 	while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
280e373a269Srenato 		adj_del(adj, S_SHUTDOWN);
281ab0c2486Smichele 
282814e607dSclaudio 	/* try to cleanup */
283a8c39dc0Srenato 	switch (af) {
284a8c39dc0Srenato 	case AF_INET:
285a8c39dc0Srenato 		if (global.ipv4.ldp_disc_socket != -1)
286a8c39dc0Srenato 			if_leave_ipv4_group(iface, &global.mcast_addr_v4);
287a8c39dc0Srenato 		break;
288a8c39dc0Srenato 	case AF_INET6:
289a8c39dc0Srenato 		if (global.ipv6.ldp_disc_socket != -1)
290a8c39dc0Srenato 			if_leave_ipv6_group(iface, &global.mcast_addr_v6);
291a8c39dc0Srenato 		break;
292a8c39dc0Srenato 	default:
293a8c39dc0Srenato 		fatalx("if_start: unknown af");
2942cba3533Srenato 	}
295814e607dSclaudio 
296ab0c2486Smichele 	return (0);
297ab0c2486Smichele }
298ab0c2486Smichele 
299c28a25a1Srenato static void
if_update_af(struct iface_af * ia,int link_ok)300a8c39dc0Srenato if_update_af(struct iface_af *ia, int link_ok)
301814e607dSclaudio {
302a8c39dc0Srenato 	int			 addr_ok = 0, socket_ok, rtr_id_ok;
303a8c39dc0Srenato 	struct if_addr		*if_addr;
304814e607dSclaudio 
305a8c39dc0Srenato 	switch (ia->af) {
306a8c39dc0Srenato 	case AF_INET:
307a8c39dc0Srenato 		/*
308a8c39dc0Srenato 		 * NOTE: for LDPv4, each interface should have at least one
309a8c39dc0Srenato 		 * valid IP address otherwise they can not be enabled.
310a8c39dc0Srenato 		 */
311a8c39dc0Srenato 		LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
312a8c39dc0Srenato 			if (if_addr->af == AF_INET) {
313a8c39dc0Srenato 				addr_ok = 1;
314a8c39dc0Srenato 				break;
315a8c39dc0Srenato 			}
316a8c39dc0Srenato 		}
317a8c39dc0Srenato 		break;
318a8c39dc0Srenato 	case AF_INET6:
319a8c39dc0Srenato 		/* for IPv6 the link-local address is enough. */
320a8c39dc0Srenato 		if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
321a8c39dc0Srenato 			addr_ok = 1;
322a8c39dc0Srenato 		break;
323a8c39dc0Srenato 	default:
324a8c39dc0Srenato 		fatalx("if_update_af: unknown af");
325a8c39dc0Srenato 	}
326b5921293Srenato 
327a8c39dc0Srenato 	if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
328b5921293Srenato 		socket_ok = 1;
329b5921293Srenato 	else
330b5921293Srenato 		socket_ok = 0;
331b5921293Srenato 
33208964f31Srenato 	if (leconf->rtr_id.s_addr != INADDR_ANY)
33308964f31Srenato 		rtr_id_ok = 1;
33408964f31Srenato 	else
33508964f31Srenato 		rtr_id_ok = 0;
33608964f31Srenato 
337a8c39dc0Srenato 	if (ia->state == IF_STA_DOWN) {
338a8c39dc0Srenato 		if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
339a8c39dc0Srenato 		    !rtr_id_ok)
340a8c39dc0Srenato 			return;
341814e607dSclaudio 
342a8c39dc0Srenato 		ia->state = IF_STA_ACTIVE;
343a8c39dc0Srenato 		if_start(ia->iface, ia->af);
344a8c39dc0Srenato 	} else if (ia->state == IF_STA_ACTIVE) {
345a8c39dc0Srenato 		if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
346a8c39dc0Srenato 			return;
347b5921293Srenato 
348a8c39dc0Srenato 		ia->state = IF_STA_DOWN;
349a8c39dc0Srenato 		if_reset(ia->iface, ia->af);
350814e607dSclaudio 	}
351814e607dSclaudio }
352814e607dSclaudio 
353b5921293Srenato void
if_update(struct iface * iface,int af)354a8c39dc0Srenato if_update(struct iface *iface, int af)
355a8c39dc0Srenato {
356a8c39dc0Srenato 	int			 link_ok;
357a8c39dc0Srenato 
358a8c39dc0Srenato 	link_ok = (iface->flags & IFF_UP) &&
359a8c39dc0Srenato 	    LINK_STATE_IS_UP(iface->linkstate);
360a8c39dc0Srenato 
361a8c39dc0Srenato 	if (af == AF_INET || af == AF_UNSPEC)
362a8c39dc0Srenato 		if_update_af(&iface->ipv4, link_ok);
363a8c39dc0Srenato 	if (af == AF_INET6 || af == AF_UNSPEC)
364a8c39dc0Srenato 		if_update_af(&iface->ipv6, link_ok);
365a8c39dc0Srenato }
366a8c39dc0Srenato 
367a8c39dc0Srenato void
if_update_all(int af)368a8c39dc0Srenato if_update_all(int af)
369b5921293Srenato {
370b5921293Srenato 	struct iface		*iface;
371b5921293Srenato 
372b5921293Srenato 	LIST_FOREACH(iface, &leconf->iface_list, entry)
373a8c39dc0Srenato 		if_update(iface, af);
374b5921293Srenato }
375b5921293Srenato 
37633f6ccfeSrenato /* timers */
377c28a25a1Srenato static void
if_hello_timer(int fd,short event,void * arg)37833f6ccfeSrenato if_hello_timer(int fd, short event, void *arg)
37933f6ccfeSrenato {
380a8c39dc0Srenato 	struct iface_af		*ia = arg;
38133f6ccfeSrenato 
382a8c39dc0Srenato 	send_hello(HELLO_LINK, ia, NULL);
383a8c39dc0Srenato 	if_start_hello_timer(ia);
38433f6ccfeSrenato }
38533f6ccfeSrenato 
386c28a25a1Srenato static void
if_start_hello_timer(struct iface_af * ia)387a8c39dc0Srenato if_start_hello_timer(struct iface_af *ia)
38833f6ccfeSrenato {
38933f6ccfeSrenato 	struct timeval		 tv;
39033f6ccfeSrenato 
39133f6ccfeSrenato 	timerclear(&tv);
392a8c39dc0Srenato 	tv.tv_sec = ia->hello_interval;
393a8c39dc0Srenato 	if (evtimer_add(&ia->hello_timer, &tv) == -1)
39433f6ccfeSrenato 		fatal(__func__);
39533f6ccfeSrenato }
39633f6ccfeSrenato 
397c28a25a1Srenato static void
if_stop_hello_timer(struct iface_af * ia)398a8c39dc0Srenato if_stop_hello_timer(struct iface_af *ia)
39933f6ccfeSrenato {
400a8c39dc0Srenato 	if (evtimer_pending(&ia->hello_timer, NULL) &&
401a8c39dc0Srenato 	    evtimer_del(&ia->hello_timer) == -1)
40233f6ccfeSrenato 		fatal(__func__);
40333f6ccfeSrenato }
40433f6ccfeSrenato 
405ab0c2486Smichele struct ctl_iface *
if_to_ctl(struct iface_af * ia)406a8c39dc0Srenato if_to_ctl(struct iface_af *ia)
407ab0c2486Smichele {
408ab0c2486Smichele 	static struct ctl_iface	 ictl;
4092a261b04Sclaudio 	struct timeval		 now;
4102a261b04Sclaudio 	struct adj		*adj;
411ab0c2486Smichele 
412a8c39dc0Srenato 	ictl.af = ia->af;
413a8c39dc0Srenato 	memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
414a8c39dc0Srenato 	ictl.ifindex = ia->iface->ifindex;
415a8c39dc0Srenato 	ictl.state = ia->state;
416a8c39dc0Srenato 	ictl.flags = ia->iface->flags;
417a8c39dc0Srenato 	ictl.linkstate = ia->iface->linkstate;
418a8c39dc0Srenato 	ictl.type = ia->iface->type;
419a8c39dc0Srenato 	ictl.if_type = ia->iface->if_type;
420a8c39dc0Srenato 	ictl.hello_holdtime = ia->hello_holdtime;
421a8c39dc0Srenato 	ictl.hello_interval = ia->hello_interval;
422ab0c2486Smichele 
423ab0c2486Smichele 	gettimeofday(&now, NULL);
424a8c39dc0Srenato 	if (ia->state != IF_STA_DOWN &&
425a8c39dc0Srenato 	    ia->uptime != 0) {
426a8c39dc0Srenato 		ictl.uptime = now.tv_sec - ia->uptime;
427ab0c2486Smichele 	} else
428ab0c2486Smichele 		ictl.uptime = 0;
429ab0c2486Smichele 
4302a261b04Sclaudio 	ictl.adj_cnt = 0;
431a8c39dc0Srenato 	LIST_FOREACH(adj, &ia->adj_list, ia_entry)
4322a261b04Sclaudio 		ictl.adj_cnt++;
4332a261b04Sclaudio 
434ab0c2486Smichele 	return (&ictl);
435ab0c2486Smichele }
436ab0c2486Smichele 
437a8c39dc0Srenato /* multicast membership sockopts */
438a8c39dc0Srenato in_addr_t
if_get_ipv4_addr(struct iface * iface)439a8c39dc0Srenato if_get_ipv4_addr(struct iface *iface)
440a8c39dc0Srenato {
441a8c39dc0Srenato 	struct if_addr		*if_addr;
442a8c39dc0Srenato 
443a8c39dc0Srenato 	LIST_FOREACH(if_addr, &iface->addr_list, entry)
444a8c39dc0Srenato 		if (if_addr->af == AF_INET)
445a8c39dc0Srenato 			return (if_addr->addr.v4.s_addr);
446a8c39dc0Srenato 
447a8c39dc0Srenato 	return (INADDR_ANY);
448a8c39dc0Srenato }
449a8c39dc0Srenato 
450c28a25a1Srenato static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)451a8c39dc0Srenato if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
452ab0c2486Smichele {
453ab0c2486Smichele 	struct ip_mreq		 mreq;
454ab0c2486Smichele 
4553de94509Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
4563de94509Srenato 	    inet_ntoa(*addr));
457ab0c2486Smichele 
4587aa09c5dSrenato 	mreq.imr_multiaddr = *addr;
459a8c39dc0Srenato 	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
460ab0c2486Smichele 
461a8c39dc0Srenato 	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
462df69c215Sderaadt 	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
4633de94509Srenato 		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
4643de94509Srenato 		     __func__, iface->name, inet_ntoa(*addr));
465ab0c2486Smichele 		return (-1);
466ab0c2486Smichele 	}
467ab0c2486Smichele 	return (0);
468ab0c2486Smichele }
469ab0c2486Smichele 
470c28a25a1Srenato static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)471a8c39dc0Srenato if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
472ab0c2486Smichele {
473ab0c2486Smichele 	struct ip_mreq		 mreq;
474ab0c2486Smichele 
4753de94509Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
4763de94509Srenato 	    inet_ntoa(*addr));
477814e607dSclaudio 
4787aa09c5dSrenato 	mreq.imr_multiaddr = *addr;
479a8c39dc0Srenato 	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
480ab0c2486Smichele 
481a8c39dc0Srenato 	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
482df69c215Sderaadt 	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) == -1) {
483b7b4db73Srenato 		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
484b7b4db73Srenato 		    "address %s", __func__, iface->name, inet_ntoa(*addr));
485ab0c2486Smichele 		return (-1);
486ab0c2486Smichele 	}
487ab0c2486Smichele 
488ab0c2486Smichele 	return (0);
489ab0c2486Smichele }
490a8c39dc0Srenato 
491c28a25a1Srenato static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)492a8c39dc0Srenato if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
493a8c39dc0Srenato {
494a8c39dc0Srenato 	struct ipv6_mreq	 mreq;
495a8c39dc0Srenato 
496a8c39dc0Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
497a8c39dc0Srenato 	    log_in6addr(addr));
498a8c39dc0Srenato 
499a8c39dc0Srenato 	mreq.ipv6mr_multiaddr = *addr;
500a8c39dc0Srenato 	mreq.ipv6mr_interface = iface->ifindex;
501a8c39dc0Srenato 
502a8c39dc0Srenato 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
503df69c215Sderaadt 	    IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
504a8c39dc0Srenato 		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
505a8c39dc0Srenato 		    __func__, iface->name, log_in6addr(addr));
506a8c39dc0Srenato 		return (-1);
507a8c39dc0Srenato 	}
508a8c39dc0Srenato 
509a8c39dc0Srenato 	return (0);
510a8c39dc0Srenato }
511a8c39dc0Srenato 
512c28a25a1Srenato static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)513a8c39dc0Srenato if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
514a8c39dc0Srenato {
515a8c39dc0Srenato 	struct ipv6_mreq	 mreq;
516a8c39dc0Srenato 
517a8c39dc0Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
518a8c39dc0Srenato 	    log_in6addr(addr));
519a8c39dc0Srenato 
520a8c39dc0Srenato 	mreq.ipv6mr_multiaddr = *addr;
521a8c39dc0Srenato 	mreq.ipv6mr_interface = iface->ifindex;
522a8c39dc0Srenato 
523a8c39dc0Srenato 	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
524df69c215Sderaadt 	    IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) == -1) {
525a8c39dc0Srenato 		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
526a8c39dc0Srenato 		    __func__, iface->name, log_in6addr(addr));
527a8c39dc0Srenato 		return (-1);
528a8c39dc0Srenato 	}
529a8c39dc0Srenato 
530a8c39dc0Srenato 	return (0);
531a8c39dc0Srenato }
532