xref: /openbsd-src/usr.sbin/ospfd/ospfe.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: ospfe.c,v 1.111 2023/03/08 04:43:14 guenther Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/queue.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if_types.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <pwd.h>
32 #include <unistd.h>
33 #include <event.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <stdio.h>
37 
38 #include "ospf.h"
39 #include "ospfd.h"
40 #include "ospfe.h"
41 #include "rde.h"
42 #include "control.h"
43 #include "log.h"
44 
45 void		 ospfe_sig_handler(int, short, void *);
46 __dead void	 ospfe_shutdown(void);
47 void		 orig_rtr_lsa_all(struct area *);
48 struct iface	*find_vlink(struct abr_rtr *);
49 
50 struct ospfd_conf	*oeconf = NULL, *noeconf;
51 static struct imsgev	*iev_main;
52 static struct imsgev	*iev_rde;
53 int			 oe_nofib;
54 
55 void
56 ospfe_sig_handler(int sig, short event, void *bula)
57 {
58 	switch (sig) {
59 	case SIGINT:
60 	case SIGTERM:
61 		ospfe_shutdown();
62 		/* NOTREACHED */
63 	default:
64 		fatalx("unexpected signal");
65 	}
66 }
67 
68 /* ospf engine */
69 pid_t
70 ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2],
71     int pipe_parent2rde[2])
72 {
73 	struct area	*area;
74 	struct iface	*iface;
75 	struct redistribute *r;
76 	struct passwd	*pw;
77 	struct event	 ev_sigint, ev_sigterm;
78 	pid_t		 pid;
79 
80 	switch (pid = fork()) {
81 	case -1:
82 		fatal("cannot fork");
83 	case 0:
84 		break;
85 	default:
86 		return (pid);
87 	}
88 
89 	/* cleanup a bit */
90 	kif_clear();
91 
92 	/* create the raw ip socket */
93 	if ((xconf->ospf_socket = socket(AF_INET,
94 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
95 	    IPPROTO_OSPF)) == -1)
96 		fatal("error creating raw socket");
97 
98 	/* set some defaults */
99 	if (if_set_mcast_loop(xconf->ospf_socket) == -1)
100 		fatal("if_set_mcast_loop");
101 	if (if_set_ip_hdrincl(xconf->ospf_socket) == -1)
102 		fatal("if_set_ip_hdrincl");
103 	if (if_set_recvif(xconf->ospf_socket, 1) == -1)
104 		fatal("if_set_recvif");
105 	if_set_sockbuf(xconf->ospf_socket);
106 
107 	oeconf = xconf;
108 	if (oeconf->flags & OSPFD_FLAG_NO_FIB_UPDATE)
109 		oe_nofib = 1;
110 
111 	if ((pw = getpwnam(OSPFD_USER)) == NULL)
112 		fatal("getpwnam");
113 
114 	if (chroot(pw->pw_dir) == -1)
115 		fatal("chroot");
116 	if (chdir("/") == -1)
117 		fatal("chdir(\"/\")");
118 
119 	setproctitle("ospf engine");
120 	/*
121 	 * XXX needed with fork+exec
122 	 * log_init(debug, LOG_DAEMON);
123 	 * log_setverbose(verbose);
124 	 */
125 
126 	ospfd_process = PROC_OSPF_ENGINE;
127 	log_procinit(log_procnames[ospfd_process]);
128 
129 	if (setgroups(1, &pw->pw_gid) ||
130 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
131 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
132 		fatal("can't drop privileges");
133 
134 	if (pledge("stdio inet mcast recvfd", NULL) == -1)
135 		fatal("pledge");
136 
137 	event_init();
138 	nbr_init(NBR_HASHSIZE);
139 	lsa_cache_init(LSA_HASHSIZE);
140 
141 	/* setup signal handler */
142 	signal_set(&ev_sigint, SIGINT, ospfe_sig_handler, NULL);
143 	signal_set(&ev_sigterm, SIGTERM, ospfe_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 pipes */
150 	close(pipe_parent2ospfe[0]);
151 	close(pipe_ospfe2rde[1]);
152 	close(pipe_parent2rde[0]);
153 	close(pipe_parent2rde[1]);
154 
155 	if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL ||
156 	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
157 		fatal(NULL);
158 	imsg_init(&iev_rde->ibuf, pipe_ospfe2rde[0]);
159 	iev_rde->handler = ospfe_dispatch_rde;
160 	imsg_init(&iev_main->ibuf, pipe_parent2ospfe[1]);
161 	iev_main->handler = ospfe_dispatch_main;
162 
163 	/* setup event handler */
164 	iev_rde->events = EV_READ;
165 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
166 	    iev_rde->handler, iev_rde);
167 	event_add(&iev_rde->ev, NULL);
168 
169 	iev_main->events = EV_READ;
170 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
171 	    iev_main->handler, iev_main);
172 	event_add(&iev_main->ev, NULL);
173 
174 	event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST,
175 	    recv_packet, oeconf);
176 	event_add(&oeconf->ev, NULL);
177 
178 	/* remove unneeded config stuff */
179 	conf_clear_redist_list(&oeconf->redist_list);
180 	LIST_FOREACH(area, &oeconf->area_list, entry) {
181 		while ((r = SIMPLEQ_FIRST(&area->redist_list)) != NULL) {
182 			SIMPLEQ_REMOVE_HEAD(&area->redist_list, entry);
183 			free(r);
184 		}
185 	}
186 
187 	/* start interfaces */
188 	LIST_FOREACH(area, &oeconf->area_list, entry) {
189 		ospfe_demote_area(area, 0);
190 		LIST_FOREACH(iface, &area->iface_list, entry) {
191 			if_init(xconf, iface);
192 			if (if_fsm(iface, IF_EVT_UP)) {
193 				log_debug("error starting interface %s",
194 				    iface->name);
195 			}
196 		}
197 	}
198 
199 	event_dispatch();
200 
201 	ospfe_shutdown();
202 	/* NOTREACHED */
203 	return (0);
204 }
205 
206 __dead void
207 ospfe_shutdown(void)
208 {
209 	struct area	*area;
210 	struct iface	*iface;
211 
212 	/* close pipes */
213 	msgbuf_write(&iev_rde->ibuf.w);
214 	msgbuf_clear(&iev_rde->ibuf.w);
215 	close(iev_rde->ibuf.fd);
216 	msgbuf_write(&iev_main->ibuf.w);
217 	msgbuf_clear(&iev_main->ibuf.w);
218 	close(iev_main->ibuf.fd);
219 
220 	/* stop all interfaces and remove all areas */
221 	while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) {
222 		LIST_FOREACH(iface, &area->iface_list, entry) {
223 			if (if_fsm(iface, IF_EVT_DOWN)) {
224 				log_debug("error stopping interface %s",
225 				    iface->name);
226 			}
227 		}
228 		LIST_REMOVE(area, entry);
229 		area_del(area);
230 	}
231 
232 	nbr_del(nbr_find_peerid(NBR_IDSELF));
233 	close(oeconf->ospf_socket);
234 
235 	/* clean up */
236 	free(iev_rde);
237 	free(iev_main);
238 	free(oeconf);
239 
240 	log_info("ospf engine exiting");
241 	_exit(0);
242 }
243 
244 /* imesg */
245 int
246 ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
247 {
248 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
249 }
250 
251 int
252 ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
253     void *data, u_int16_t datalen)
254 {
255 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
256 	    data, datalen));
257 }
258 
259 void
260 ospfe_dispatch_main(int fd, short event, void *bula)
261 {
262 	static struct area	*narea;
263 	static struct iface	*niface;
264 	struct ifaddrchange	*ifc;
265 	struct imsg	 imsg;
266 	struct imsgev	*iev = bula;
267 	struct imsgbuf	*ibuf = &iev->ibuf;
268 	struct area	*area = NULL;
269 	struct iface	*iface = NULL;
270 	struct kif	*kif;
271 	struct auth_md	 md;
272 	int		 n, link_ok, stub_changed, shut = 0;
273 
274 	if (event & EV_READ) {
275 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
276 			fatal("imsg_read error");
277 		if (n == 0)	/* connection closed */
278 			shut = 1;
279 	}
280 	if (event & EV_WRITE) {
281 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
282 			fatal("msgbuf_write");
283 		if (n == 0)	/* connection closed */
284 			shut = 1;
285 	}
286 
287 	for (;;) {
288 		if ((n = imsg_get(ibuf, &imsg)) == -1)
289 			fatal("ospfe_dispatch_main: imsg_get error");
290 		if (n == 0)
291 			break;
292 
293 		switch (imsg.hdr.type) {
294 		case IMSG_IFINFO:
295 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
296 			    sizeof(struct kif))
297 				fatalx("IFINFO imsg with wrong len");
298 			kif = imsg.data;
299 			link_ok = (kif->flags & IFF_UP) &&
300 			    LINK_STATE_IS_UP(kif->link_state);
301 
302 			LIST_FOREACH(area, &oeconf->area_list, entry) {
303 				LIST_FOREACH(iface, &area->iface_list, entry) {
304 					if (kif->ifindex == iface->ifindex &&
305 					    iface->type !=
306 					    IF_TYPE_VIRTUALLINK) {
307 						int prev_link_state =
308 						    (iface->flags & IFF_UP) &&
309 						    LINK_STATE_IS_UP(iface->linkstate);
310 
311 						iface->flags = kif->flags;
312 						iface->linkstate =
313 						    kif->link_state;
314 						iface->mtu = kif->mtu;
315 
316 						if (link_ok == prev_link_state)
317 							break;
318 
319 						if (link_ok) {
320 							if_fsm(iface,
321 							    IF_EVT_UP);
322 							log_warnx("interface %s"
323 							    " up", iface->name);
324 						} else {
325 							if_fsm(iface,
326 							    IF_EVT_DOWN);
327 							log_warnx("interface %s"
328 							    " down",
329 							    iface->name);
330 						}
331 					}
332 					if (strcmp(kif->ifname,
333 					    iface->dependon) == 0) {
334 						log_warnx("interface %s"
335 						    " changed state, %s"
336 						    " depends on it",
337 						    kif->ifname,
338 						    iface->name);
339 						iface->depend_ok =
340 						    ifstate_is_up(kif);
341 
342 						if ((iface->flags &
343 						    IFF_UP) &&
344 						    LINK_STATE_IS_UP(iface->linkstate))
345 							orig_rtr_lsa(iface->area);
346 					}
347 				}
348 			}
349 			break;
350 		case IMSG_IFADDRADD:
351 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
352 			    sizeof(struct ifaddrchange))
353 				fatalx("IFADDRADD imsg with wrong len");
354 			ifc = imsg.data;
355 
356 			LIST_FOREACH(area, &oeconf->area_list, entry) {
357 				LIST_FOREACH(iface, &area->iface_list, entry) {
358 					if (ifc->ifindex == iface->ifindex &&
359 					    ifc->addr.s_addr ==
360 					    iface->addr.s_addr) {
361 						iface->mask = ifc->mask;
362 						iface->dst = ifc->dst;
363 						/*
364 						 * Previous down event might
365 						 * have failed if the address
366 						 * was not present at that
367 						 * time.
368 						 */
369 						if_fsm(iface, IF_EVT_DOWN);
370 						if_fsm(iface, IF_EVT_UP);
371 						log_warnx("interface %s:%s "
372 						    "returned", iface->name,
373 						    inet_ntoa(iface->addr));
374 						break;
375 					}
376 				}
377 			}
378 			break;
379 		case IMSG_IFADDRDEL:
380 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
381 			    sizeof(struct ifaddrchange))
382 				fatalx("IFADDRDEL imsg with wrong len");
383 			ifc = imsg.data;
384 
385 			LIST_FOREACH(area, &oeconf->area_list, entry) {
386 				LIST_FOREACH(iface, &area->iface_list, entry) {
387 					if (ifc->ifindex == iface->ifindex &&
388 					    ifc->addr.s_addr ==
389 					    iface->addr.s_addr) {
390 						if_fsm(iface, IF_EVT_DOWN);
391 						log_warnx("interface %s:%s "
392 						    "gone", iface->name,
393 						    inet_ntoa(iface->addr));
394 						break;
395 					}
396 				}
397 			}
398 			break;
399 		case IMSG_RECONF_CONF:
400 			if ((noeconf = malloc(sizeof(struct ospfd_conf))) ==
401 			    NULL)
402 				fatal(NULL);
403 			memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf));
404 
405 			LIST_INIT(&noeconf->area_list);
406 			LIST_INIT(&noeconf->cand_list);
407 			break;
408 		case IMSG_RECONF_AREA:
409 			if ((narea = area_new()) == NULL)
410 				fatal(NULL);
411 			memcpy(narea, imsg.data, sizeof(struct area));
412 
413 			LIST_INIT(&narea->iface_list);
414 			LIST_INIT(&narea->nbr_list);
415 			RB_INIT(&narea->lsa_tree);
416 			SIMPLEQ_INIT(&narea->redist_list);
417 
418 			LIST_INSERT_HEAD(&noeconf->area_list, narea, entry);
419 			break;
420 		case IMSG_RECONF_IFACE:
421 			if ((niface = malloc(sizeof(struct iface))) == NULL)
422 				fatal(NULL);
423 			memcpy(niface, imsg.data, sizeof(struct iface));
424 
425 			LIST_INIT(&niface->nbr_list);
426 			TAILQ_INIT(&niface->ls_ack_list);
427 			TAILQ_INIT(&niface->auth_md_list);
428 			RB_INIT(&niface->lsa_tree);
429 
430 			niface->area = narea;
431 			LIST_INSERT_HEAD(&narea->iface_list, niface, entry);
432 			break;
433 		case IMSG_RECONF_AUTHMD:
434 			memcpy(&md, imsg.data, sizeof(struct auth_md));
435 			md_list_add(&niface->auth_md_list, md.keyid, md.key);
436 			break;
437 		case IMSG_RECONF_END:
438 			if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) !=
439 			    (noeconf->flags & OSPFD_FLAG_STUB_ROUTER))
440 				stub_changed = 1;
441 			else
442 				stub_changed = 0;
443 			merge_config(oeconf, noeconf);
444 			noeconf = NULL;
445 			if (stub_changed)
446 				orig_rtr_lsa_all(NULL);
447 			break;
448 		case IMSG_CTL_KROUTE:
449 		case IMSG_CTL_KROUTE_ADDR:
450 		case IMSG_CTL_IFINFO:
451 		case IMSG_CTL_END:
452 			control_imsg_relay(&imsg);
453 			break;
454 		case IMSG_CONTROLFD:
455 			if ((fd = imsg.fd) == -1)
456 				fatalx("%s: expected to receive imsg control"
457 				    "fd but didn't receive any", __func__);
458 			/* Listen on control socket. */
459 			control_listen(fd);
460 			if (pledge("stdio inet mcast", NULL) == -1)
461 				fatal("pledge");
462 			break;
463 		default:
464 			log_debug("ospfe_dispatch_main: error handling imsg %d",
465 			    imsg.hdr.type);
466 			break;
467 		}
468 		imsg_free(&imsg);
469 	}
470 	if (!shut)
471 		imsg_event_add(iev);
472 	else {
473 		/* this pipe is dead, so remove the event handler */
474 		event_del(&iev->ev);
475 		event_loopexit(NULL);
476 	}
477 }
478 
479 void
480 ospfe_dispatch_rde(int fd, short event, void *bula)
481 {
482 	struct lsa_hdr		 lsa_hdr;
483 	struct imsgev		*iev = bula;
484 	struct imsgbuf		*ibuf = &iev->ibuf;
485 	struct nbr		*nbr;
486 	struct lsa_hdr		*lhp;
487 	struct lsa_ref		*ref;
488 	struct area		*area;
489 	struct iface		*iface;
490 	struct lsa_entry	*le;
491 	struct imsg		 imsg;
492 	struct abr_rtr		 ar;
493 	int			 n, noack = 0, shut = 0;
494 	u_int16_t		 l, age;
495 
496 	if (event & EV_READ) {
497 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
498 			fatal("imsg_read error");
499 		if (n == 0)	/* connection closed */
500 			shut = 1;
501 	}
502 	if (event & EV_WRITE) {
503 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
504 			fatal("msgbuf_write");
505 		if (n == 0)	/* connection closed */
506 			shut = 1;
507 	}
508 
509 	for (;;) {
510 		if ((n = imsg_get(ibuf, &imsg)) == -1)
511 			fatal("ospfe_dispatch_rde: imsg_get error");
512 		if (n == 0)
513 			break;
514 
515 		switch (imsg.hdr.type) {
516 		case IMSG_DD:
517 			nbr = nbr_find_peerid(imsg.hdr.peerid);
518 			if (nbr == NULL)
519 				break;
520 
521 			/*
522 			 * Ignore imsg when in the wrong state because a
523 			 * NBR_EVT_SEQ_NUM_MIS may have been issued in between.
524 			 * Luckily regetting the DB snapshot acts as a barrier
525 			 * for both state and process synchronisation.
526 			 */
527 			if ((nbr->state & NBR_STA_FLOOD) == 0)
528 				break;
529 
530 			/* put these on my ls_req_list for retrieval */
531 			lhp = lsa_hdr_new();
532 			memcpy(lhp, imsg.data, sizeof(*lhp));
533 			ls_req_list_add(nbr, lhp);
534 			break;
535 		case IMSG_DD_END:
536 			nbr = nbr_find_peerid(imsg.hdr.peerid);
537 			if (nbr == NULL)
538 				break;
539 
540 			/* see above */
541 			if ((nbr->state & NBR_STA_FLOOD) == 0)
542 				break;
543 
544 			nbr->dd_pending--;
545 			if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) {
546 				if (ls_req_list_empty(nbr))
547 					nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
548 				else
549 					start_ls_req_tx_timer(nbr);
550 			}
551 			break;
552 		case IMSG_DD_BADLSA:
553 			nbr = nbr_find_peerid(imsg.hdr.peerid);
554 			if (nbr == NULL)
555 				break;
556 
557 			if (nbr->iface->self == nbr)
558 				fatalx("ospfe_dispatch_rde: "
559 				    "dummy neighbor got BADREQ");
560 
561 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
562 			break;
563 		case IMSG_DB_SNAPSHOT:
564 			nbr = nbr_find_peerid(imsg.hdr.peerid);
565 			if (nbr == NULL)
566 				break;
567 			if (nbr->state != NBR_STA_SNAP)	/* discard */
568 				break;
569 
570 			/* add LSA header to the neighbor db_sum_list */
571 			lhp = lsa_hdr_new();
572 			memcpy(lhp, imsg.data, sizeof(*lhp));
573 			db_sum_list_add(nbr, lhp);
574 			break;
575 		case IMSG_DB_END:
576 			nbr = nbr_find_peerid(imsg.hdr.peerid);
577 			if (nbr == NULL)
578 				break;
579 
580 			nbr->dd_snapshot = 0;
581 			if (nbr->state != NBR_STA_SNAP)
582 				break;
583 
584 			/* snapshot done, start tx of dd packets */
585 			nbr_fsm(nbr, NBR_EVT_SNAP_DONE);
586 			break;
587 		case IMSG_LS_FLOOD:
588 			nbr = nbr_find_peerid(imsg.hdr.peerid);
589 			if (nbr == NULL)
590 				break;
591 
592 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
593 			if (l < sizeof(lsa_hdr))
594 				fatalx("ospfe_dispatch_rde: "
595 				    "bad imsg size");
596 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
597 
598 			ref = lsa_cache_add(imsg.data, l);
599 
600 			if (lsa_hdr.type == LSA_TYPE_EXTERNAL) {
601 				/*
602 				 * flood on all areas but stub areas and
603 				 * virtual links
604 				 */
605 				LIST_FOREACH(area, &oeconf->area_list, entry) {
606 				    if (area->stub)
607 					    continue;
608 				    LIST_FOREACH(iface, &area->iface_list,
609 					entry) {
610 					    noack += lsa_flood(iface, nbr,
611 						&lsa_hdr, imsg.data);
612 				    }
613 				}
614 			} else if (lsa_hdr.type == LSA_TYPE_LINK_OPAQ) {
615 				/*
616 				 * Flood on interface only
617 				 */
618 				noack += lsa_flood(nbr->iface, nbr,
619 				    &lsa_hdr, imsg.data);
620 			} else {
621 				/*
622 				 * Flood on all area interfaces. For
623 				 * area 0.0.0.0 include the virtual links.
624 				 */
625 				area = nbr->iface->area;
626 				LIST_FOREACH(iface, &area->iface_list, entry) {
627 					noack += lsa_flood(iface, nbr,
628 					    &lsa_hdr, imsg.data);
629 				}
630 				/* XXX virtual links */
631 			}
632 
633 			/* remove from ls_req_list */
634 			le = ls_req_list_get(nbr, &lsa_hdr);
635 			if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
636 				ls_req_list_free(nbr, le);
637 				/*
638 				 * XXX no need to ack requested lsa
639 				 * the problem is that the RFC is very
640 				 * unclear about this.
641 				 */
642 				noack = 1;
643 			}
644 
645 			if (!noack && nbr->iface != NULL &&
646 			    nbr->iface->self != nbr) {
647 				if (!(nbr->iface->state & IF_STA_BACKUP) ||
648 				    nbr->iface->dr == nbr) {
649 					/* delayed ack */
650 					lhp = lsa_hdr_new();
651 					memcpy(lhp, &lsa_hdr, sizeof(*lhp));
652 					ls_ack_list_add(nbr->iface, lhp);
653 				}
654 			}
655 
656 			lsa_cache_put(ref, nbr);
657 			break;
658 		case IMSG_LS_UPD:
659 		case IMSG_LS_SNAP:
660 			/*
661 			 * IMSG_LS_UPD is used in two cases:
662 			 * 1. as response to ls requests
663 			 * 2. as response to ls updates where the DB
664 			 *    is newer then the sent LSA
665 			 * IMSG_LS_SNAP is used in one case:
666 			 *    in EXSTART when the LSA has age MaxAge
667 			 */
668 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
669 			if (l < sizeof(lsa_hdr))
670 				fatalx("ospfe_dispatch_rde: "
671 				    "bad imsg size");
672 
673 			nbr = nbr_find_peerid(imsg.hdr.peerid);
674 			if (nbr == NULL)
675 				break;
676 
677 			if (nbr->iface->self == nbr)
678 				break;
679 
680 			if (imsg.hdr.type == IMSG_LS_SNAP &&
681 			    nbr->state != NBR_STA_SNAP)
682 				break;
683 
684 			memcpy(&age, imsg.data, sizeof(age));
685 			ref = lsa_cache_add(imsg.data, l);
686 			if (ntohs(age) >= MAX_AGE)
687 				/* add to retransmit list */
688 				ls_retrans_list_add(nbr, imsg.data, 0, 0);
689 			else
690 				ls_retrans_list_add(nbr, imsg.data, 0, 1);
691 
692 			lsa_cache_put(ref, nbr);
693 			break;
694 		case IMSG_LS_ACK:
695 			/*
696 			 * IMSG_LS_ACK is used in two cases:
697 			 * 1. LSA was a duplicate
698 			 * 2. LS age is MaxAge and there is no current
699 			 *    instance in the DB plus no neighbor in state
700 			 *    Exchange or Loading
701 			 */
702 			nbr = nbr_find_peerid(imsg.hdr.peerid);
703 			if (nbr == NULL)
704 				break;
705 
706 			if (nbr->iface->self == nbr)
707 				break;
708 
709 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr))
710 				fatalx("ospfe_dispatch_rde: bad imsg size");
711 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
712 
713 			/* for case one check for implied acks */
714 			if (nbr->iface->state & IF_STA_DROTHER)
715 				if (ls_retrans_list_del(nbr->iface->self,
716 				    &lsa_hdr) == 0)
717 					break;
718 			if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
719 				break;
720 
721 			/* send a direct acknowledgement */
722 			send_direct_ack(nbr->iface, nbr->addr, imsg.data,
723 			    imsg.hdr.len - IMSG_HEADER_SIZE);
724 
725 			break;
726 		case IMSG_LS_BADREQ:
727 			nbr = nbr_find_peerid(imsg.hdr.peerid);
728 			if (nbr == NULL)
729 				break;
730 
731 			if (nbr->iface->self == nbr)
732 				fatalx("ospfe_dispatch_rde: "
733 				    "dummy neighbor got BADREQ");
734 
735 			nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
736 			break;
737 		case IMSG_ABR_UP:
738 			memcpy(&ar, imsg.data, sizeof(ar));
739 
740 			if ((iface = find_vlink(&ar)) != NULL &&
741 			    iface->state == IF_STA_DOWN)
742 				if (if_fsm(iface, IF_EVT_UP)) {
743 					log_debug("error starting interface %s",
744 					    iface->name);
745 				}
746 			break;
747 		case IMSG_ABR_DOWN:
748 			memcpy(&ar, imsg.data, sizeof(ar));
749 
750 			if ((iface = find_vlink(&ar)) != NULL &&
751 			    iface->state == IF_STA_POINTTOPOINT)
752 				if (if_fsm(iface, IF_EVT_DOWN)) {
753 					log_debug("error stopping interface %s",
754 					    iface->name);
755 				}
756 			break;
757 		case IMSG_CTL_AREA:
758 		case IMSG_CTL_IFACE:
759 		case IMSG_CTL_END:
760 		case IMSG_CTL_SHOW_DATABASE:
761 		case IMSG_CTL_SHOW_DB_EXT:
762 		case IMSG_CTL_SHOW_DB_NET:
763 		case IMSG_CTL_SHOW_DB_RTR:
764 		case IMSG_CTL_SHOW_DB_SELF:
765 		case IMSG_CTL_SHOW_DB_SUM:
766 		case IMSG_CTL_SHOW_DB_ASBR:
767 		case IMSG_CTL_SHOW_DB_OPAQ:
768 		case IMSG_CTL_SHOW_RIB:
769 		case IMSG_CTL_SHOW_SUM:
770 		case IMSG_CTL_SHOW_SUM_AREA:
771 			control_imsg_relay(&imsg);
772 			break;
773 		default:
774 			log_debug("ospfe_dispatch_rde: error handling imsg %d",
775 			    imsg.hdr.type);
776 			break;
777 		}
778 		imsg_free(&imsg);
779 	}
780 	if (!shut)
781 		imsg_event_add(iev);
782 	else {
783 		/* this pipe is dead, so remove the event handler */
784 		event_del(&iev->ev);
785 		event_loopexit(NULL);
786 	}
787 }
788 
789 struct iface *
790 find_vlink(struct abr_rtr *ar)
791 {
792 	struct area	*area;
793 	struct iface	*iface = NULL;
794 
795 	LIST_FOREACH(area, &oeconf->area_list, entry)
796 		LIST_FOREACH(iface, &area->iface_list, entry)
797 			if (iface->abr_id.s_addr == ar->abr_id.s_addr &&
798 			    iface->type == IF_TYPE_VIRTUALLINK &&
799 			    iface->area->id.s_addr == ar->area.s_addr) {
800 				iface->dst.s_addr = ar->dst_ip.s_addr;
801 				iface->addr.s_addr = ar->addr.s_addr;
802 				iface->metric = ar->metric;
803 
804 				return (iface);
805 			}
806 
807 	return (iface);
808 }
809 
810 void
811 orig_rtr_lsa_all(struct area *area)
812 {
813 	struct area	*a;
814 
815 	/*
816 	 * update all router LSA in all areas except area itself,
817 	 * as this update is already running.
818 	 */
819 	LIST_FOREACH(a, &oeconf->area_list, entry)
820 		if (a != area)
821 			orig_rtr_lsa(a);
822 }
823 
824 void
825 orig_rtr_lsa(struct area *area)
826 {
827 	struct lsa_hdr		 lsa_hdr;
828 	struct lsa_rtr		 lsa_rtr;
829 	struct lsa_rtr_link	 rtr_link;
830 	struct iface		*iface;
831 	struct ibuf		*buf;
832 	struct nbr		*nbr, *self = NULL;
833 	u_int16_t		 num_links = 0;
834 	u_int16_t		 chksum;
835 	u_int8_t		 border, virtual = 0;
836 
837 	log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
838 
839 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
840 	    IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
841 	    sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
842 		fatal("orig_rtr_lsa");
843 
844 	/* reserve space for LSA header and LSA Router header */
845 	if (ibuf_reserve(buf, sizeof(lsa_hdr)) == NULL)
846 		fatal("orig_rtr_lsa: ibuf_reserve failed");
847 
848 	if (ibuf_reserve(buf, sizeof(lsa_rtr)) == NULL)
849 		fatal("orig_rtr_lsa: ibuf_reserve failed");
850 
851 	/* links */
852 	LIST_FOREACH(iface, &area->iface_list, entry) {
853 		if (self == NULL && iface->self != NULL)
854 			self = iface->self;
855 
856 		bzero(&rtr_link, sizeof(rtr_link));
857 
858 		if (iface->state & IF_STA_LOOPBACK) {
859 			rtr_link.id = iface->addr.s_addr;
860 			rtr_link.data = 0xffffffff;
861 			rtr_link.type = LINK_TYPE_STUB_NET;
862 			rtr_link.metric = htons(iface->metric);
863 			num_links++;
864 			if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
865 				fatalx("orig_rtr_lsa: ibuf_add failed");
866 			continue;
867 		}
868 
869 		switch (iface->type) {
870 		case IF_TYPE_POINTOPOINT:
871 			LIST_FOREACH(nbr, &iface->nbr_list, entry)
872 				if (nbr != iface->self &&
873 				    nbr->state & NBR_STA_FULL)
874 					break;
875 			if (nbr) {
876 				log_debug("orig_rtr_lsa: point-to-point, "
877 				    "interface %s", iface->name);
878 				rtr_link.id = nbr->id.s_addr;
879 				rtr_link.data = iface->addr.s_addr;
880 				rtr_link.type = LINK_TYPE_POINTTOPOINT;
881 				/* RFC 3137: stub router support */
882 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
883 				    oe_nofib)
884 					rtr_link.metric = MAX_METRIC;
885 				else if (iface->dependon[0] != '\0' &&
886 					 iface->depend_ok == 0)
887 					rtr_link.metric = MAX_METRIC;
888 				else
889 					rtr_link.metric = htons(iface->metric);
890 				num_links++;
891 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
892 					fatalx("orig_rtr_lsa: ibuf_add failed");
893 			}
894 			if ((iface->flags & IFF_UP) &&
895 			    LINK_STATE_IS_UP(iface->linkstate)) {
896 				log_debug("orig_rtr_lsa: stub net, "
897 				    "interface %s", iface->name);
898 				bzero(&rtr_link, sizeof(rtr_link));
899 				if (nbr) {
900 					rtr_link.id = nbr->addr.s_addr;
901 					rtr_link.data = 0xffffffff;
902 				} else {
903 					rtr_link.id = iface->addr.s_addr &
904 					              iface->mask.s_addr;
905 					rtr_link.data = iface->mask.s_addr;
906 				}
907 				rtr_link.type = LINK_TYPE_STUB_NET;
908 				if (iface->dependon[0] != '\0' &&
909 				    iface->depend_ok == 0)
910 					rtr_link.metric = MAX_METRIC;
911 				else
912 					rtr_link.metric = htons(iface->metric);
913 				num_links++;
914 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
915 					fatalx("orig_rtr_lsa: ibuf_add failed");
916 			}
917 			continue;
918 		case IF_TYPE_BROADCAST:
919 		case IF_TYPE_NBMA:
920 			if ((iface->state & IF_STA_MULTI)) {
921 				if (iface->dr == iface->self) {
922 					LIST_FOREACH(nbr, &iface->nbr_list,
923 					    entry)
924 						if (nbr != iface->self &&
925 						    nbr->state & NBR_STA_FULL)
926 							break;
927 				} else
928 					nbr = iface->dr;
929 
930 				if (nbr && nbr->state & NBR_STA_FULL) {
931 					log_debug("orig_rtr_lsa: transit net, "
932 					    "interface %s", iface->name);
933 
934 					rtr_link.id = iface->dr->addr.s_addr;
935 					rtr_link.data = iface->addr.s_addr;
936 					rtr_link.type = LINK_TYPE_TRANSIT_NET;
937 					break;
938 				}
939 			}
940 
941 			/*
942 			 * do not add a stub net LSA for interfaces that are:
943 			 *  - down
944 			 *  - have a linkstate which is down, apart from carp:
945 			 *    backup carp interfaces have linkstate down, but
946 			 *    we still announce them.
947 			 */
948 			if (!(iface->flags & IFF_UP) ||
949 			    (!LINK_STATE_IS_UP(iface->linkstate) &&
950 			    !(iface->if_type == IFT_CARP &&
951 			    iface->linkstate == LINK_STATE_DOWN)))
952 				continue;
953 			log_debug("orig_rtr_lsa: stub net, "
954 			    "interface %s", iface->name);
955 
956 			rtr_link.id =
957 			    iface->addr.s_addr & iface->mask.s_addr;
958 			rtr_link.data = iface->mask.s_addr;
959 			rtr_link.type = LINK_TYPE_STUB_NET;
960 
961 			rtr_link.num_tos = 0;
962 			/*
963 			 * backup carp interfaces and interfaces that depend
964 			 * on an interface that is down are announced with
965 			 * high metric for faster failover.
966 			 */
967 			if (iface->if_type == IFT_CARP &&
968 			    iface->linkstate == LINK_STATE_DOWN)
969 				rtr_link.metric = MAX_METRIC;
970 			else if (iface->dependon[0] != '\0' &&
971 			         iface->depend_ok == 0)
972 				rtr_link.metric = MAX_METRIC;
973 			else
974 				rtr_link.metric = htons(iface->metric);
975 			num_links++;
976 			if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
977 				fatalx("orig_rtr_lsa: ibuf_add failed");
978 			continue;
979 		case IF_TYPE_VIRTUALLINK:
980 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
981 				if (nbr != iface->self &&
982 				    nbr->state & NBR_STA_FULL)
983 					break;
984 			}
985 			if (nbr) {
986 				rtr_link.id = nbr->id.s_addr;
987 				rtr_link.data = iface->addr.s_addr;
988 				rtr_link.type = LINK_TYPE_VIRTUAL;
989 				/* RFC 3137: stub router support */
990 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
991 				    oe_nofib)
992 					rtr_link.metric = MAX_METRIC;
993 				else
994 					rtr_link.metric = htons(iface->metric);
995 				num_links++;
996 				virtual = 1;
997 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
998 					fatalx("orig_rtr_lsa: ibuf_add failed");
999 
1000 				log_debug("orig_rtr_lsa: virtual link, "
1001 				    "interface %s", iface->name);
1002 			}
1003 			continue;
1004 		case IF_TYPE_POINTOMULTIPOINT:
1005 			log_debug("orig_rtr_lsa: stub net, "
1006 			    "interface %s", iface->name);
1007 			rtr_link.id = iface->addr.s_addr;
1008 			rtr_link.data = 0xffffffff;
1009 			rtr_link.type = LINK_TYPE_STUB_NET;
1010 			rtr_link.metric = htons(iface->metric);
1011 			num_links++;
1012 			if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
1013 				fatalx("orig_rtr_lsa: ibuf_add failed");
1014 
1015 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
1016 				if (nbr != iface->self &&
1017 				    nbr->state & NBR_STA_FULL) {
1018 					bzero(&rtr_link, sizeof(rtr_link));
1019 					log_debug("orig_rtr_lsa: "
1020 					    "point-to-multipoint, interface %s",
1021 					    iface->name);
1022 					rtr_link.id = nbr->addr.s_addr;
1023 					rtr_link.data = iface->addr.s_addr;
1024 					rtr_link.type = LINK_TYPE_POINTTOPOINT;
1025 					/* RFC 3137: stub router support */
1026 					if (oe_nofib || oeconf->flags &
1027 					    OSPFD_FLAG_STUB_ROUTER)
1028 						rtr_link.metric = MAX_METRIC;
1029 					else if (iface->dependon[0] != '\0' &&
1030 						 iface->depend_ok == 0)
1031 						rtr_link.metric = MAX_METRIC;
1032 					else
1033 						rtr_link.metric =
1034 						    htons(iface->metric);
1035 					num_links++;
1036 					if (ibuf_add(buf, &rtr_link,
1037 					    sizeof(rtr_link)))
1038 						fatalx("orig_rtr_lsa: "
1039 						    "ibuf_add failed");
1040 				}
1041 			}
1042 			continue;
1043 		default:
1044 			fatalx("orig_rtr_lsa: unknown interface type");
1045 		}
1046 
1047 		rtr_link.num_tos = 0;
1048 		/* RFC 3137: stub router support */
1049 		if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER || oe_nofib) &&
1050 		    rtr_link.type != LINK_TYPE_STUB_NET)
1051 			rtr_link.metric = MAX_METRIC;
1052 		else if (iface->dependon[0] != '\0' && iface->depend_ok == 0)
1053 			rtr_link.metric = MAX_METRIC;
1054 		else
1055 			rtr_link.metric = htons(iface->metric);
1056 		num_links++;
1057 		if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
1058 			fatalx("orig_rtr_lsa: ibuf_add failed");
1059 	}
1060 
1061 	/* LSA router header */
1062 	lsa_rtr.flags = 0;
1063 	/*
1064 	 * Set the E bit as soon as an as-ext lsa may be redistributed, only
1065 	 * setting it in case we redistribute something is not worth the fuss.
1066 	 * Do not set the E bit in case of a stub area.
1067 	 */
1068 	if (oeconf->redistribute && !area->stub)
1069 		lsa_rtr.flags |= OSPF_RTR_E;
1070 
1071 	border = (area_border_router(oeconf) != 0);
1072 	if (border != oeconf->border) {
1073 		oeconf->border = border;
1074 		orig_rtr_lsa_all(area);
1075 	}
1076 	if (oeconf->border)
1077 		lsa_rtr.flags |= OSPF_RTR_B;
1078 
1079 	/* TODO set V flag if a active virtual link ends here and the
1080 	 * area is the transit area for this link. */
1081 	if (virtual)
1082 		lsa_rtr.flags |= OSPF_RTR_V;
1083 
1084 	lsa_rtr.dummy = 0;
1085 	lsa_rtr.nlinks = htons(num_links);
1086 	memcpy(ibuf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_rtr)),
1087 	    &lsa_rtr, sizeof(lsa_rtr));
1088 
1089 	/* LSA header */
1090 	lsa_hdr.age = htons(DEFAULT_AGE);
1091 	lsa_hdr.opts = area_ospf_options(area);
1092 	lsa_hdr.type = LSA_TYPE_ROUTER;
1093 	lsa_hdr.ls_id = oeconf->rtr_id.s_addr;
1094 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1095 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1096 	lsa_hdr.len = htons(ibuf_size(buf));
1097 	lsa_hdr.ls_chksum = 0;		/* updated later */
1098 	memcpy(ibuf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr));
1099 
1100 	chksum = htons(iso_cksum(buf->buf, ibuf_size(buf), LS_CKSUM_OFFSET));
1101 	memcpy(ibuf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)),
1102 	    &chksum, sizeof(chksum));
1103 
1104 	if (self && num_links)
1105 		imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0,
1106 		    -1, buf->buf, ibuf_size(buf));
1107 	else
1108 		log_warnx("orig_rtr_lsa: empty area %s",
1109 		    inet_ntoa(area->id));
1110 
1111 	ibuf_free(buf);
1112 }
1113 
1114 void
1115 orig_net_lsa(struct iface *iface)
1116 {
1117 	struct lsa_hdr		 lsa_hdr;
1118 	struct nbr		*nbr;
1119 	struct ibuf		*buf;
1120 	int			 num_rtr = 0;
1121 	u_int16_t		 chksum;
1122 
1123 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
1124 	    IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
1125 	    sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
1126 		fatal("orig_net_lsa");
1127 
1128 	/* reserve space for LSA header and LSA Router header */
1129 	if (ibuf_reserve(buf, sizeof(lsa_hdr)) == NULL)
1130 		fatal("orig_net_lsa: ibuf_reserve failed");
1131 
1132 	/* LSA net mask and then all fully adjacent routers */
1133 	if (ibuf_add(buf, &iface->mask, sizeof(iface->mask)))
1134 		fatal("orig_net_lsa: ibuf_add failed");
1135 
1136 	/* fully adjacent neighbors + self */
1137 	LIST_FOREACH(nbr, &iface->nbr_list, entry)
1138 		if (nbr->state & NBR_STA_FULL) {
1139 			if (ibuf_add(buf, &nbr->id, sizeof(nbr->id)))
1140 				fatal("orig_net_lsa: ibuf_add failed");
1141 			num_rtr++;
1142 		}
1143 
1144 	if (num_rtr == 1) {
1145 		/* non transit net therefore no need to generate a net lsa */
1146 		ibuf_free(buf);
1147 		return;
1148 	}
1149 
1150 	/* LSA header */
1151 	if (iface->state & IF_STA_DR)
1152 		lsa_hdr.age = htons(DEFAULT_AGE);
1153 	else
1154 		lsa_hdr.age = htons(MAX_AGE);
1155 
1156 	lsa_hdr.opts = area_ospf_options(iface->area);
1157 	lsa_hdr.type = LSA_TYPE_NETWORK;
1158 	lsa_hdr.ls_id = iface->addr.s_addr;
1159 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1160 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1161 	lsa_hdr.len = htons(ibuf_size(buf));
1162 	lsa_hdr.ls_chksum = 0;		/* updated later */
1163 	memcpy(ibuf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr));
1164 
1165 	chksum = htons(iso_cksum(buf->buf, ibuf_size(buf), LS_CKSUM_OFFSET));
1166 	memcpy(ibuf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)),
1167 	    &chksum, sizeof(chksum));
1168 
1169 	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1170 	    -1, buf->buf, ibuf_size(buf));
1171 
1172 	ibuf_free(buf);
1173 }
1174 
1175 u_int32_t
1176 ospfe_router_id(void)
1177 {
1178 	return (oeconf->rtr_id.s_addr);
1179 }
1180 
1181 void
1182 ospfe_fib_update(int type)
1183 {
1184 	int	old = oe_nofib;
1185 
1186 	if (type == IMSG_CTL_FIB_COUPLE)
1187 		oe_nofib = 0;
1188 	if (type == IMSG_CTL_FIB_DECOUPLE)
1189 		oe_nofib = 1;
1190 	if (old != oe_nofib)
1191 		orig_rtr_lsa_all(NULL);
1192 }
1193 
1194 void
1195 ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
1196 {
1197 	struct area		*area;
1198 	struct iface		*iface;
1199 	struct ctl_iface	*ictl;
1200 
1201 	LIST_FOREACH(area, &oeconf->area_list, entry)
1202 		LIST_FOREACH(iface, &area->iface_list, entry)
1203 			if (idx == 0 || idx == iface->ifindex) {
1204 				ictl = if_to_ctl(iface);
1205 				imsg_compose_event(&c->iev,
1206 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
1207 				    ictl, sizeof(struct ctl_iface));
1208 			}
1209 }
1210 
1211 void
1212 ospfe_nbr_ctl(struct ctl_conn *c)
1213 {
1214 	struct area	*area;
1215 	struct iface	*iface;
1216 	struct nbr	*nbr;
1217 	struct ctl_nbr	*nctl;
1218 
1219 	LIST_FOREACH(area, &oeconf->area_list, entry)
1220 		LIST_FOREACH(iface, &area->iface_list, entry)
1221 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
1222 				if (iface->self != nbr) {
1223 					nctl = nbr_to_ctl(nbr);
1224 					imsg_compose_event(&c->iev,
1225 					    IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
1226 					    sizeof(struct ctl_nbr));
1227 				}
1228 			}
1229 
1230 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
1231 }
1232 
1233 void
1234 ospfe_demote_area(struct area *area, int active)
1235 {
1236 	struct demote_msg	dmsg;
1237 
1238 	if (ospfd_process != PROC_OSPF_ENGINE ||
1239 	    area->demote_group[0] == '\0')
1240 		return;
1241 
1242 	bzero(&dmsg, sizeof(dmsg));
1243 	strlcpy(dmsg.demote_group, area->demote_group,
1244 	    sizeof(dmsg.demote_group));
1245 	dmsg.level = area->demote_level;
1246 	if (active)
1247 		dmsg.level = -dmsg.level;
1248 
1249 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1250 }
1251 
1252 void
1253 ospfe_demote_iface(struct iface *iface, int active)
1254 {
1255 	struct demote_msg	dmsg;
1256 
1257 	if (ospfd_process != PROC_OSPF_ENGINE ||
1258 	    iface->demote_group[0] == '\0')
1259 		return;
1260 
1261 	bzero(&dmsg, sizeof(dmsg));
1262 	strlcpy(dmsg.demote_group, iface->demote_group,
1263 	sizeof(dmsg.demote_group));
1264 	if (active)
1265 		dmsg.level = -1;
1266 	else
1267 		dmsg.level = 1;
1268 
1269 	log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group,
1270 	    dmsg.level);
1271 
1272 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1273 }
1274