xref: /openbsd-src/usr.sbin/eigrpd/interface.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: interface.c,v 1.26 2023/03/08 04:43:13 guenther Exp $ */
243509a12Srenato 
343509a12Srenato /*
443509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
643509a12Srenato  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
743509a12Srenato  *
843509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
943509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
1043509a12Srenato  * copyright notice and this permission notice appear in all copies.
1143509a12Srenato  *
1243509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1343509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1443509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1543509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1643509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1743509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1843509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1943509a12Srenato  */
2043509a12Srenato 
218072de9bSrenato #include <sys/types.h>
2243509a12Srenato #include <sys/socket.h>
238072de9bSrenato #include <sys/ioctl.h>
2443509a12Srenato #include <arpa/inet.h>
258072de9bSrenato 
2643509a12Srenato #include <ctype.h>
278072de9bSrenato #include <stdlib.h>
2843509a12Srenato #include <string.h>
298072de9bSrenato #include <unistd.h>
3043509a12Srenato 
3143509a12Srenato #include "eigrpd.h"
3243509a12Srenato #include "eigrpe.h"
338072de9bSrenato #include "log.h"
3443509a12Srenato 
35ab786365Srenato static __inline int	 iface_id_compare(struct eigrp_iface *,
36ab786365Srenato 			    struct eigrp_iface *);
37ab786365Srenato static struct iface	*if_new(struct eigrpd_conf *, struct kif *);
38ab786365Srenato static void		 if_del(struct iface *);
39ab786365Srenato static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
40ab786365Srenato static void		 eigrp_if_start(struct eigrp_iface *);
41ab786365Srenato static void		 eigrp_if_reset(struct eigrp_iface *);
42ab786365Srenato static void		 eigrp_if_hello_timer(int, short, void *);
43ab786365Srenato static void		 eigrp_if_start_hello_timer(struct eigrp_iface *);
44ab786365Srenato static void		 eigrp_if_stop_hello_timer(struct eigrp_iface *);
45ab786365Srenato static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
46ab786365Srenato static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
47ab786365Srenato static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
48ab786365Srenato static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
4943509a12Srenato 
50ab786365Srenato RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare)
51ab786365Srenato 
52ab786365Srenato struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id);
5343509a12Srenato 
5443509a12Srenato static __inline int
iface_id_compare(struct eigrp_iface * a,struct eigrp_iface * b)5543509a12Srenato iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b)
5643509a12Srenato {
5743509a12Srenato 	return (a->ifaceid - b->ifaceid);
5843509a12Srenato }
5943509a12Srenato 
60ab786365Srenato static struct iface *
if_new(struct eigrpd_conf * xconf,struct kif * kif)6143509a12Srenato if_new(struct eigrpd_conf *xconf, struct kif *kif)
6243509a12Srenato {
6343509a12Srenato 	struct iface		*iface;
6443509a12Srenato 
6543509a12Srenato 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
6644faa115Srenato 		fatal("if_new: calloc");
6743509a12Srenato 
6843509a12Srenato 	TAILQ_INIT(&iface->ei_list);
6943509a12Srenato 	TAILQ_INIT(&iface->addr_list);
7043509a12Srenato 
7143509a12Srenato 	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
7243509a12Srenato 
7343509a12Srenato 	/* get type */
7443509a12Srenato 	if (kif->flags & IFF_POINTOPOINT)
7543509a12Srenato 		iface->type = IF_TYPE_POINTOPOINT;
7643509a12Srenato 	if (kif->flags & IFF_BROADCAST &&
7743509a12Srenato 	    kif->flags & IFF_MULTICAST)
7843509a12Srenato 		iface->type = IF_TYPE_BROADCAST;
7943509a12Srenato 	if (kif->flags & IFF_LOOPBACK)
8043509a12Srenato 		iface->type = IF_TYPE_POINTOPOINT;
8143509a12Srenato 
8243509a12Srenato 	/* get index and flags */
8343509a12Srenato 	iface->mtu = kif->mtu;
8443509a12Srenato 	iface->ifindex = kif->ifindex;
8506c7f8f8Srenato 	iface->rdomain = kif->rdomain;
8643509a12Srenato 	iface->flags = kif->flags;
8743509a12Srenato 	iface->linkstate = kif->link_state;
8843509a12Srenato 	iface->if_type = kif->if_type;
8943509a12Srenato 	iface->baudrate = kif->baudrate;
9043509a12Srenato 
9143509a12Srenato 	TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry);
9243509a12Srenato 
9343509a12Srenato 	return (iface);
9443509a12Srenato }
9543509a12Srenato 
96ab786365Srenato static void
if_del(struct iface * iface)9743509a12Srenato if_del(struct iface *iface)
9843509a12Srenato {
9943509a12Srenato 	struct if_addr		*if_addr;
10043509a12Srenato 
10143509a12Srenato 	log_debug("%s: interface %s", __func__, iface->name);
10243509a12Srenato 
10343509a12Srenato 	while ((if_addr = TAILQ_FIRST(&iface->addr_list)) != NULL) {
10443509a12Srenato 		TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
10543509a12Srenato 		free(if_addr);
10643509a12Srenato 	}
10743509a12Srenato 
10843509a12Srenato 	TAILQ_REMOVE(&econf->iface_list, iface, entry);
10943509a12Srenato 	free(iface);
11043509a12Srenato }
11143509a12Srenato 
1122e046f62Srenato struct iface *
if_lookup(struct eigrpd_conf * xconf,unsigned int ifindex)1132e046f62Srenato if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex)
1142e046f62Srenato {
1152e046f62Srenato 	struct iface	*iface;
1162e046f62Srenato 
1172e046f62Srenato 	TAILQ_FOREACH(iface, &xconf->iface_list, entry)
1182e046f62Srenato 		if (iface->ifindex == ifindex)
1192e046f62Srenato 			return (iface);
1202e046f62Srenato 
1212e046f62Srenato 	return (NULL);
1222e046f62Srenato }
1232e046f62Srenato 
12443509a12Srenato void
if_addr_new(struct iface * iface,struct kaddr * ka)1252e046f62Srenato if_addr_new(struct iface *iface, struct kaddr *ka)
12643509a12Srenato {
12743509a12Srenato 	struct if_addr		*if_addr;
12843509a12Srenato 	struct eigrp_iface	*ei;
12943509a12Srenato 
130e7271a36Srenato 	if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) {
131e7271a36Srenato 		iface->linklocal = ka->addr.v6;
132e7271a36Srenato 		if_update(iface, AF_INET6);
133e7271a36Srenato 		return;
134e7271a36Srenato 	}
135e7271a36Srenato 
1362e046f62Srenato 	if (if_addr_lookup(&iface->addr_list, ka) != NULL)
13744faa115Srenato 		return;
13843509a12Srenato 
13943509a12Srenato 	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
14044faa115Srenato 		fatal("if_addr_new: calloc");
1412e046f62Srenato 	if_addr->af = ka->af;
1422e046f62Srenato 	if_addr->addr = ka->addr;
1432e046f62Srenato 	if_addr->prefixlen = ka->prefixlen;
1442e046f62Srenato 	if_addr->dstbrd = ka->dstbrd;
14543509a12Srenato 	TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry);
14643509a12Srenato 
14743509a12Srenato 	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
14843509a12Srenato 		if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
14943509a12Srenato 			eigrpe_orig_local_route(ei, if_addr, 0);
15043509a12Srenato 
151e7271a36Srenato 	if (if_addr->af == AF_INET)
152e7271a36Srenato 		if_update(iface, AF_INET);
15343509a12Srenato }
15443509a12Srenato 
15543509a12Srenato void
if_addr_del(struct iface * iface,struct kaddr * ka)1562e046f62Srenato if_addr_del(struct iface *iface, struct kaddr *ka)
15743509a12Srenato {
15843509a12Srenato 	struct if_addr		*if_addr;
15943509a12Srenato 	struct eigrp_iface	*ei;
160e7271a36Srenato 	int			 af = ka->af;
161e7271a36Srenato 
162e7271a36Srenato 	if (ka->af == AF_INET6 &&
163e7271a36Srenato 	    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) {
164e7271a36Srenato 		memset(&iface->linklocal, 0, sizeof(iface->linklocal));
165e7271a36Srenato 		if_update(iface, AF_INET6);
166e7271a36Srenato 		return;
167e7271a36Srenato 	}
16843509a12Srenato 
1692e046f62Srenato 	if_addr = if_addr_lookup(&iface->addr_list, ka);
17043509a12Srenato 	if (if_addr == NULL)
17143509a12Srenato 		return;
17243509a12Srenato 
17343509a12Srenato 	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
17443509a12Srenato 		if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
17543509a12Srenato 			eigrpe_orig_local_route(ei, if_addr, 1);
17643509a12Srenato 
17743509a12Srenato 	TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
17843509a12Srenato 	free(if_addr);
179e7271a36Srenato 
180e7271a36Srenato 	if (af == AF_INET)
181e7271a36Srenato 		if_update(iface, AF_INET);
18243509a12Srenato }
18343509a12Srenato 
184ab786365Srenato static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)1852e046f62Srenato if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
18643509a12Srenato {
18743509a12Srenato 	struct if_addr	*if_addr;
1882e046f62Srenato 	int		 af = ka->af;
18943509a12Srenato 
19043509a12Srenato 	TAILQ_FOREACH(if_addr, addr_list, entry)
1912e046f62Srenato 		if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) &&
1922e046f62Srenato 		    if_addr->prefixlen == ka->prefixlen &&
1932e046f62Srenato 		    !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
19443509a12Srenato 			return (if_addr);
19543509a12Srenato 
19643509a12Srenato 	return (NULL);
19743509a12Srenato }
19843509a12Srenato 
19943509a12Srenato in_addr_t
if_primary_addr(struct iface * iface)20043509a12Srenato if_primary_addr(struct iface *iface)
20143509a12Srenato {
20243509a12Srenato 	struct if_addr	*if_addr;
20343509a12Srenato 
20443509a12Srenato 	TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
20543509a12Srenato 		if (if_addr->af == AF_INET)
20643509a12Srenato 			return (if_addr->addr.v4.s_addr);
20743509a12Srenato 
20843509a12Srenato 	return (INADDR_ANY);
20943509a12Srenato }
21043509a12Srenato 
21143509a12Srenato uint8_t
if_primary_addr_prefixlen(struct iface * iface)21243509a12Srenato if_primary_addr_prefixlen(struct iface *iface)
21343509a12Srenato {
21443509a12Srenato 	struct if_addr	*if_addr;
21543509a12Srenato 
21643509a12Srenato 	TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
21743509a12Srenato 		if (if_addr->af == AF_INET)
21843509a12Srenato 			return (if_addr->prefixlen);
21943509a12Srenato 
22043509a12Srenato 	return (0);
22143509a12Srenato }
22243509a12Srenato 
22343509a12Srenato /* up/down events */
22443509a12Srenato void
if_update(struct iface * iface,int af)22543509a12Srenato if_update(struct iface *iface, int af)
22643509a12Srenato {
22743509a12Srenato 	struct eigrp_iface	*ei;
22843509a12Srenato 	int			 link_ok;
229d6040158Srenato 	int			 addr_ok, addr4_ok = 0, addr6_ok = 0;
23046ee0129Srenato 	struct if_addr		*if_addr;
23143509a12Srenato 
23243509a12Srenato 	link_ok = (iface->flags & IFF_UP) &&
23343509a12Srenato 	    LINK_STATE_IS_UP(iface->linkstate);
23443509a12Srenato 
23546ee0129Srenato 	/*
236d6040158Srenato 	 * NOTE: for EIGRPv4, each interface should have at least one valid
237d6040158Srenato 	 * IP address otherwise they can not be enabled in the routing domain.
23846ee0129Srenato 	 */
239d6040158Srenato 	TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
240d6040158Srenato 		if (if_addr->af == AF_INET) {
241d6040158Srenato 			addr4_ok = 1;
24246ee0129Srenato 			break;
24346ee0129Srenato 		}
244d6040158Srenato 	}
245d6040158Srenato 	/* for IPv6 the link-local address is enough. */
246d6040158Srenato 	if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal))
247d6040158Srenato 		addr6_ok = 1;
24846ee0129Srenato 
24943509a12Srenato 	TAILQ_FOREACH(ei, &iface->ei_list, i_entry) {
25043509a12Srenato 		if (af != AF_UNSPEC && ei->eigrp->af != af)
25143509a12Srenato 			continue;
25243509a12Srenato 
253d6040158Srenato 		switch (ei->eigrp->af) {
254d6040158Srenato 		case AF_INET:
255d6040158Srenato 			addr_ok = addr4_ok;
256d6040158Srenato 			break;
257d6040158Srenato 		case AF_INET6:
258d6040158Srenato 			addr_ok = addr6_ok;
259d6040158Srenato 			break;
260d6040158Srenato 		default:
261d6040158Srenato 			fatalx("if_update: unknown af");
262d6040158Srenato 		}
263d6040158Srenato 
26443509a12Srenato 		if (ei->state == IF_STA_DOWN) {
26546ee0129Srenato 			if (!link_ok || !addr_ok)
26643509a12Srenato 				continue;
26743509a12Srenato 			ei->state = IF_STA_ACTIVE;
26843509a12Srenato 			eigrp_if_start(ei);
26946ee0129Srenato 		} else if (ei->state == IF_STA_ACTIVE) {
27046ee0129Srenato 			if (link_ok && addr_ok)
27143509a12Srenato 				continue;
27243509a12Srenato 			ei->state = IF_STA_DOWN;
27343509a12Srenato 			eigrp_if_reset(ei);
27443509a12Srenato 		}
27543509a12Srenato 	}
27643509a12Srenato }
27743509a12Srenato 
27843509a12Srenato struct eigrp_iface *
eigrp_if_new(struct eigrpd_conf * xconf,struct eigrp * eigrp,struct kif * kif)27943509a12Srenato eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif)
28043509a12Srenato {
28143509a12Srenato 	struct iface		*iface;
28243509a12Srenato 	struct eigrp_iface	*ei;
2835425f012Srenato 	static uint32_t		 ifacecnt = 1;
28443509a12Srenato 
28543509a12Srenato 	iface = if_lookup(xconf, kif->ifindex);
28643509a12Srenato 	if (iface == NULL)
28743509a12Srenato 		iface = if_new(xconf, kif);
28843509a12Srenato 
28943509a12Srenato 	if ((ei = calloc(1, sizeof(*ei))) == NULL)
29044faa115Srenato 		fatal("eigrp_if_new: calloc");
29143509a12Srenato 
29243509a12Srenato 	ei->state = IF_STA_DOWN;
29343509a12Srenato 	/* get next unused ifaceid */
2942e046f62Srenato 	while (eigrp_if_lookup_id(ifacecnt++))
29543509a12Srenato 		;
29643509a12Srenato 	ei->ifaceid = ifacecnt;
29743509a12Srenato 	ei->eigrp = eigrp;
29843509a12Srenato 	ei->iface = iface;
29943509a12Srenato 	if (ei->iface->flags & IFF_LOOPBACK)
30043509a12Srenato 		ei->passive = 1;
30143509a12Srenato 
30243509a12Srenato 	TAILQ_INIT(&ei->nbr_list);
30343509a12Srenato 	TAILQ_INIT(&ei->update_list);
30443509a12Srenato 	TAILQ_INIT(&ei->query_list);
305bc6e1915Srenato 	TAILQ_INIT(&ei->summary_list);
30643509a12Srenato 	TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry);
30743509a12Srenato 	TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry);
30843509a12Srenato 	if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL)
30943509a12Srenato 		fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed");
31043509a12Srenato 
31143509a12Srenato 	return (ei);
31243509a12Srenato }
31343509a12Srenato 
31443509a12Srenato void
eigrp_if_del(struct eigrp_iface * ei)31543509a12Srenato eigrp_if_del(struct eigrp_iface *ei)
31643509a12Srenato {
317bc6e1915Srenato 	struct summary_addr	*summary;
318bc6e1915Srenato 
31943509a12Srenato 	RB_REMOVE(iface_id_head, &ifaces_by_id, ei);
32043509a12Srenato 	TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry);
32143509a12Srenato 	TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry);
322bc6e1915Srenato 	while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) {
323bc6e1915Srenato 		TAILQ_REMOVE(&ei->summary_list, summary, entry);
324bc6e1915Srenato 		free(summary);
325bc6e1915Srenato 	}
3260cefb3adSrenato 	message_list_clr(&ei->query_list);
3270cefb3adSrenato 	message_list_clr(&ei->update_list);
32843509a12Srenato 
32943509a12Srenato 	if (ei->state == IF_STA_ACTIVE)
33043509a12Srenato 		eigrp_if_reset(ei);
33143509a12Srenato 
33243509a12Srenato 	if (TAILQ_EMPTY(&ei->iface->ei_list))
33343509a12Srenato 		if_del(ei->iface);
33443509a12Srenato 
33543509a12Srenato 	free(ei);
33643509a12Srenato }
33743509a12Srenato 
3382e046f62Srenato struct eigrp_iface *
eigrp_if_lookup(struct iface * iface,int af,uint16_t as)3392e046f62Srenato eigrp_if_lookup(struct iface *iface, int af, uint16_t as)
3402e046f62Srenato {
3412e046f62Srenato 	struct eigrp_iface	*ei;
3422e046f62Srenato 
3432e046f62Srenato 	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
3442e046f62Srenato 		if (ei->eigrp->af == af &&
3452e046f62Srenato 		    ei->eigrp->as == as)
3462e046f62Srenato 			return (ei);
3472e046f62Srenato 
3482e046f62Srenato 	return (NULL);
3492e046f62Srenato }
3502e046f62Srenato 
3512e046f62Srenato struct eigrp_iface *
eigrp_if_lookup_id(uint32_t ifaceid)3522e046f62Srenato eigrp_if_lookup_id(uint32_t ifaceid)
3532e046f62Srenato {
3542e046f62Srenato 	struct eigrp_iface	 e;
3552e046f62Srenato 	e.ifaceid = ifaceid;
3562e046f62Srenato 	return (RB_FIND(iface_id_head, &ifaces_by_id, &e));
3572e046f62Srenato }
3582e046f62Srenato 
359ab786365Srenato static void
eigrp_if_start(struct eigrp_iface * ei)36043509a12Srenato eigrp_if_start(struct eigrp_iface *ei)
36143509a12Srenato {
36243509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
3632d38b530Srenato 	struct timeval		 now;
36443509a12Srenato 	struct if_addr		*if_addr;
36518d502b7Srenato 	union eigrpd_addr	 addr;
36643509a12Srenato 
36743509a12Srenato 	log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
36843509a12Srenato 	    eigrp->as, af_name(eigrp->af));
36943509a12Srenato 
3702d38b530Srenato 	gettimeofday(&now, NULL);
3712d38b530Srenato 	ei->uptime = now.tv_sec;
3722d38b530Srenato 
37318d502b7Srenato 	/* init the dummy self neighbor */
37418d502b7Srenato 	memset(&addr, 0, sizeof(addr));
37518d502b7Srenato 	ei->self = nbr_new(ei, &addr, 0, 1);
37618d502b7Srenato 	nbr_init(ei->self);
37718d502b7Srenato 
37843509a12Srenato 	TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry) {
37943509a12Srenato 		if (if_addr->af != eigrp->af)
38043509a12Srenato 			continue;
38143509a12Srenato 
38243509a12Srenato 		eigrpe_orig_local_route(ei, if_addr, 0);
38343509a12Srenato 	}
38443509a12Srenato 
38543509a12Srenato 	if (ei->passive)
38643509a12Srenato 		return;
38743509a12Srenato 
38843509a12Srenato 	switch (eigrp->af) {
38943509a12Srenato 	case AF_INET:
390e14e95d7Srenato 		if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4))
39143509a12Srenato 			return;
39243509a12Srenato 		break;
39343509a12Srenato 	case AF_INET6:
394e14e95d7Srenato 		if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6))
39543509a12Srenato 			return;
39643509a12Srenato 		break;
39743509a12Srenato 	default:
3983c8071b0Srenato 		fatalx("eigrp_if_start: unknown af");
39943509a12Srenato 	}
40043509a12Srenato 
4010b78755cSrenato 	evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei);
40243509a12Srenato 	eigrp_if_start_hello_timer(ei);
40343509a12Srenato }
40443509a12Srenato 
405ab786365Srenato static void
eigrp_if_reset(struct eigrp_iface * ei)40643509a12Srenato eigrp_if_reset(struct eigrp_iface *ei)
40743509a12Srenato {
40843509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
409a2dbf0baSrenato 	struct nbr		*nbr;
41043509a12Srenato 
41143509a12Srenato 	log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
41243509a12Srenato 	    eigrp->as, af_name(eigrp->af));
41343509a12Srenato 
41443509a12Srenato 	/* the rde will withdraw the connected route for us */
41543509a12Srenato 
4160b78755cSrenato 	while ((nbr = TAILQ_FIRST(&ei->nbr_list)) != NULL)
4170b78755cSrenato 		nbr_del(nbr);
4180b78755cSrenato 
41943509a12Srenato 	if (ei->passive)
42043509a12Srenato 		return;
42143509a12Srenato 
42243509a12Srenato 	/* try to cleanup */
42343509a12Srenato 	switch (eigrp->af) {
42443509a12Srenato 	case AF_INET:
425e14e95d7Srenato 		if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4);
42643509a12Srenato 		break;
42743509a12Srenato 	case AF_INET6:
428e14e95d7Srenato 		if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6);
42943509a12Srenato 		break;
43043509a12Srenato 	default:
4313c8071b0Srenato 		fatalx("eigrp_if_reset: unknown af");
43243509a12Srenato 	}
43343509a12Srenato 
43443509a12Srenato 	eigrp_if_stop_hello_timer(ei);
43543509a12Srenato }
43643509a12Srenato 
43743509a12Srenato /* timers */
438ab786365Srenato static void
eigrp_if_hello_timer(int fd,short event,void * arg)43943509a12Srenato eigrp_if_hello_timer(int fd, short event, void *arg)
44043509a12Srenato {
44143509a12Srenato 	struct eigrp_iface	*ei = arg;
44243509a12Srenato 	struct timeval		 tv;
44343509a12Srenato 
4440e96235eSrenato 	send_hello(ei, NULL, 0);
44543509a12Srenato 
44643509a12Srenato 	/* reschedule hello_timer */
44743509a12Srenato 	timerclear(&tv);
44843509a12Srenato 	tv.tv_sec = ei->hello_interval;
44943509a12Srenato 	if (evtimer_add(&ei->hello_timer, &tv) == -1)
45043509a12Srenato 		fatal("eigrp_if_hello_timer");
45143509a12Srenato }
45243509a12Srenato 
453ab786365Srenato static void
eigrp_if_start_hello_timer(struct eigrp_iface * ei)45443509a12Srenato eigrp_if_start_hello_timer(struct eigrp_iface *ei)
45543509a12Srenato {
45643509a12Srenato 	struct timeval		 tv;
45743509a12Srenato 
45843509a12Srenato 	timerclear(&tv);
45943509a12Srenato 	tv.tv_sec = ei->hello_interval;
46043509a12Srenato 	if (evtimer_add(&ei->hello_timer, &tv) == -1)
46143509a12Srenato 		fatal("eigrp_if_start_hello_timer");
46243509a12Srenato }
46343509a12Srenato 
464ab786365Srenato static void
eigrp_if_stop_hello_timer(struct eigrp_iface * ei)46543509a12Srenato eigrp_if_stop_hello_timer(struct eigrp_iface *ei)
46643509a12Srenato {
46743509a12Srenato 	if (evtimer_pending(&ei->hello_timer, NULL) &&
46843509a12Srenato 	    evtimer_del(&ei->hello_timer) == -1)
46943509a12Srenato 		fatal("eigrp_if_stop_hello_timer");
47043509a12Srenato }
47143509a12Srenato 
47243509a12Srenato struct ctl_iface *
if_to_ctl(struct eigrp_iface * ei)47343509a12Srenato if_to_ctl(struct eigrp_iface *ei)
47443509a12Srenato {
47543509a12Srenato 	static struct ctl_iface	 ictl;
47643509a12Srenato 	struct timeval		 now;
47743509a12Srenato 	struct nbr		*nbr;
47843509a12Srenato 
47943509a12Srenato 	ictl.af = ei->eigrp->af;
48043509a12Srenato 	ictl.as = ei->eigrp->as;
48143509a12Srenato 	memcpy(ictl.name, ei->iface->name, sizeof(ictl.name));
48243509a12Srenato 	ictl.ifindex = ei->iface->ifindex;
48343509a12Srenato 	switch (ei->eigrp->af) {
48443509a12Srenato 	case AF_INET:
48543509a12Srenato 		ictl.addr.v4.s_addr = if_primary_addr(ei->iface);
48643509a12Srenato 		ictl.prefixlen = if_primary_addr_prefixlen(ei->iface);
48743509a12Srenato 		break;
48843509a12Srenato 	case AF_INET6:
4893eb03b29Srenato 		ictl.addr.v6 = ei->iface->linklocal;
490bce3b5b3Srenato 		if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal))
49143509a12Srenato 			ictl.prefixlen = 64;
492bce3b5b3Srenato 		else
493bce3b5b3Srenato 			ictl.prefixlen = 0;
49443509a12Srenato 		break;
49543509a12Srenato 	default:
4963c8071b0Srenato 		fatalx("if_to_ctl: unknown af");
49743509a12Srenato 	}
49843509a12Srenato 	ictl.flags = ei->iface->flags;
49943509a12Srenato 	ictl.linkstate = ei->iface->linkstate;
50043509a12Srenato 	ictl.mtu = ei->iface->mtu;
50143509a12Srenato 	ictl.type = ei->iface->type;
50243509a12Srenato 	ictl.if_type = ei->iface->if_type;
50343509a12Srenato 	ictl.baudrate = ei->iface->baudrate;
50443509a12Srenato 	ictl.delay = ei->delay;
50543509a12Srenato 	ictl.bandwidth = ei->bandwidth;
50643509a12Srenato 	ictl.hello_holdtime = ei->hello_holdtime;
50743509a12Srenato 	ictl.hello_interval = ei->hello_interval;
50843509a12Srenato 	ictl.splithorizon = ei->splithorizon;
50943509a12Srenato 	ictl.passive = ei->passive;
51043509a12Srenato 	ictl.nbr_cnt = 0;
51143509a12Srenato 
51243509a12Srenato 	gettimeofday(&now, NULL);
51343509a12Srenato 	if (ei->state != IF_STA_DOWN && ei->uptime != 0)
51443509a12Srenato 		ictl.uptime = now.tv_sec - ei->uptime;
51543509a12Srenato 	else
51643509a12Srenato 		ictl.uptime = 0;
51743509a12Srenato 
51843509a12Srenato 	TAILQ_FOREACH(nbr, &ei->nbr_list, entry)
51943509a12Srenato 		if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF)))
52043509a12Srenato 			ictl.nbr_cnt++;
52143509a12Srenato 
52243509a12Srenato 	return (&ictl);
52343509a12Srenato }
52443509a12Srenato 
52543509a12Srenato /* misc */
52643509a12Srenato void
if_set_sockbuf(int fd)52743509a12Srenato if_set_sockbuf(int fd)
52843509a12Srenato {
52943509a12Srenato 	int	bsize;
53043509a12Srenato 
53143509a12Srenato 	bsize = 65535;
53243509a12Srenato 	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
53343509a12Srenato 	    sizeof(bsize)) == -1)
53443509a12Srenato 		bsize /= 2;
53543509a12Srenato 
53643509a12Srenato 	if (bsize != 65535)
53743509a12Srenato 		log_warnx("%s: recvbuf size only %d", __func__, bsize);
53843509a12Srenato 
53943509a12Srenato 	bsize = 65535;
54043509a12Srenato 	while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize,
54143509a12Srenato 	    sizeof(bsize)) == -1)
54243509a12Srenato 		bsize /= 2;
54343509a12Srenato 
54443509a12Srenato 	if (bsize != 65535)
54543509a12Srenato 		log_warnx("%s: sendbuf size only %d", __func__, bsize);
54643509a12Srenato }
54743509a12Srenato 
548ab786365Srenato static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)54943509a12Srenato if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
55043509a12Srenato {
55143509a12Srenato 	struct ip_mreq		 mreq;
55243509a12Srenato 
55343509a12Srenato 	if (iface->group_count_v4++ != 0)
55443509a12Srenato 		/* already joined */
55543509a12Srenato 		return (0);
55643509a12Srenato 
55743509a12Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
55843509a12Srenato 	    inet_ntoa(*addr));
55943509a12Srenato 
560bce3b5b3Srenato 	mreq.imr_multiaddr = *addr;
56143509a12Srenato 	mreq.imr_interface.s_addr = if_primary_addr(iface);
56243509a12Srenato 
56302eb61efSrenato 	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP,
564df69c215Sderaadt 	    (void *)&mreq, sizeof(mreq)) == -1) {
56543509a12Srenato 		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
56643509a12Srenato 		    __func__, iface->name, inet_ntoa(*addr));
56743509a12Srenato 		return (-1);
56843509a12Srenato 	}
56943509a12Srenato 
57043509a12Srenato 	return (0);
57143509a12Srenato }
57243509a12Srenato 
573ab786365Srenato static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)57443509a12Srenato if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
57543509a12Srenato {
57643509a12Srenato 	struct ip_mreq		 mreq;
57743509a12Srenato 
57843509a12Srenato 	if (--iface->group_count_v4 != 0)
57943509a12Srenato 		/* others still joined */
58043509a12Srenato 		return (0);
58143509a12Srenato 
58243509a12Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
58343509a12Srenato 	    inet_ntoa(*addr));
58443509a12Srenato 
585bce3b5b3Srenato 	mreq.imr_multiaddr = *addr;
58643509a12Srenato 	mreq.imr_interface.s_addr = if_primary_addr(iface);
58743509a12Srenato 
58802eb61efSrenato 	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP,
589df69c215Sderaadt 	    (void *)&mreq, sizeof(mreq)) == -1) {
59043509a12Srenato 		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
59143509a12Srenato 		    "address %s", iface->name, __func__, inet_ntoa(*addr));
59243509a12Srenato 		return (-1);
59343509a12Srenato 	}
59443509a12Srenato 
59543509a12Srenato 	return (0);
59643509a12Srenato }
59743509a12Srenato 
59843509a12Srenato int
if_set_ipv4_mcast_ttl(int fd,uint8_t ttl)59943509a12Srenato if_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
60043509a12Srenato {
60143509a12Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
602df69c215Sderaadt 	    (char *)&ttl, sizeof(ttl)) == -1) {
60343509a12Srenato 		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
60443509a12Srenato 		    __func__, ttl);
60543509a12Srenato 		return (-1);
60643509a12Srenato 	}
60743509a12Srenato 
60843509a12Srenato 	return (0);
60943509a12Srenato }
61043509a12Srenato 
61143509a12Srenato int
if_set_ipv4_mcast(struct iface * iface)61243509a12Srenato if_set_ipv4_mcast(struct iface *iface)
61343509a12Srenato {
61443509a12Srenato 	in_addr_t	 addr;
61543509a12Srenato 
61643509a12Srenato 	addr = if_primary_addr(iface);
61743509a12Srenato 
61802eb61efSrenato 	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF,
619df69c215Sderaadt 	    &addr, sizeof(addr)) == -1) {
62043509a12Srenato 		log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
62143509a12Srenato 		    __func__, iface->name);
62243509a12Srenato 		return (-1);
62343509a12Srenato 	}
62443509a12Srenato 
62543509a12Srenato 	return (0);
62643509a12Srenato }
62743509a12Srenato 
62843509a12Srenato int
if_set_ipv4_mcast_loop(int fd)62943509a12Srenato if_set_ipv4_mcast_loop(int fd)
63043509a12Srenato {
63143509a12Srenato 	uint8_t	loop = 0;
63243509a12Srenato 
63343509a12Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
634df69c215Sderaadt 	    (char *)&loop, sizeof(loop)) == -1) {
63543509a12Srenato 		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
63643509a12Srenato 		return (-1);
63743509a12Srenato 	}
63843509a12Srenato 
63943509a12Srenato 	return (0);
64043509a12Srenato }
64143509a12Srenato 
64243509a12Srenato int
if_set_ipv4_recvif(int fd,int enable)64343509a12Srenato if_set_ipv4_recvif(int fd, int enable)
64443509a12Srenato {
64543509a12Srenato 	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
646df69c215Sderaadt 	    sizeof(enable)) == -1) {
64743509a12Srenato 		log_warn("%s: error setting IP_RECVIF", __func__);
64843509a12Srenato 		return (-1);
64943509a12Srenato 	}
65043509a12Srenato 	return (0);
65143509a12Srenato }
65243509a12Srenato 
65343509a12Srenato int
if_set_ipv4_hdrincl(int fd)65443509a12Srenato if_set_ipv4_hdrincl(int fd)
65543509a12Srenato {
65643509a12Srenato 	int	hincl = 1;
65743509a12Srenato 
658df69c215Sderaadt 	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) {
65943509a12Srenato 		log_warn("%s: error setting IP_HDRINCL", __func__);
66043509a12Srenato 		return (-1);
66143509a12Srenato 	}
66243509a12Srenato 
66343509a12Srenato 	return (0);
66443509a12Srenato }
66543509a12Srenato 
666ab786365Srenato static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)66743509a12Srenato if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
66843509a12Srenato {
66943509a12Srenato 	struct ipv6_mreq	 mreq;
67043509a12Srenato 
67143509a12Srenato 	if (iface->group_count_v6++ != 0)
67243509a12Srenato 		/* already joined */
67343509a12Srenato 		return (0);
67443509a12Srenato 
67543509a12Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
67643509a12Srenato 	    log_in6addr(addr));
67743509a12Srenato 
67843509a12Srenato 	mreq.ipv6mr_multiaddr = *addr;
67943509a12Srenato 	mreq.ipv6mr_interface = iface->ifindex;
68043509a12Srenato 
68102eb61efSrenato 	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
682df69c215Sderaadt 	    &mreq, sizeof(mreq)) == -1) {
68343509a12Srenato 		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
68443509a12Srenato 		    __func__, iface->name, log_in6addr(addr));
68543509a12Srenato 		return (-1);
68643509a12Srenato 	}
68743509a12Srenato 
68843509a12Srenato 	return (0);
68943509a12Srenato }
69043509a12Srenato 
691ab786365Srenato static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)69243509a12Srenato if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
69343509a12Srenato {
69443509a12Srenato 	struct ipv6_mreq	 mreq;
69543509a12Srenato 
69643509a12Srenato 	if (--iface->group_count_v6 != 0)
69743509a12Srenato 		/* others still joined */
69843509a12Srenato 		return (0);
69943509a12Srenato 
70043509a12Srenato 	log_debug("%s: interface %s addr %s", __func__, iface->name,
70143509a12Srenato 	    log_in6addr(addr));
70243509a12Srenato 
70343509a12Srenato 	mreq.ipv6mr_multiaddr = *addr;
70443509a12Srenato 	mreq.ipv6mr_interface = iface->ifindex;
70543509a12Srenato 
70602eb61efSrenato 	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
707df69c215Sderaadt 	    (void *)&mreq, sizeof(mreq)) == -1) {
70843509a12Srenato 		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
70943509a12Srenato 		    __func__, iface->name, log_in6addr(addr));
71043509a12Srenato 		return (-1);
71143509a12Srenato 	}
71243509a12Srenato 
71343509a12Srenato 	return (0);
71443509a12Srenato }
71543509a12Srenato 
71643509a12Srenato int
if_set_ipv6_mcast(struct iface * iface)71743509a12Srenato if_set_ipv6_mcast(struct iface *iface)
71843509a12Srenato {
71902eb61efSrenato 	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
720df69c215Sderaadt 	    &iface->ifindex, sizeof(iface->ifindex)) == -1) {
72144faa115Srenato 		log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
72243509a12Srenato 		    __func__, iface->name);
72343509a12Srenato 		return (-1);
72443509a12Srenato 	}
72543509a12Srenato 
72643509a12Srenato 	return (0);
72743509a12Srenato }
72843509a12Srenato 
72943509a12Srenato int
if_set_ipv6_mcast_loop(int fd)73043509a12Srenato if_set_ipv6_mcast_loop(int fd)
73143509a12Srenato {
73243509a12Srenato 	unsigned int	loop = 0;
73343509a12Srenato 
73443509a12Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
735df69c215Sderaadt 	    (unsigned int *)&loop, sizeof(loop)) == -1) {
73643509a12Srenato 		log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
73743509a12Srenato 		return (-1);
73843509a12Srenato 	}
73943509a12Srenato 
74043509a12Srenato 	return (0);
74143509a12Srenato }
74243509a12Srenato 
74343509a12Srenato int
if_set_ipv6_pktinfo(int fd,int enable)74443509a12Srenato if_set_ipv6_pktinfo(int fd, int enable)
74543509a12Srenato {
74643509a12Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
747df69c215Sderaadt 	    sizeof(enable)) == -1) {
748bce3b5b3Srenato 		log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
74943509a12Srenato 		return (-1);
75043509a12Srenato 	}
75143509a12Srenato 
75243509a12Srenato 	return (0);
75343509a12Srenato }
75443509a12Srenato 
75543509a12Srenato int
if_set_ipv6_dscp(int fd,int dscp)75643509a12Srenato if_set_ipv6_dscp(int fd, int dscp)
75743509a12Srenato {
75843509a12Srenato 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
759df69c215Sderaadt 	    sizeof(dscp)) == -1) {
76043509a12Srenato 		log_warn("%s: error setting IPV6_TCLASS", __func__);
76143509a12Srenato 		return (-1);
76243509a12Srenato 	}
76343509a12Srenato 
76443509a12Srenato 	return (0);
76543509a12Srenato }
766