GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/eigrpe.c Lines: 0 347 0.0 %
Date: 2017-11-13 Branches: 0 208 0.0 %

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