xref: /openbsd-src/usr.sbin/eigrpd/eigrpe.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: eigrpe.c,v 1.47 2024/11/21 13:38:14 claudio 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 Esben Norby <norby@openbsd.org>
743509a12Srenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
843509a12Srenato  *
943509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
1043509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
1143509a12Srenato  * copyright notice and this permission notice appear in all copies.
1243509a12Srenato  *
1343509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1443509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1543509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1643509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1743509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1843509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1943509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2043509a12Srenato  */
2143509a12Srenato 
228072de9bSrenato #include <sys/types.h>
238072de9bSrenato #include <netinet/in.h>
248072de9bSrenato #include <netinet/ip.h>
2543509a12Srenato 
268072de9bSrenato #include <arpa/inet.h>
278072de9bSrenato #include <errno.h>
288072de9bSrenato #include <pwd.h>
298072de9bSrenato #include <signal.h>
308072de9bSrenato #include <stdlib.h>
318072de9bSrenato #include <string.h>
328072de9bSrenato #include <unistd.h>
338072de9bSrenato 
3443509a12Srenato #include "eigrpd.h"
3543509a12Srenato #include "eigrpe.h"
3643509a12Srenato #include "rde.h"
3743509a12Srenato #include "log.h"
388072de9bSrenato #include "control.h"
3943509a12Srenato 
40ab786365Srenato static void		 eigrpe_sig_handler(int, short, void *);
41ab786365Srenato static __dead void	 eigrpe_shutdown(void);
42ab786365Srenato static void		 eigrpe_dispatch_main(int, short, void *);
43ab786365Srenato static void		 eigrpe_dispatch_rde(int, short, void *);
44ab786365Srenato 
45ab786365Srenato struct eigrpd_conf	*econf;
4643509a12Srenato 
4743509a12Srenato static struct event	 ev4;
4843509a12Srenato static struct event	 ev6;
49ab786365Srenato static struct imsgev	*iev_main;
50ab786365Srenato static struct imsgev	*iev_rde;
5143509a12Srenato 
52ab786365Srenato static void
5343509a12Srenato eigrpe_sig_handler(int sig, short event, void *bula)
5443509a12Srenato {
5543509a12Srenato 	switch (sig) {
5643509a12Srenato 	case SIGINT:
5743509a12Srenato 	case SIGTERM:
5843509a12Srenato 		eigrpe_shutdown();
5943509a12Srenato 		/* NOTREACHED */
6043509a12Srenato 	default:
6143509a12Srenato 		fatalx("unexpected signal");
6243509a12Srenato 	}
6343509a12Srenato }
6443509a12Srenato 
6543509a12Srenato /* eigrp engine */
66a7928e1eSrenato void
67ed7fd2c0Srenato eigrpe(int debug, int verbose, char *sockname)
6843509a12Srenato {
6943509a12Srenato 	struct passwd		*pw;
7043509a12Srenato 	struct event		 ev_sigint, ev_sigterm;
7143509a12Srenato 
72ed7fd2c0Srenato 	econf = config_new_empty();
73ed7fd2c0Srenato 
74ed7fd2c0Srenato 	log_init(debug);
75ed7fd2c0Srenato 	log_verbose(verbose);
7643509a12Srenato 
7743509a12Srenato 	/* create eigrpd control socket outside chroot */
78d0f844f1Smestre 	if (control_init(sockname) == -1)
7943509a12Srenato 		fatalx("control socket setup failed");
8043509a12Srenato 
81e14e95d7Srenato 	if (inet_pton(AF_INET, AllEIGRPRouters_v4, &global.mcast_addr_v4) != 1)
82e14e95d7Srenato 		fatal("inet_pton");
83e14e95d7Srenato 	if (inet_pton(AF_INET6, AllEIGRPRouters_v6, &global.mcast_addr_v6) != 1)
84e14e95d7Srenato 		fatal("inet_pton");
85e14e95d7Srenato 
8643509a12Srenato 	/* create the raw ipv4 socket */
8702eb61efSrenato 	if ((global.eigrp_socket_v4 = socket(AF_INET,
8843509a12Srenato 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
8943509a12Srenato 		fatal("error creating raw ipv4 socket");
9043509a12Srenato 
9143509a12Srenato 	/* set some defaults */
9202eb61efSrenato 	if (if_set_ipv4_mcast_ttl(global.eigrp_socket_v4, EIGRP_IP_TTL) == -1)
9343509a12Srenato 		fatal("if_set_ipv4_mcast_ttl");
9402eb61efSrenato 	if (if_set_ipv4_mcast_loop(global.eigrp_socket_v4) == -1)
9543509a12Srenato 		fatal("if_set_ipv4_mcast_loop");
9602eb61efSrenato 	if (if_set_ipv4_recvif(global.eigrp_socket_v4, 1) == -1)
9743509a12Srenato 		fatal("if_set_ipv4_recvif");
9802eb61efSrenato 	if (if_set_ipv4_hdrincl(global.eigrp_socket_v4) == -1)
9943509a12Srenato 		fatal("if_set_ipv4_hdrincl");
10002eb61efSrenato 	if_set_sockbuf(global.eigrp_socket_v4);
10143509a12Srenato 
10243509a12Srenato 	/* create the raw ipv6 socket */
10302eb61efSrenato 	if ((global.eigrp_socket_v6 = socket(AF_INET6,
10443509a12Srenato 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
10543509a12Srenato 		fatal("error creating raw ipv6 socket");
10643509a12Srenato 
10743509a12Srenato 	/* set some defaults */
10802eb61efSrenato 	if (if_set_ipv6_mcast_loop(global.eigrp_socket_v6) == -1)
10943509a12Srenato 		fatal("if_set_ipv6_mcast_loop");
11002eb61efSrenato 	if (if_set_ipv6_pktinfo(global.eigrp_socket_v6, 1) == -1)
11143509a12Srenato 		fatal("if_set_ipv6_pktinfo");
11202eb61efSrenato 	if (if_set_ipv6_dscp(global.eigrp_socket_v6,
11343509a12Srenato 	    IPTOS_PREC_NETCONTROL) == -1)
11443509a12Srenato 		fatal("if_set_ipv6_dscp");
11502eb61efSrenato 	if_set_sockbuf(global.eigrp_socket_v6);
11643509a12Srenato 
11743509a12Srenato 	if ((pw = getpwnam(EIGRPD_USER)) == NULL)
11843509a12Srenato 		fatal("getpwnam");
11943509a12Srenato 
12043509a12Srenato 	if (chroot(pw->pw_dir) == -1)
12143509a12Srenato 		fatal("chroot");
12243509a12Srenato 	if (chdir("/") == -1)
12343509a12Srenato 		fatal("chdir(\"/\")");
12443509a12Srenato 
12543509a12Srenato 	setproctitle("eigrp engine");
126ac61aa8aSclaudio 	log_procname = "eigrpe";
12743509a12Srenato 
12843509a12Srenato 	if (setgroups(1, &pw->pw_gid) ||
12943509a12Srenato 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
13043509a12Srenato 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
13143509a12Srenato 		fatal("can't drop privileges");
13243509a12Srenato 
133abe347cfSmestre 	if (pledge("stdio inet mcast recvfd", NULL) == -1)
134c5bcf9a7Srenato 		fatal("pledge");
135c5bcf9a7Srenato 
13643509a12Srenato 	event_init();
13743509a12Srenato 
13843509a12Srenato 	/* setup signal handler */
13943509a12Srenato 	signal_set(&ev_sigint, SIGINT, eigrpe_sig_handler, NULL);
14043509a12Srenato 	signal_set(&ev_sigterm, SIGTERM, eigrpe_sig_handler, NULL);
14143509a12Srenato 	signal_add(&ev_sigint, NULL);
14243509a12Srenato 	signal_add(&ev_sigterm, NULL);
14343509a12Srenato 	signal(SIGPIPE, SIG_IGN);
14443509a12Srenato 	signal(SIGHUP, SIG_IGN);
14543509a12Srenato 
146ed7fd2c0Srenato 	/* setup pipe and event handler to the parent process */
147ed7fd2c0Srenato 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
14843509a12Srenato 		fatal(NULL);
149*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
150*f1b790a5Sclaudio 		fatal(NULL);
151*f1b790a5Sclaudio 	imsgbuf_allow_fdpass(&iev_main->ibuf);
15243509a12Srenato 	iev_main->handler = eigrpe_dispatch_main;
15343509a12Srenato 	iev_main->events = EV_READ;
15443509a12Srenato 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
15543509a12Srenato 	    iev_main->handler, iev_main);
15643509a12Srenato 	event_add(&iev_main->ev, NULL);
15743509a12Srenato 
15802eb61efSrenato 	event_set(&ev4, global.eigrp_socket_v4, EV_READ|EV_PERSIST,
159414c2f5bSrenato 	    recv_packet, econf);
16043509a12Srenato 	event_add(&ev4, NULL);
16143509a12Srenato 
16202eb61efSrenato 	event_set(&ev6, global.eigrp_socket_v6, EV_READ|EV_PERSIST,
163414c2f5bSrenato 	    recv_packet, econf);
16443509a12Srenato 	event_add(&ev6, NULL);
16543509a12Srenato 
16643509a12Srenato 	/* listen on eigrpd control socket */
16743509a12Srenato 	control_listen();
16843509a12Srenato 
16943509a12Srenato 	event_dispatch();
17043509a12Srenato 
17143509a12Srenato 	eigrpe_shutdown();
17243509a12Srenato }
17343509a12Srenato 
174ab786365Srenato static __dead void
17543509a12Srenato eigrpe_shutdown(void)
17643509a12Srenato {
177490a1964Srenato 	/* close pipes */
178dd7efffeSclaudio 	imsgbuf_write(&iev_rde->ibuf);
1799cbf9e90Sclaudio 	imsgbuf_clear(&iev_rde->ibuf);
180490a1964Srenato 	close(iev_rde->ibuf.fd);
181dd7efffeSclaudio 	imsgbuf_write(&iev_main->ibuf);
1829cbf9e90Sclaudio 	imsgbuf_clear(&iev_main->ibuf);
183490a1964Srenato 	close(iev_main->ibuf.fd);
18443509a12Srenato 
185ac61aa8aSclaudio 	config_clear(econf, PROC_EIGRP_ENGINE);
18643509a12Srenato 
18743509a12Srenato 	event_del(&ev4);
18843509a12Srenato 	event_del(&ev6);
18902eb61efSrenato 	close(global.eigrp_socket_v4);
19002eb61efSrenato 	close(global.eigrp_socket_v6);
19143509a12Srenato 
19243509a12Srenato 	/* clean up */
19343509a12Srenato 	free(iev_rde);
19443509a12Srenato 	free(iev_main);
19543509a12Srenato 
19643509a12Srenato 	log_info("eigrp engine exiting");
197beaf8b10Srenato 	exit(0);
19843509a12Srenato }
19943509a12Srenato 
20043509a12Srenato /* imesg */
20143509a12Srenato int
20243509a12Srenato eigrpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
20343509a12Srenato {
20443509a12Srenato 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
20543509a12Srenato }
20643509a12Srenato 
20743509a12Srenato int
20843509a12Srenato eigrpe_imsg_compose_rde(int type, uint32_t peerid, pid_t pid,
20943509a12Srenato     void *data, uint16_t datalen)
21043509a12Srenato {
21143509a12Srenato 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
21243509a12Srenato 	    data, datalen));
21343509a12Srenato }
21443509a12Srenato 
215ab786365Srenato static void
21643509a12Srenato eigrpe_dispatch_main(int fd, short event, void *bula)
21743509a12Srenato {
2185425f012Srenato 	static struct eigrpd_conf *nconf;
2195425f012Srenato 	static struct iface	*niface;
22043509a12Srenato 	static struct eigrp	*neigrp;
22143509a12Srenato 	struct eigrp_iface	*nei;
22243509a12Srenato 	struct imsg		 imsg;
22343509a12Srenato 	struct imsgev		*iev = bula;
22443509a12Srenato 	struct imsgbuf		*ibuf = &iev->ibuf;
22543509a12Srenato 	struct iface		*iface = NULL;
22643509a12Srenato 	struct kif		*kif;
22743509a12Srenato 	struct kaddr		*ka;
22843509a12Srenato 	int			 n, shut = 0;
22943509a12Srenato 
23043509a12Srenato 	if (event & EV_READ) {
231668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
232dd7efffeSclaudio 			fatal("imsgbuf_read error");
23343509a12Srenato 		if (n == 0)	/* connection closed */
23443509a12Srenato 			shut = 1;
23543509a12Srenato 	}
23643509a12Srenato 	if (event & EV_WRITE) {
237dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
238c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
23943509a12Srenato 				shut = 1;
240c1aa9554Sclaudio 			else
241dd7efffeSclaudio 				fatal("imsgbuf_write");
242c1aa9554Sclaudio 		}
24343509a12Srenato 	}
24443509a12Srenato 
24543509a12Srenato 	for (;;) {
24643509a12Srenato 		if ((n = imsg_get(ibuf, &imsg)) == -1)
24789e951f9Sclaudio 			fatal("eigrpe_dispatch_main: imsg_get error");
24843509a12Srenato 		if (n == 0)
24943509a12Srenato 			break;
25043509a12Srenato 
25143509a12Srenato 		switch (imsg.hdr.type) {
25243509a12Srenato 		case IMSG_IFINFO:
25343509a12Srenato 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
25443509a12Srenato 			    sizeof(struct kif))
25543509a12Srenato 				fatalx("IFSTATUS imsg with wrong len");
25643509a12Srenato 			kif = imsg.data;
25743509a12Srenato 
25843509a12Srenato 			iface = if_lookup(econf, kif->ifindex);
25943509a12Srenato 			if (!iface)
26043509a12Srenato 				break;
26143509a12Srenato 
26243509a12Srenato 			iface->flags = kif->flags;
26343509a12Srenato 			iface->linkstate = kif->link_state;
26443509a12Srenato 			if_update(iface, AF_UNSPEC);
26543509a12Srenato 			break;
26643509a12Srenato 		case IMSG_NEWADDR:
26743509a12Srenato 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
26843509a12Srenato 			    sizeof(struct kaddr))
26943509a12Srenato 				fatalx("NEWADDR imsg with wrong len");
27043509a12Srenato 			ka = imsg.data;
27143509a12Srenato 
27243509a12Srenato 			iface = if_lookup(econf, ka->ifindex);
27343509a12Srenato 			if (iface == NULL)
27443509a12Srenato 				break;
27543509a12Srenato 
27643509a12Srenato 			if_addr_new(iface, ka);
27743509a12Srenato 			break;
27843509a12Srenato 		case IMSG_DELADDR:
27943509a12Srenato 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
28043509a12Srenato 			    sizeof(struct kaddr))
28143509a12Srenato 				fatalx("DELADDR imsg with wrong len");
28243509a12Srenato 			ka = imsg.data;
28343509a12Srenato 
28443509a12Srenato 			iface = if_lookup(econf, ka->ifindex);
28543509a12Srenato 			if (iface == NULL)
28643509a12Srenato 				break;
28743509a12Srenato 
28843509a12Srenato 			if_addr_del(iface, ka);
28943509a12Srenato 			break;
290ed7fd2c0Srenato 		case IMSG_SOCKET_IPC:
291ed7fd2c0Srenato 			if (iev_rde) {
292ed7fd2c0Srenato 				log_warnx("%s: received unexpected imsg fd "
293ed7fd2c0Srenato 				    "to rde", __func__);
294ed7fd2c0Srenato 				break;
295ed7fd2c0Srenato 			}
29695e9ede3Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1) {
297ed7fd2c0Srenato 				log_warnx("%s: expected to receive imsg fd to "
298ed7fd2c0Srenato 				    "rde but didn't receive any", __func__);
299ed7fd2c0Srenato 				break;
300ed7fd2c0Srenato 			}
301ed7fd2c0Srenato 
302ed7fd2c0Srenato 			iev_rde = malloc(sizeof(struct imsgev));
303ed7fd2c0Srenato 			if (iev_rde == NULL)
304ed7fd2c0Srenato 				fatal(NULL);
305*f1b790a5Sclaudio 			if (imsgbuf_init(&iev_rde->ibuf, fd) == -1)
306*f1b790a5Sclaudio 				fatal(NULL);
307ed7fd2c0Srenato 			iev_rde->handler = eigrpe_dispatch_rde;
308ed7fd2c0Srenato 			iev_rde->events = EV_READ;
309ed7fd2c0Srenato 			event_set(&iev_rde->ev, iev_rde->ibuf.fd,
310ed7fd2c0Srenato 			    iev_rde->events, iev_rde->handler, iev_rde);
311ed7fd2c0Srenato 			event_add(&iev_rde->ev, NULL);
312ed7fd2c0Srenato 			break;
31343509a12Srenato 		case IMSG_RECONF_CONF:
31443509a12Srenato 			if ((nconf = malloc(sizeof(struct eigrpd_conf))) ==
31543509a12Srenato 			    NULL)
31643509a12Srenato 				fatal(NULL);
31743509a12Srenato 			memcpy(nconf, imsg.data, sizeof(struct eigrpd_conf));
31843509a12Srenato 
31943509a12Srenato 			TAILQ_INIT(&nconf->iface_list);
32043509a12Srenato 			TAILQ_INIT(&nconf->instances);
32143509a12Srenato 			break;
32243509a12Srenato 		case IMSG_RECONF_INSTANCE:
32343509a12Srenato 			if ((neigrp = malloc(sizeof(struct eigrp))) == NULL)
32443509a12Srenato 				fatal(NULL);
32543509a12Srenato 			memcpy(neigrp, imsg.data, sizeof(struct eigrp));
32643509a12Srenato 
32743509a12Srenato 			SIMPLEQ_INIT(&neigrp->redist_list);
32843509a12Srenato 			TAILQ_INIT(&neigrp->ei_list);
32943509a12Srenato 			RB_INIT(&neigrp->nbrs);
33043509a12Srenato 			RB_INIT(&neigrp->topology);
33143509a12Srenato 			TAILQ_INSERT_TAIL(&nconf->instances, neigrp, entry);
33243509a12Srenato 			break;
33343509a12Srenato 		case IMSG_RECONF_IFACE:
33443509a12Srenato 			niface = imsg.data;
33543509a12Srenato 			niface = if_lookup(nconf, niface->ifindex);
33643509a12Srenato 			if (niface)
33743509a12Srenato 				break;
33843509a12Srenato 
33943509a12Srenato 			if ((niface = malloc(sizeof(struct iface))) == NULL)
34043509a12Srenato 				fatal(NULL);
34143509a12Srenato 			memcpy(niface, imsg.data, sizeof(struct iface));
34243509a12Srenato 
34336dfa452Srenato 			TAILQ_INIT(&niface->ei_list);
34443509a12Srenato 			TAILQ_INIT(&niface->addr_list);
34543509a12Srenato 			TAILQ_INSERT_TAIL(&nconf->iface_list, niface, entry);
34643509a12Srenato 			break;
34743509a12Srenato 		case IMSG_RECONF_EIGRP_IFACE:
3483c8071b0Srenato 			if (niface == NULL)
3493c8071b0Srenato 				break;
35043509a12Srenato 			if ((nei = malloc(sizeof(struct eigrp_iface))) == NULL)
35143509a12Srenato 				fatal(NULL);
35243509a12Srenato 			memcpy(nei, imsg.data, sizeof(struct eigrp_iface));
35343509a12Srenato 
35443509a12Srenato 			nei->iface = niface;
35543509a12Srenato 			nei->eigrp = neigrp;
35643509a12Srenato 			TAILQ_INIT(&nei->nbr_list);
35743509a12Srenato 			TAILQ_INIT(&nei->update_list);
35843509a12Srenato 			TAILQ_INIT(&nei->query_list);
359bc6e1915Srenato 			TAILQ_INIT(&nei->summary_list);
36043509a12Srenato 			TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry);
36143509a12Srenato 			TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry);
36243509a12Srenato 			if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) !=
36343509a12Srenato 			    NULL)
364bce3b5b3Srenato 				fatalx("eigrpe_dispatch_main: "
36543509a12Srenato 				    "RB_INSERT(ifaces_by_id) failed");
36643509a12Srenato 			break;
36743509a12Srenato 		case IMSG_RECONF_END:
368ac61aa8aSclaudio 			merge_config(econf, nconf, PROC_EIGRP_ENGINE);
36943509a12Srenato 			nconf = NULL;
37043509a12Srenato 			break;
37143509a12Srenato 		case IMSG_CTL_KROUTE:
37243509a12Srenato 		case IMSG_CTL_IFINFO:
37343509a12Srenato 		case IMSG_CTL_END:
37443509a12Srenato 			control_imsg_relay(&imsg);
37543509a12Srenato 			break;
37643509a12Srenato 		default:
37743509a12Srenato 			log_debug("%s: error handling imsg %d", __func__,
37843509a12Srenato 			    imsg.hdr.type);
37943509a12Srenato 			break;
38043509a12Srenato 		}
38143509a12Srenato 		imsg_free(&imsg);
38243509a12Srenato 	}
38343509a12Srenato 	if (!shut)
38443509a12Srenato 		imsg_event_add(iev);
3853cd25924Srenato 	else {
3863cd25924Srenato 		/* this pipe is dead, so remove the event handler */
3873cd25924Srenato 		event_del(&iev->ev);
3883cd25924Srenato 		event_loopexit(NULL);
3893cd25924Srenato 	}
39043509a12Srenato }
39143509a12Srenato 
392ab786365Srenato static void
39343509a12Srenato eigrpe_dispatch_rde(int fd, short event, void *bula)
39443509a12Srenato {
39543509a12Srenato 	struct imsgev		*iev = bula;
39643509a12Srenato 	struct imsgbuf		*ibuf = &iev->ibuf;
39743509a12Srenato 	struct imsg		 imsg;
39843509a12Srenato 	struct nbr		*nbr;
39943509a12Srenato 	struct eigrp_iface	*ei;
40043509a12Srenato 	struct rinfo		 rinfo;
40143509a12Srenato 	int			 n, shut = 0;
40243509a12Srenato 
40343509a12Srenato 	if (event & EV_READ) {
404668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
405dd7efffeSclaudio 			fatal("imsgbuf_read error");
40643509a12Srenato 		if (n == 0)	/* connection closed */
40743509a12Srenato 			shut = 1;
40843509a12Srenato 	}
40943509a12Srenato 	if (event & EV_WRITE) {
410dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
411c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
41243509a12Srenato 				shut = 1;
413c1aa9554Sclaudio 			else
414dd7efffeSclaudio 				fatal("imsgbuf_write");
415c1aa9554Sclaudio 		}
41643509a12Srenato 	}
41743509a12Srenato 
41843509a12Srenato 	for (;;) {
41943509a12Srenato 		if ((n = imsg_get(ibuf, &imsg)) == -1)
42089e951f9Sclaudio 			fatal("eigrpe_dispatch_rde: imsg_get error");
42143509a12Srenato 		if (n == 0)
42243509a12Srenato 			break;
42343509a12Srenato 
42443509a12Srenato 		switch (imsg.hdr.type) {
42543509a12Srenato 		case IMSG_SEND_UPDATE:
42643509a12Srenato 		case IMSG_SEND_QUERY:
42743509a12Srenato 		case IMSG_SEND_REPLY:
42843509a12Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
42943509a12Srenato 				fatalx("invalid size of rinfo");
43043509a12Srenato 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
43143509a12Srenato 
43243509a12Srenato 			nbr = nbr_find_peerid(imsg.hdr.peerid);
43343509a12Srenato 			if (nbr == NULL) {
43443509a12Srenato 				log_debug("%s: cannot find rde neighbor",
43543509a12Srenato 				    __func__);
43643509a12Srenato 				break;
43743509a12Srenato 			}
43843509a12Srenato 
43943509a12Srenato 			switch (imsg.hdr.type) {
44043509a12Srenato 			case IMSG_SEND_UPDATE:
44143509a12Srenato 				message_add(&nbr->update_list, &rinfo);
44243509a12Srenato 				break;
44343509a12Srenato 			case IMSG_SEND_QUERY:
44443509a12Srenato 				message_add(&nbr->query_list, &rinfo);
44543509a12Srenato 				break;
44643509a12Srenato 			case IMSG_SEND_REPLY:
44743509a12Srenato 				message_add(&nbr->reply_list, &rinfo);
44843509a12Srenato 				break;
44943509a12Srenato 			}
45043509a12Srenato 			break;
45143509a12Srenato 		case IMSG_SEND_MUPDATE:
45243509a12Srenato 		case IMSG_SEND_MQUERY:
45343509a12Srenato 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
45443509a12Srenato 				fatalx("invalid size of rinfo");
45543509a12Srenato 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
45643509a12Srenato 
4572e046f62Srenato 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
45843509a12Srenato 			if (ei == NULL) {
45943509a12Srenato 				log_debug("%s: cannot find interface",
46043509a12Srenato 				    __func__);
46143509a12Srenato 				break;
46243509a12Srenato 			}
46343509a12Srenato 
46443509a12Srenato 			switch (imsg.hdr.type) {
46543509a12Srenato 			case IMSG_SEND_MUPDATE:
46643509a12Srenato 				message_add(&ei->update_list, &rinfo);
46743509a12Srenato 				break;
46843509a12Srenato 			case IMSG_SEND_MQUERY:
46943509a12Srenato 				message_add(&ei->query_list, &rinfo);
47043509a12Srenato 				break;
47143509a12Srenato 			}
47243509a12Srenato 			break;
47343509a12Srenato 		case IMSG_SEND_UPDATE_END:
47443509a12Srenato 		case IMSG_SEND_REPLY_END:
47543509a12Srenato 		case IMSG_SEND_SIAQUERY_END:
47643509a12Srenato 		case IMSG_SEND_SIAREPLY_END:
47743509a12Srenato 			nbr = nbr_find_peerid(imsg.hdr.peerid);
47843509a12Srenato 			if (nbr == NULL) {
47943509a12Srenato 				log_debug("%s: cannot find rde neighbor",
48043509a12Srenato 				    __func__);
48143509a12Srenato 				break;
48243509a12Srenato 			}
48343509a12Srenato 
48443509a12Srenato 			switch (imsg.hdr.type) {
48543509a12Srenato 			case IMSG_SEND_UPDATE_END:
4865c6a958cSrenato 				send_update(nbr->ei, nbr, 0, &nbr->update_list);
48743509a12Srenato 				message_list_clr(&nbr->update_list);
48843509a12Srenato 				break;
48943509a12Srenato 			case IMSG_SEND_REPLY_END:
49043509a12Srenato 				send_reply(nbr,  &nbr->reply_list, 0);
49143509a12Srenato 				message_list_clr(&nbr->reply_list);
49243509a12Srenato 				break;
49343509a12Srenato 			case IMSG_SEND_SIAQUERY_END:
49443509a12Srenato 				send_query(nbr->ei, nbr, &nbr->query_list, 1);
49543509a12Srenato 				message_list_clr(&nbr->query_list);
49643509a12Srenato 				break;
49743509a12Srenato 			case IMSG_SEND_SIAREPLY_END:
49843509a12Srenato 				send_reply(nbr, &nbr->reply_list, 1);
49943509a12Srenato 				message_list_clr(&nbr->reply_list);
50043509a12Srenato 				break;
50143509a12Srenato 			}
50243509a12Srenato 			break;
50343509a12Srenato 		case IMSG_SEND_MUPDATE_END:
50443509a12Srenato 		case IMSG_SEND_MQUERY_END:
5052e046f62Srenato 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
50643509a12Srenato 			if (ei == NULL) {
50743509a12Srenato 				log_debug("%s: cannot find interface",
50843509a12Srenato 				    __func__);
50943509a12Srenato 				break;
51043509a12Srenato 			}
51143509a12Srenato 
51243509a12Srenato 			switch (imsg.hdr.type) {
51343509a12Srenato 			case IMSG_SEND_MUPDATE_END:
5145c6a958cSrenato 				send_update(ei, NULL, 0, &ei->update_list);
51543509a12Srenato 				message_list_clr(&ei->update_list);
51643509a12Srenato 				break;
51743509a12Srenato 			case IMSG_SEND_MQUERY_END:
51843509a12Srenato 				send_query(ei, NULL, &ei->query_list, 0);
51943509a12Srenato 				message_list_clr(&ei->query_list);
52043509a12Srenato 				break;
52143509a12Srenato 			}
52243509a12Srenato 			break;
5233af0505bSrenato 		case IMSG_NEIGHBOR_DOWN:
5243af0505bSrenato 			nbr = nbr_find_peerid(imsg.hdr.peerid);
5253af0505bSrenato 			if (nbr == NULL) {
5263af0505bSrenato 				log_debug("%s: cannot find rde neighbor",
5273af0505bSrenato 				    __func__);
5283af0505bSrenato 				break;
5293af0505bSrenato 			}
5303af0505bSrenato 			/* announce that this neighborship is dead */
5310e96235eSrenato 			send_peerterm(nbr);
5323af0505bSrenato 			nbr_del(nbr);
5333af0505bSrenato 			break;
53443509a12Srenato 		case IMSG_CTL_SHOW_TOPOLOGY:
53543509a12Srenato 		case IMSG_CTL_END:
53643509a12Srenato 			control_imsg_relay(&imsg);
53743509a12Srenato 			break;
53843509a12Srenato 		default:
53943509a12Srenato 			log_debug("%s: error handling imsg %d", __func__,
54043509a12Srenato 			    imsg.hdr.type);
54143509a12Srenato 			break;
54243509a12Srenato 		}
54343509a12Srenato 		imsg_free(&imsg);
54443509a12Srenato 	}
54543509a12Srenato 	if (!shut)
54643509a12Srenato 		imsg_event_add(iev);
5473cd25924Srenato 	else {
5483cd25924Srenato 		/* this pipe is dead, so remove the event handler */
5493cd25924Srenato 		event_del(&iev->ev);
5503cd25924Srenato 		event_loopexit(NULL);
5513cd25924Srenato 	}
55243509a12Srenato }
55343509a12Srenato 
55443509a12Srenato void
55543509a12Srenato eigrpe_instance_init(struct eigrp *eigrp)
55643509a12Srenato {
55743509a12Srenato }
55843509a12Srenato 
55943509a12Srenato void
56043509a12Srenato eigrpe_instance_del(struct eigrp *eigrp)
56143509a12Srenato {
56243509a12Srenato 	struct eigrp_iface	*ei;
56343509a12Srenato 
56443509a12Srenato 	while ((ei = TAILQ_FIRST(&eigrp->ei_list)) != NULL)
56543509a12Srenato 		eigrp_if_del(ei);
56643509a12Srenato 
56743509a12Srenato 	free(eigrp);
56843509a12Srenato }
56943509a12Srenato 
57043509a12Srenato void
57143509a12Srenato message_add(struct rinfo_head *rinfo_list, struct rinfo *rinfo)
57243509a12Srenato {
57343509a12Srenato 	struct rinfo_entry	*re;
57443509a12Srenato 
57543509a12Srenato 	re = calloc(1, sizeof(*re));
57643509a12Srenato 	if (re == NULL)
57743509a12Srenato 		fatal("message_add");
5783eb03b29Srenato 	re->rinfo = *rinfo;
57943509a12Srenato 
58043509a12Srenato 	TAILQ_INSERT_TAIL(rinfo_list, re, entry);
58143509a12Srenato }
58243509a12Srenato 
58343509a12Srenato void
58443509a12Srenato message_list_clr(struct rinfo_head *rinfo_list)
58543509a12Srenato {
58643509a12Srenato 	struct rinfo_entry	*re;
58743509a12Srenato 
58843509a12Srenato 	while ((re = TAILQ_FIRST(rinfo_list)) != NULL) {
58943509a12Srenato 		TAILQ_REMOVE(rinfo_list, re, entry);
59043509a12Srenato 		free(re);
59143509a12Srenato 	}
59243509a12Srenato }
59343509a12Srenato 
59443509a12Srenato void
59543509a12Srenato seq_addr_list_clr(struct seq_addr_head *seq_addr_list)
59643509a12Srenato {
59743509a12Srenato 	struct seq_addr_entry	*sa;
59843509a12Srenato 
59943509a12Srenato 	while ((sa = TAILQ_FIRST(seq_addr_list)) != NULL) {
60043509a12Srenato 		TAILQ_REMOVE(seq_addr_list, sa, entry);
60143509a12Srenato 		free(sa);
60243509a12Srenato 	}
60343509a12Srenato }
60443509a12Srenato 
60543509a12Srenato void
60643509a12Srenato eigrpe_orig_local_route(struct eigrp_iface *ei, struct if_addr *if_addr,
60743509a12Srenato     int withdraw)
60843509a12Srenato {
60943509a12Srenato 	struct rinfo	 rinfo;
61043509a12Srenato 
61143509a12Srenato 	memset(&rinfo, 0, sizeof(rinfo));
61243509a12Srenato 	rinfo.af = if_addr->af;
61343509a12Srenato 	rinfo.type = EIGRP_ROUTE_INTERNAL;
6143eb03b29Srenato 	rinfo.prefix = if_addr->addr;
61543509a12Srenato 	rinfo.prefixlen = if_addr->prefixlen;
61643509a12Srenato 
61743509a12Srenato 	eigrp_applymask(rinfo.af, &rinfo.prefix, &rinfo.prefix,
61843509a12Srenato 	    rinfo.prefixlen);
61943509a12Srenato 
62043509a12Srenato 	if (withdraw)
62143509a12Srenato 		rinfo.metric.delay = EIGRP_INFINITE_METRIC;
62243509a12Srenato 	else
62343509a12Srenato 		rinfo.metric.delay = eigrp_composite_delay(ei->delay);
62443509a12Srenato 	rinfo.metric.bandwidth = eigrp_composite_bandwidth(ei->bandwidth);
62543509a12Srenato 	metric_encode_mtu(rinfo.metric.mtu, ei->iface->mtu);
62643509a12Srenato 	rinfo.metric.hop_count = 0;
62743509a12Srenato 	rinfo.metric.reliability = DEFAULT_RELIABILITY;
62843509a12Srenato 	rinfo.metric.load = DEFAULT_LOAD;
62943509a12Srenato 	rinfo.metric.tag = 0;
63043509a12Srenato 	rinfo.metric.flags = 0;
63143509a12Srenato 
63243509a12Srenato 	eigrpe_imsg_compose_rde(IMSG_RECV_UPDATE, ei->self->peerid, 0,
63343509a12Srenato 	    &rinfo, sizeof(rinfo));
63443509a12Srenato }
63543509a12Srenato 
63643509a12Srenato void
63743509a12Srenato eigrpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
63843509a12Srenato {
63943509a12Srenato 	struct eigrp		*eigrp;
64043509a12Srenato 	struct eigrp_iface	*ei;
64143509a12Srenato 	struct ctl_iface	*ictl;
64243509a12Srenato 
64343509a12Srenato 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
64443509a12Srenato 		TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) {
64543509a12Srenato 			if (idx == 0 || idx == ei->iface->ifindex) {
64643509a12Srenato 				ictl = if_to_ctl(ei);
64743509a12Srenato 				imsg_compose_event(&c->iev,
64843509a12Srenato 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
64943509a12Srenato 				    ictl, sizeof(struct ctl_iface));
65043509a12Srenato 			}
65143509a12Srenato 		}
65243509a12Srenato 	}
65343509a12Srenato }
65443509a12Srenato 
65543509a12Srenato void
65643509a12Srenato eigrpe_nbr_ctl(struct ctl_conn *c)
65743509a12Srenato {
65843509a12Srenato 	struct eigrp	*eigrp;
65943509a12Srenato 	struct nbr	*nbr;
66043509a12Srenato 	struct ctl_nbr	*nctl;
66143509a12Srenato 
66243509a12Srenato 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
66343509a12Srenato 		RB_FOREACH(nbr, nbr_addr_head, &eigrp->nbrs) {
66443509a12Srenato 			if (nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF))
66543509a12Srenato 				continue;
66643509a12Srenato 
66743509a12Srenato 			nctl = nbr_to_ctl(nbr);
66843509a12Srenato 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0,
66943509a12Srenato 			    0, -1, nctl, sizeof(struct ctl_nbr));
67043509a12Srenato 		}
67143509a12Srenato 	}
67243509a12Srenato 
67343509a12Srenato 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
67443509a12Srenato }
675dcfaa8d4Srenato 
676dcfaa8d4Srenato void
677dcfaa8d4Srenato eigrpe_stats_ctl(struct ctl_conn *c)
678dcfaa8d4Srenato {
679dcfaa8d4Srenato 	struct eigrp		*eigrp;
680dcfaa8d4Srenato 	struct ctl_stats	 sctl;
681dcfaa8d4Srenato 
682dcfaa8d4Srenato 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
683dcfaa8d4Srenato 		sctl.af = eigrp->af;
684dcfaa8d4Srenato 		sctl.as = eigrp->as;
6853eb03b29Srenato 		sctl.stats = eigrp->stats;
686dcfaa8d4Srenato 		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_STATS, 0,
687dcfaa8d4Srenato 		    0, -1, &sctl, sizeof(struct ctl_stats));
688dcfaa8d4Srenato 	}
689dcfaa8d4Srenato 
690dcfaa8d4Srenato 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
691dcfaa8d4Srenato }
692