xref: /openbsd/usr.sbin/eigrpd/eigrpe.c (revision 95e9ede3)
1 /*	$OpenBSD: eigrpe.c,v 1.41 2023/12/14 11:09:56 claudio 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 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 
26 #include <arpa/inet.h>
27 #include <errno.h>
28 #include <pwd.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "eigrpd.h"
35 #include "eigrpe.h"
36 #include "rde.h"
37 #include "log.h"
38 #include "control.h"
39 
40 static void		 eigrpe_sig_handler(int, short, void *);
41 static __dead void	 eigrpe_shutdown(void);
42 static void		 eigrpe_dispatch_main(int, short, void *);
43 static void		 eigrpe_dispatch_rde(int, short, void *);
44 
45 struct eigrpd_conf	*econf;
46 
47 static struct event	 ev4;
48 static struct event	 ev6;
49 static struct imsgev	*iev_main;
50 static struct imsgev	*iev_rde;
51 
52 static void
eigrpe_sig_handler(int sig,short event,void * bula)53 eigrpe_sig_handler(int sig, short event, void *bula)
54 {
55 	switch (sig) {
56 	case SIGINT:
57 	case SIGTERM:
58 		eigrpe_shutdown();
59 		/* NOTREACHED */
60 	default:
61 		fatalx("unexpected signal");
62 	}
63 }
64 
65 /* eigrp engine */
66 void
eigrpe(int debug,int verbose,char * sockname)67 eigrpe(int debug, int verbose, char *sockname)
68 {
69 	struct passwd		*pw;
70 	struct event		 ev_sigint, ev_sigterm;
71 
72 	econf = config_new_empty();
73 
74 	log_init(debug);
75 	log_verbose(verbose);
76 
77 	/* create eigrpd control socket outside chroot */
78 	if (control_init(sockname) == -1)
79 		fatalx("control socket setup failed");
80 
81 	if (inet_pton(AF_INET, AllEIGRPRouters_v4, &global.mcast_addr_v4) != 1)
82 		fatal("inet_pton");
83 	if (inet_pton(AF_INET6, AllEIGRPRouters_v6, &global.mcast_addr_v6) != 1)
84 		fatal("inet_pton");
85 
86 	/* create the raw ipv4 socket */
87 	if ((global.eigrp_socket_v4 = socket(AF_INET,
88 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
89 		fatal("error creating raw ipv4 socket");
90 
91 	/* set some defaults */
92 	if (if_set_ipv4_mcast_ttl(global.eigrp_socket_v4, EIGRP_IP_TTL) == -1)
93 		fatal("if_set_ipv4_mcast_ttl");
94 	if (if_set_ipv4_mcast_loop(global.eigrp_socket_v4) == -1)
95 		fatal("if_set_ipv4_mcast_loop");
96 	if (if_set_ipv4_recvif(global.eigrp_socket_v4, 1) == -1)
97 		fatal("if_set_ipv4_recvif");
98 	if (if_set_ipv4_hdrincl(global.eigrp_socket_v4) == -1)
99 		fatal("if_set_ipv4_hdrincl");
100 	if_set_sockbuf(global.eigrp_socket_v4);
101 
102 	/* create the raw ipv6 socket */
103 	if ((global.eigrp_socket_v6 = socket(AF_INET6,
104 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
105 		fatal("error creating raw ipv6 socket");
106 
107 	/* set some defaults */
108 	if (if_set_ipv6_mcast_loop(global.eigrp_socket_v6) == -1)
109 		fatal("if_set_ipv6_mcast_loop");
110 	if (if_set_ipv6_pktinfo(global.eigrp_socket_v6, 1) == -1)
111 		fatal("if_set_ipv6_pktinfo");
112 	if (if_set_ipv6_dscp(global.eigrp_socket_v6,
113 	    IPTOS_PREC_NETCONTROL) == -1)
114 		fatal("if_set_ipv6_dscp");
115 	if_set_sockbuf(global.eigrp_socket_v6);
116 
117 	if ((pw = getpwnam(EIGRPD_USER)) == NULL)
118 		fatal("getpwnam");
119 
120 	if (chroot(pw->pw_dir) == -1)
121 		fatal("chroot");
122 	if (chdir("/") == -1)
123 		fatal("chdir(\"/\")");
124 
125 	setproctitle("eigrp engine");
126 	log_procname = "eigrpe";
127 
128 	if (setgroups(1, &pw->pw_gid) ||
129 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
130 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
131 		fatal("can't drop privileges");
132 
133 	if (pledge("stdio inet mcast recvfd", NULL) == -1)
134 		fatal("pledge");
135 
136 	event_init();
137 
138 	/* setup signal handler */
139 	signal_set(&ev_sigint, SIGINT, eigrpe_sig_handler, NULL);
140 	signal_set(&ev_sigterm, SIGTERM, eigrpe_sig_handler, NULL);
141 	signal_add(&ev_sigint, NULL);
142 	signal_add(&ev_sigterm, NULL);
143 	signal(SIGPIPE, SIG_IGN);
144 	signal(SIGHUP, SIG_IGN);
145 
146 	/* setup pipe and event handler to the parent process */
147 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
148 		fatal(NULL);
149 	imsg_init(&iev_main->ibuf, 3);
150 	iev_main->handler = eigrpe_dispatch_main;
151 	iev_main->events = EV_READ;
152 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
153 	    iev_main->handler, iev_main);
154 	event_add(&iev_main->ev, NULL);
155 
156 	event_set(&ev4, global.eigrp_socket_v4, EV_READ|EV_PERSIST,
157 	    recv_packet, econf);
158 	event_add(&ev4, NULL);
159 
160 	event_set(&ev6, global.eigrp_socket_v6, EV_READ|EV_PERSIST,
161 	    recv_packet, econf);
162 	event_add(&ev6, NULL);
163 
164 	/* listen on eigrpd control socket */
165 	control_listen();
166 
167 	event_dispatch();
168 
169 	eigrpe_shutdown();
170 }
171 
172 static __dead void
eigrpe_shutdown(void)173 eigrpe_shutdown(void)
174 {
175 	/* close pipes */
176 	msgbuf_write(&iev_rde->ibuf.w);
177 	msgbuf_clear(&iev_rde->ibuf.w);
178 	close(iev_rde->ibuf.fd);
179 	msgbuf_write(&iev_main->ibuf.w);
180 	msgbuf_clear(&iev_main->ibuf.w);
181 	close(iev_main->ibuf.fd);
182 
183 	config_clear(econf, PROC_EIGRP_ENGINE);
184 
185 	event_del(&ev4);
186 	event_del(&ev6);
187 	close(global.eigrp_socket_v4);
188 	close(global.eigrp_socket_v6);
189 
190 	/* clean up */
191 	free(iev_rde);
192 	free(iev_main);
193 
194 	log_info("eigrp engine exiting");
195 	exit(0);
196 }
197 
198 /* imesg */
199 int
eigrpe_imsg_compose_parent(int type,pid_t pid,void * data,uint16_t datalen)200 eigrpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
201 {
202 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
203 }
204 
205 int
eigrpe_imsg_compose_rde(int type,uint32_t peerid,pid_t pid,void * data,uint16_t datalen)206 eigrpe_imsg_compose_rde(int type, uint32_t peerid, pid_t pid,
207     void *data, uint16_t datalen)
208 {
209 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
210 	    data, datalen));
211 }
212 
213 static void
eigrpe_dispatch_main(int fd,short event,void * bula)214 eigrpe_dispatch_main(int fd, short event, void *bula)
215 {
216 	static struct eigrpd_conf *nconf;
217 	static struct iface	*niface;
218 	static struct eigrp	*neigrp;
219 	struct eigrp_iface	*nei;
220 	struct imsg		 imsg;
221 	struct imsgev		*iev = bula;
222 	struct imsgbuf		*ibuf = &iev->ibuf;
223 	struct iface		*iface = NULL;
224 	struct kif		*kif;
225 	struct kaddr		*ka;
226 	int			 n, shut = 0;
227 
228 	if (event & EV_READ) {
229 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
230 			fatal("imsg_read error");
231 		if (n == 0)	/* connection closed */
232 			shut = 1;
233 	}
234 	if (event & EV_WRITE) {
235 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
236 			fatal("msgbuf_write");
237 		if (n == 0)	/* connection closed */
238 			shut = 1;
239 	}
240 
241 	for (;;) {
242 		if ((n = imsg_get(ibuf, &imsg)) == -1)
243 			fatal("eigrpe_dispatch_main: imsg_get error");
244 		if (n == 0)
245 			break;
246 
247 		switch (imsg.hdr.type) {
248 		case IMSG_IFINFO:
249 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
250 			    sizeof(struct kif))
251 				fatalx("IFSTATUS imsg with wrong len");
252 			kif = imsg.data;
253 
254 			iface = if_lookup(econf, kif->ifindex);
255 			if (!iface)
256 				break;
257 
258 			iface->flags = kif->flags;
259 			iface->linkstate = kif->link_state;
260 			if_update(iface, AF_UNSPEC);
261 			break;
262 		case IMSG_NEWADDR:
263 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
264 			    sizeof(struct kaddr))
265 				fatalx("NEWADDR imsg with wrong len");
266 			ka = imsg.data;
267 
268 			iface = if_lookup(econf, ka->ifindex);
269 			if (iface == NULL)
270 				break;
271 
272 			if_addr_new(iface, ka);
273 			break;
274 		case IMSG_DELADDR:
275 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
276 			    sizeof(struct kaddr))
277 				fatalx("DELADDR imsg with wrong len");
278 			ka = imsg.data;
279 
280 			iface = if_lookup(econf, ka->ifindex);
281 			if (iface == NULL)
282 				break;
283 
284 			if_addr_del(iface, ka);
285 			break;
286 		case IMSG_SOCKET_IPC:
287 			if (iev_rde) {
288 				log_warnx("%s: received unexpected imsg fd "
289 				    "to rde", __func__);
290 				break;
291 			}
292 			if ((fd = imsg_get_fd(&imsg)) == -1) {
293 				log_warnx("%s: expected to receive imsg fd to "
294 				    "rde but didn't receive any", __func__);
295 				break;
296 			}
297 
298 			iev_rde = malloc(sizeof(struct imsgev));
299 			if (iev_rde == NULL)
300 				fatal(NULL);
301 			imsg_init(&iev_rde->ibuf, fd);
302 			iev_rde->handler = eigrpe_dispatch_rde;
303 			iev_rde->events = EV_READ;
304 			event_set(&iev_rde->ev, iev_rde->ibuf.fd,
305 			    iev_rde->events, iev_rde->handler, iev_rde);
306 			event_add(&iev_rde->ev, NULL);
307 			break;
308 		case IMSG_RECONF_CONF:
309 			if ((nconf = malloc(sizeof(struct eigrpd_conf))) ==
310 			    NULL)
311 				fatal(NULL);
312 			memcpy(nconf, imsg.data, sizeof(struct eigrpd_conf));
313 
314 			TAILQ_INIT(&nconf->iface_list);
315 			TAILQ_INIT(&nconf->instances);
316 			break;
317 		case IMSG_RECONF_INSTANCE:
318 			if ((neigrp = malloc(sizeof(struct eigrp))) == NULL)
319 				fatal(NULL);
320 			memcpy(neigrp, imsg.data, sizeof(struct eigrp));
321 
322 			SIMPLEQ_INIT(&neigrp->redist_list);
323 			TAILQ_INIT(&neigrp->ei_list);
324 			RB_INIT(&neigrp->nbrs);
325 			RB_INIT(&neigrp->topology);
326 			TAILQ_INSERT_TAIL(&nconf->instances, neigrp, entry);
327 			break;
328 		case IMSG_RECONF_IFACE:
329 			niface = imsg.data;
330 			niface = if_lookup(nconf, niface->ifindex);
331 			if (niface)
332 				break;
333 
334 			if ((niface = malloc(sizeof(struct iface))) == NULL)
335 				fatal(NULL);
336 			memcpy(niface, imsg.data, sizeof(struct iface));
337 
338 			TAILQ_INIT(&niface->ei_list);
339 			TAILQ_INIT(&niface->addr_list);
340 			TAILQ_INSERT_TAIL(&nconf->iface_list, niface, entry);
341 			break;
342 		case IMSG_RECONF_EIGRP_IFACE:
343 			if (niface == NULL)
344 				break;
345 			if ((nei = malloc(sizeof(struct eigrp_iface))) == NULL)
346 				fatal(NULL);
347 			memcpy(nei, imsg.data, sizeof(struct eigrp_iface));
348 
349 			nei->iface = niface;
350 			nei->eigrp = neigrp;
351 			TAILQ_INIT(&nei->nbr_list);
352 			TAILQ_INIT(&nei->update_list);
353 			TAILQ_INIT(&nei->query_list);
354 			TAILQ_INIT(&nei->summary_list);
355 			TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry);
356 			TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry);
357 			if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) !=
358 			    NULL)
359 				fatalx("eigrpe_dispatch_main: "
360 				    "RB_INSERT(ifaces_by_id) failed");
361 			break;
362 		case IMSG_RECONF_END:
363 			merge_config(econf, nconf, PROC_EIGRP_ENGINE);
364 			nconf = NULL;
365 			break;
366 		case IMSG_CTL_KROUTE:
367 		case IMSG_CTL_IFINFO:
368 		case IMSG_CTL_END:
369 			control_imsg_relay(&imsg);
370 			break;
371 		default:
372 			log_debug("%s: error handling imsg %d", __func__,
373 			    imsg.hdr.type);
374 			break;
375 		}
376 		imsg_free(&imsg);
377 	}
378 	if (!shut)
379 		imsg_event_add(iev);
380 	else {
381 		/* this pipe is dead, so remove the event handler */
382 		event_del(&iev->ev);
383 		event_loopexit(NULL);
384 	}
385 }
386 
387 static void
eigrpe_dispatch_rde(int fd,short event,void * bula)388 eigrpe_dispatch_rde(int fd, short event, void *bula)
389 {
390 	struct imsgev		*iev = bula;
391 	struct imsgbuf		*ibuf = &iev->ibuf;
392 	struct imsg		 imsg;
393 	struct nbr		*nbr;
394 	struct eigrp_iface	*ei;
395 	struct rinfo		 rinfo;
396 	int			 n, shut = 0;
397 
398 	if (event & EV_READ) {
399 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
400 			fatal("imsg_read error");
401 		if (n == 0)	/* connection closed */
402 			shut = 1;
403 	}
404 	if (event & EV_WRITE) {
405 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
406 			fatal("msgbuf_write");
407 		if (n == 0)	/* connection closed */
408 			shut = 1;
409 	}
410 
411 	for (;;) {
412 		if ((n = imsg_get(ibuf, &imsg)) == -1)
413 			fatal("eigrpe_dispatch_rde: imsg_get error");
414 		if (n == 0)
415 			break;
416 
417 		switch (imsg.hdr.type) {
418 		case IMSG_SEND_UPDATE:
419 		case IMSG_SEND_QUERY:
420 		case IMSG_SEND_REPLY:
421 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
422 				fatalx("invalid size of rinfo");
423 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
424 
425 			nbr = nbr_find_peerid(imsg.hdr.peerid);
426 			if (nbr == NULL) {
427 				log_debug("%s: cannot find rde neighbor",
428 				    __func__);
429 				break;
430 			}
431 
432 			switch (imsg.hdr.type) {
433 			case IMSG_SEND_UPDATE:
434 				message_add(&nbr->update_list, &rinfo);
435 				break;
436 			case IMSG_SEND_QUERY:
437 				message_add(&nbr->query_list, &rinfo);
438 				break;
439 			case IMSG_SEND_REPLY:
440 				message_add(&nbr->reply_list, &rinfo);
441 				break;
442 			}
443 			break;
444 		case IMSG_SEND_MUPDATE:
445 		case IMSG_SEND_MQUERY:
446 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
447 				fatalx("invalid size of rinfo");
448 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
449 
450 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
451 			if (ei == NULL) {
452 				log_debug("%s: cannot find interface",
453 				    __func__);
454 				break;
455 			}
456 
457 			switch (imsg.hdr.type) {
458 			case IMSG_SEND_MUPDATE:
459 				message_add(&ei->update_list, &rinfo);
460 				break;
461 			case IMSG_SEND_MQUERY:
462 				message_add(&ei->query_list, &rinfo);
463 				break;
464 			}
465 			break;
466 		case IMSG_SEND_UPDATE_END:
467 		case IMSG_SEND_REPLY_END:
468 		case IMSG_SEND_SIAQUERY_END:
469 		case IMSG_SEND_SIAREPLY_END:
470 			nbr = nbr_find_peerid(imsg.hdr.peerid);
471 			if (nbr == NULL) {
472 				log_debug("%s: cannot find rde neighbor",
473 				    __func__);
474 				break;
475 			}
476 
477 			switch (imsg.hdr.type) {
478 			case IMSG_SEND_UPDATE_END:
479 				send_update(nbr->ei, nbr, 0, &nbr->update_list);
480 				message_list_clr(&nbr->update_list);
481 				break;
482 			case IMSG_SEND_REPLY_END:
483 				send_reply(nbr,  &nbr->reply_list, 0);
484 				message_list_clr(&nbr->reply_list);
485 				break;
486 			case IMSG_SEND_SIAQUERY_END:
487 				send_query(nbr->ei, nbr, &nbr->query_list, 1);
488 				message_list_clr(&nbr->query_list);
489 				break;
490 			case IMSG_SEND_SIAREPLY_END:
491 				send_reply(nbr, &nbr->reply_list, 1);
492 				message_list_clr(&nbr->reply_list);
493 				break;
494 			}
495 			break;
496 		case IMSG_SEND_MUPDATE_END:
497 		case IMSG_SEND_MQUERY_END:
498 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
499 			if (ei == NULL) {
500 				log_debug("%s: cannot find interface",
501 				    __func__);
502 				break;
503 			}
504 
505 			switch (imsg.hdr.type) {
506 			case IMSG_SEND_MUPDATE_END:
507 				send_update(ei, NULL, 0, &ei->update_list);
508 				message_list_clr(&ei->update_list);
509 				break;
510 			case IMSG_SEND_MQUERY_END:
511 				send_query(ei, NULL, &ei->query_list, 0);
512 				message_list_clr(&ei->query_list);
513 				break;
514 			}
515 			break;
516 		case IMSG_NEIGHBOR_DOWN:
517 			nbr = nbr_find_peerid(imsg.hdr.peerid);
518 			if (nbr == NULL) {
519 				log_debug("%s: cannot find rde neighbor",
520 				    __func__);
521 				break;
522 			}
523 			/* announce that this neighborship is dead */
524 			send_peerterm(nbr);
525 			nbr_del(nbr);
526 			break;
527 		case IMSG_CTL_SHOW_TOPOLOGY:
528 		case IMSG_CTL_END:
529 			control_imsg_relay(&imsg);
530 			break;
531 		default:
532 			log_debug("%s: error handling imsg %d", __func__,
533 			    imsg.hdr.type);
534 			break;
535 		}
536 		imsg_free(&imsg);
537 	}
538 	if (!shut)
539 		imsg_event_add(iev);
540 	else {
541 		/* this pipe is dead, so remove the event handler */
542 		event_del(&iev->ev);
543 		event_loopexit(NULL);
544 	}
545 }
546 
547 void
eigrpe_instance_init(struct eigrp * eigrp)548 eigrpe_instance_init(struct eigrp *eigrp)
549 {
550 }
551 
552 void
eigrpe_instance_del(struct eigrp * eigrp)553 eigrpe_instance_del(struct eigrp *eigrp)
554 {
555 	struct eigrp_iface	*ei;
556 
557 	while ((ei = TAILQ_FIRST(&eigrp->ei_list)) != NULL)
558 		eigrp_if_del(ei);
559 
560 	free(eigrp);
561 }
562 
563 void
message_add(struct rinfo_head * rinfo_list,struct rinfo * rinfo)564 message_add(struct rinfo_head *rinfo_list, struct rinfo *rinfo)
565 {
566 	struct rinfo_entry	*re;
567 
568 	re = calloc(1, sizeof(*re));
569 	if (re == NULL)
570 		fatal("message_add");
571 	re->rinfo = *rinfo;
572 
573 	TAILQ_INSERT_TAIL(rinfo_list, re, entry);
574 }
575 
576 void
message_list_clr(struct rinfo_head * rinfo_list)577 message_list_clr(struct rinfo_head *rinfo_list)
578 {
579 	struct rinfo_entry	*re;
580 
581 	while ((re = TAILQ_FIRST(rinfo_list)) != NULL) {
582 		TAILQ_REMOVE(rinfo_list, re, entry);
583 		free(re);
584 	}
585 }
586 
587 void
seq_addr_list_clr(struct seq_addr_head * seq_addr_list)588 seq_addr_list_clr(struct seq_addr_head *seq_addr_list)
589 {
590 	struct seq_addr_entry	*sa;
591 
592 	while ((sa = TAILQ_FIRST(seq_addr_list)) != NULL) {
593 		TAILQ_REMOVE(seq_addr_list, sa, entry);
594 		free(sa);
595 	}
596 }
597 
598 void
eigrpe_orig_local_route(struct eigrp_iface * ei,struct if_addr * if_addr,int withdraw)599 eigrpe_orig_local_route(struct eigrp_iface *ei, struct if_addr *if_addr,
600     int withdraw)
601 {
602 	struct rinfo	 rinfo;
603 
604 	memset(&rinfo, 0, sizeof(rinfo));
605 	rinfo.af = if_addr->af;
606 	rinfo.type = EIGRP_ROUTE_INTERNAL;
607 	rinfo.prefix = if_addr->addr;
608 	rinfo.prefixlen = if_addr->prefixlen;
609 
610 	eigrp_applymask(rinfo.af, &rinfo.prefix, &rinfo.prefix,
611 	    rinfo.prefixlen);
612 
613 	if (withdraw)
614 		rinfo.metric.delay = EIGRP_INFINITE_METRIC;
615 	else
616 		rinfo.metric.delay = eigrp_composite_delay(ei->delay);
617 	rinfo.metric.bandwidth = eigrp_composite_bandwidth(ei->bandwidth);
618 	metric_encode_mtu(rinfo.metric.mtu, ei->iface->mtu);
619 	rinfo.metric.hop_count = 0;
620 	rinfo.metric.reliability = DEFAULT_RELIABILITY;
621 	rinfo.metric.load = DEFAULT_LOAD;
622 	rinfo.metric.tag = 0;
623 	rinfo.metric.flags = 0;
624 
625 	eigrpe_imsg_compose_rde(IMSG_RECV_UPDATE, ei->self->peerid, 0,
626 	    &rinfo, sizeof(rinfo));
627 }
628 
629 void
eigrpe_iface_ctl(struct ctl_conn * c,unsigned int idx)630 eigrpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
631 {
632 	struct eigrp		*eigrp;
633 	struct eigrp_iface	*ei;
634 	struct ctl_iface	*ictl;
635 
636 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
637 		TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) {
638 			if (idx == 0 || idx == ei->iface->ifindex) {
639 				ictl = if_to_ctl(ei);
640 				imsg_compose_event(&c->iev,
641 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
642 				    ictl, sizeof(struct ctl_iface));
643 			}
644 		}
645 	}
646 }
647 
648 void
eigrpe_nbr_ctl(struct ctl_conn * c)649 eigrpe_nbr_ctl(struct ctl_conn *c)
650 {
651 	struct eigrp	*eigrp;
652 	struct nbr	*nbr;
653 	struct ctl_nbr	*nctl;
654 
655 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
656 		RB_FOREACH(nbr, nbr_addr_head, &eigrp->nbrs) {
657 			if (nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF))
658 				continue;
659 
660 			nctl = nbr_to_ctl(nbr);
661 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0,
662 			    0, -1, nctl, sizeof(struct ctl_nbr));
663 		}
664 	}
665 
666 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
667 }
668 
669 void
eigrpe_stats_ctl(struct ctl_conn * c)670 eigrpe_stats_ctl(struct ctl_conn *c)
671 {
672 	struct eigrp		*eigrp;
673 	struct ctl_stats	 sctl;
674 
675 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
676 		sctl.af = eigrp->af;
677 		sctl.as = eigrp->as;
678 		sctl.stats = eigrp->stats;
679 		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_STATS, 0,
680 		    0, -1, &sctl, sizeof(struct ctl_stats));
681 	}
682 
683 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
684 }
685