xref: /openbsd-src/usr.sbin/ospf6d/ospfe.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1 /*	$OpenBSD: ospfe.c,v 1.78 2024/11/21 13:38:14 claudio 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 "ospf6.h"
39 #include "ospf6d.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 passwd	*pw;
76 	struct event	 ev_sigint, ev_sigterm;
77 	pid_t		 pid;
78 	int		 pre = IPTOS_PREC_INTERNETCONTROL;
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 	/* create the raw ip socket */
90 	if ((xconf->ospf_socket = socket(AF_INET6,
91 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_OSPF)) == -1)
92 		fatal("error creating raw socket");
93 
94 	if (setsockopt(xconf->ospf_socket, IPPROTO_IPV6, IPV6_TCLASS, &pre,
95 	    sizeof(pre)) == -1)
96 		fatal("setsockopt IPV6_TCLASS");
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_ipv6_checksum(xconf->ospf_socket) == -1)
102 		fatal("if_set_ipv6_checksum");
103 	if (if_set_ipv6_pktinfo(xconf->ospf_socket, 1) == -1)
104 		fatal("if_set_ipv6_pktinfo");
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(OSPF6D_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 	if (imsgbuf_init(&iev_rde->ibuf, pipe_ospfe2rde[0]) == -1)
159 		fatal(NULL);
160 	iev_rde->handler = ospfe_dispatch_rde;
161 	if (imsgbuf_init(&iev_main->ibuf, pipe_parent2ospfe[1]) == -1)
162 		fatal(NULL);
163 	imsgbuf_allow_fdpass(&iev_main->ibuf);
164 	iev_main->handler = ospfe_dispatch_main;
165 
166 	/* setup event handler */
167 	iev_rde->events = EV_READ;
168 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
169 	    iev_rde->handler, iev_rde);
170 	event_add(&iev_rde->ev, NULL);
171 
172 	iev_main->events = EV_READ;
173 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
174 	    iev_main->handler, iev_main);
175 	event_add(&iev_main->ev, NULL);
176 
177 	event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST,
178 	    recv_packet, oeconf);
179 	event_add(&oeconf->ev, NULL);
180 
181 	/* remove unneeded config stuff */
182 	conf_clear_redist_list(&oeconf->redist_list);
183 
184 	/* start interfaces */
185 	LIST_FOREACH(area, &oeconf->area_list, entry) {
186 		ospfe_demote_area(area, 0);
187 		LIST_FOREACH(iface, &area->iface_list, entry)
188 			if_start(xconf, iface);
189 	}
190 
191 	event_dispatch();
192 
193 	ospfe_shutdown();
194 	/* NOTREACHED */
195 	return (0);
196 }
197 
198 __dead void
199 ospfe_shutdown(void)
200 {
201 	struct area	*area;
202 	struct iface	*iface;
203 
204 	/* close pipes */
205 	imsgbuf_write(&iev_rde->ibuf);
206 	imsgbuf_clear(&iev_rde->ibuf);
207 	close(iev_rde->ibuf.fd);
208 	imsgbuf_write(&iev_main->ibuf);
209 	imsgbuf_clear(&iev_main->ibuf);
210 	close(iev_main->ibuf.fd);
211 
212 	/* stop all interfaces and remove all areas */
213 	while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) {
214 		LIST_FOREACH(iface, &area->iface_list, entry) {
215 			if (if_fsm(iface, IF_EVT_DOWN)) {
216 				log_debug("error stopping interface %s",
217 				    iface->name);
218 			}
219 		}
220 		LIST_REMOVE(area, entry);
221 		area_del(area);
222 	}
223 
224 	close(oeconf->ospf_socket);
225 
226 	/* clean up */
227 	free(iev_rde);
228 	free(iev_main);
229 	free(oeconf);
230 
231 	log_info("ospf engine exiting");
232 	_exit(0);
233 }
234 
235 /* imesg */
236 int
237 ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
238 {
239 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
240 }
241 
242 int
243 ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
244     void *data, u_int16_t datalen)
245 {
246 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
247 	    data, datalen));
248 }
249 
250 void
251 ospfe_dispatch_main(int fd, short event, void *bula)
252 {
253 	static struct area	*narea;
254 	struct area		*area;
255 	struct iface		*iface, *ifp, *i;
256 	struct ifaddrchange	*ifc;
257 	struct iface_addr	*ia, *nia;
258 	struct imsg		 imsg;
259 	struct imsgev		*iev = bula;
260 	struct imsgbuf		*ibuf = &iev->ibuf;
261 	int			 n, stub_changed, shut = 0, isvalid, wasvalid;
262 
263 	if (event & EV_READ) {
264 		if ((n = imsgbuf_read(ibuf)) == -1)
265 			fatal("imsgbuf_read error");
266 		if (n == 0)	/* connection closed */
267 			shut = 1;
268 	}
269 	if (event & EV_WRITE) {
270 		if (imsgbuf_write(ibuf) == -1) {
271 			if (errno == EPIPE)	/* connection closed */
272 				shut = 1;
273 			else
274 				fatal("imsgbuf_write");
275 		}
276 	}
277 
278 	for (;;) {
279 		if ((n = imsg_get(ibuf, &imsg)) == -1)
280 			fatal("ospfe_dispatch_main: imsg_get error");
281 		if (n == 0)
282 			break;
283 
284 		switch (imsg.hdr.type) {
285 		case IMSG_IFINFO:
286 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
287 			    sizeof(struct iface))
288 				fatalx("IFINFO imsg with wrong len");
289 			ifp = imsg.data;
290 
291 			LIST_FOREACH(area, &oeconf->area_list, entry) {
292 				LIST_FOREACH(i, &area->iface_list, entry) {
293 					if (strcmp(i->dependon,
294 					    ifp->name) == 0) {
295 						log_warnx("interface %s"
296 						    " changed state, %s"
297 						    " depends on it",
298 						    ifp->name, i->name);
299 						i->depend_ok =
300 						    ifstate_is_up(ifp);
301 						if (ifstate_is_up(i))
302 							orig_rtr_lsa(i->area);
303 					}
304 				}
305 			}
306 
307 			if (!(ifp->cflags & F_IFACE_CONFIGURED))
308 				break;
309 			iface = if_find(ifp->ifindex);
310 			if (iface == NULL)
311 				fatalx("interface lost in ospfe");
312 
313 			wasvalid = (iface->flags & IFF_UP) &&
314 			    LINK_STATE_IS_UP(iface->linkstate);
315 
316 			if_update(iface, ifp->mtu, ifp->flags, ifp->if_type,
317 			    ifp->linkstate, ifp->baudrate, ifp->rdomain);
318 
319 			isvalid = (iface->flags & IFF_UP) &&
320 			    LINK_STATE_IS_UP(iface->linkstate);
321 
322 			if (wasvalid == isvalid)
323 				break;
324 
325 			if (isvalid) {
326 				if_fsm(iface, IF_EVT_UP);
327 				log_warnx("interface %s up", iface->name);
328 			} else {
329 				if_fsm(iface, IF_EVT_DOWN);
330 				log_warnx("interface %s down", iface->name);
331 			}
332 			break;
333 		case IMSG_IFADDRNEW:
334 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
335 			    sizeof(struct ifaddrchange))
336 				fatalx("IFADDRNEW imsg with wrong len");
337 			ifc = imsg.data;
338 
339 			iface = if_find(ifc->ifindex);
340 			if (iface == NULL)
341 				fatalx("IFADDRNEW interface lost in ospfe");
342 
343 			if ((ia = calloc(1, sizeof(struct iface_addr))) ==
344 			    NULL)
345 				fatal("ospfe_dispatch_main IFADDRNEW");
346 			ia->addr = ifc->addr;
347 			ia->dstbrd = ifc->dstbrd;
348 			ia->prefixlen = ifc->prefixlen;
349 
350 			TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry);
351 			orig_link_lsa(iface);
352 			break;
353 		case IMSG_IFADDRDEL:
354 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
355 			    sizeof(struct ifaddrchange))
356 				fatalx("IFADDRDEL imsg with wrong len");
357 			ifc = imsg.data;
358 
359 			iface = if_find(ifc->ifindex);
360 			if (iface == NULL)
361 				fatalx("IFADDRDEL interface lost in ospfe");
362 
363 			for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL;
364 			    ia = nia) {
365 				nia = TAILQ_NEXT(ia, entry);
366 
367 				if (IN6_ARE_ADDR_EQUAL(&ia->addr,
368 				    &ifc->addr)) {
369 					TAILQ_REMOVE(&iface->ifa_list, ia,
370 					    entry);
371 					free(ia);
372 					break;
373 				}
374 			}
375 			orig_link_lsa(iface);
376 			break;
377 		case IMSG_RECONF_CONF:
378 			if ((noeconf = malloc(sizeof(struct ospfd_conf))) ==
379 			    NULL)
380 				fatal(NULL);
381 			memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf));
382 
383 			LIST_INIT(&noeconf->area_list);
384 			LIST_INIT(&noeconf->cand_list);
385 			break;
386 		case IMSG_RECONF_AREA:
387 			if ((narea = area_new()) == NULL)
388 				fatal(NULL);
389 			memcpy(narea, imsg.data, sizeof(struct area));
390 
391 			LIST_INIT(&narea->iface_list);
392 			LIST_INIT(&narea->nbr_list);
393 			RB_INIT(&narea->lsa_tree);
394 
395 			LIST_INSERT_HEAD(&noeconf->area_list, narea, entry);
396 			break;
397 		case IMSG_RECONF_END:
398 			if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) !=
399 			    (noeconf->flags & OSPFD_FLAG_STUB_ROUTER))
400 				stub_changed = 1;
401 			else
402 				stub_changed = 0;
403 			merge_config(oeconf, noeconf);
404 			noeconf = NULL;
405 			if (stub_changed)
406 				orig_rtr_lsa_all(NULL);
407 			break;
408 		case IMSG_CTL_KROUTE:
409 		case IMSG_CTL_KROUTE_ADDR:
410 		case IMSG_CTL_END:
411 			control_imsg_relay(&imsg);
412 			break;
413 		case IMSG_CONTROLFD:
414 			if ((fd = imsg_get_fd(&imsg)) == -1)
415 				fatalx("%s: expected to receive imsg control"
416 				    "fd but didn't receive any", __func__);
417 			/* Listen on control socket. */
418 			control_listen(fd);
419 			if (pledge("stdio inet mcast", NULL) == -1)
420 				fatal("pledge");
421 			break;
422 		default:
423 			log_debug("ospfe_dispatch_main: error handling imsg %d",
424 			    imsg.hdr.type);
425 			break;
426 		}
427 		imsg_free(&imsg);
428 	}
429 	if (!shut)
430 		imsg_event_add(iev);
431 	else {
432 		/* this pipe is dead, so remove the event handler */
433 		event_del(&iev->ev);
434 		event_loopexit(NULL);
435 	}
436 }
437 
438 void
439 ospfe_dispatch_rde(int fd, short event, void *bula)
440 {
441 	struct lsa_hdr		 lsa_hdr;
442 	struct lsa_link		 lsa_link;
443 	struct imsgev		*iev = bula;
444 	struct imsgbuf		*ibuf = &iev->ibuf;
445 	struct nbr		*nbr;
446 	struct lsa_hdr		*lhp;
447 	struct lsa_ref		*ref;
448 	struct area		*area;
449 	struct iface		*iface;
450 	struct lsa_entry	*le;
451 	struct imsg		 imsg;
452 	struct abr_rtr		 ar;
453 	int			 n, noack = 0, shut = 0;
454 	u_int16_t		 l, age;
455 
456 	if (event & EV_READ) {
457 		if ((n = imsgbuf_read(ibuf)) == -1)
458 			fatal("imsgbuf_read error");
459 		if (n == 0)	/* connection closed */
460 			shut = 1;
461 	}
462 	if (event & EV_WRITE) {
463 		if (imsgbuf_write(ibuf) == -1) {
464 			if (errno == EPIPE)	/* connection closed */
465 				shut = 1;
466 			else
467 				fatal("imsgbuf_write");
468 		}
469 	}
470 
471 	for (;;) {
472 		if ((n = imsg_get(ibuf, &imsg)) == -1)
473 			fatal("ospfe_dispatch_rde: imsg_get error");
474 		if (n == 0)
475 			break;
476 
477 		switch (imsg.hdr.type) {
478 		case IMSG_DD:
479 			nbr = nbr_find_peerid(imsg.hdr.peerid);
480 			if (nbr == NULL)
481 				break;
482 
483 			/* put these on my ls_req_list for retrieval */
484 			lhp = lsa_hdr_new();
485 			memcpy(lhp, imsg.data, sizeof(*lhp));
486 			ls_req_list_add(nbr, lhp);
487 			break;
488 		case IMSG_DD_END:
489 			nbr = nbr_find_peerid(imsg.hdr.peerid);
490 			if (nbr == NULL)
491 				break;
492 
493 			nbr->dd_pending--;
494 			if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) {
495 				if (ls_req_list_empty(nbr))
496 					nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
497 				else
498 					start_ls_req_tx_timer(nbr);
499 			}
500 			break;
501 		case IMSG_DB_SNAPSHOT:
502 			nbr = nbr_find_peerid(imsg.hdr.peerid);
503 			if (nbr == NULL)
504 				break;
505 			if (nbr->state != NBR_STA_SNAP)	/* discard */
506 				break;
507 
508 			/* add LSA header to the neighbor db_sum_list */
509 			lhp = lsa_hdr_new();
510 			memcpy(lhp, imsg.data, sizeof(*lhp));
511 			db_sum_list_add(nbr, lhp);
512 			break;
513 		case IMSG_DB_END:
514 			nbr = nbr_find_peerid(imsg.hdr.peerid);
515 			if (nbr == NULL)
516 				break;
517 
518 			nbr->dd_snapshot = 0;
519 			if (nbr->state != NBR_STA_SNAP)
520 				break;
521 
522 			/* snapshot done, start tx of dd packets */
523 			nbr_fsm(nbr, NBR_EVT_SNAP_DONE);
524 			break;
525 		case IMSG_LS_FLOOD:
526 			nbr = nbr_find_peerid(imsg.hdr.peerid);
527 			if (nbr == NULL)
528 				break;
529 
530 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
531 			if (l < sizeof(lsa_hdr))
532 				fatalx("ospfe_dispatch_rde: "
533 				    "bad imsg size");
534 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
535 
536 			ref = lsa_cache_add(imsg.data, l);
537 
538 			if (lsa_hdr.type == htons(LSA_TYPE_EXTERNAL)) {
539 				/*
540 				 * flood on all areas but stub areas and
541 				 * virtual links
542 				 */
543 				LIST_FOREACH(area, &oeconf->area_list, entry) {
544 					if (area->stub)
545 						continue;
546 					LIST_FOREACH(iface, &area->iface_list,
547 					    entry) {
548 						noack += lsa_flood(iface, nbr,
549 						    &lsa_hdr, imsg.data);
550 					}
551 				}
552 			} else if (lsa_hdr.type == htons(LSA_TYPE_LINK)) {
553 				/*
554 				 * Save link-LSA options of neighbor.
555 				 * This is needed to originate network-LSA.
556 				 */
557 				if (l - sizeof(lsa_hdr) < sizeof(lsa_link))
558 					fatalx("ospfe_dispatch_rde: "
559 					    "bad imsg link size");
560 				memcpy(&lsa_link, (char *)imsg.data +
561 				    sizeof(lsa_hdr), sizeof(lsa_link));
562 				nbr->link_options = lsa_link.opts &
563 				    htonl(LSA_24_MASK);
564 
565 				/*
566 				 * flood on interface only
567 				 */
568 				noack += lsa_flood(nbr->iface, nbr,
569 				    &lsa_hdr, imsg.data);
570 			} else {
571 				/*
572 				 * flood on all area interfaces on
573 				 * area 0.0.0.0 include also virtual links.
574 				 */
575 				LIST_FOREACH(iface,
576 				    &nbr->iface->area->iface_list, entry) {
577 					noack += lsa_flood(iface, nbr,
578 					    &lsa_hdr, imsg.data);
579 				}
580 				/* XXX virtual links */
581 			}
582 
583 			/* remove from ls_req_list */
584 			le = ls_req_list_get(nbr, &lsa_hdr);
585 			if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
586 				ls_req_list_free(nbr, le);
587 				/*
588 				 * XXX no need to ack requested lsa
589 				 * the problem is that the RFC is very
590 				 * unclear about this.
591 				 */
592 				noack = 1;
593 			}
594 
595 			if (!noack && nbr->iface != NULL &&
596 			    nbr->iface->self != nbr) {
597 				if (!(nbr->iface->state & IF_STA_BACKUP) ||
598 				    nbr->iface->dr == nbr) {
599 					/* delayed ack */
600 					lhp = lsa_hdr_new();
601 					memcpy(lhp, &lsa_hdr, sizeof(*lhp));
602 					ls_ack_list_add(nbr->iface, lhp);
603 				}
604 			}
605 
606 			lsa_cache_put(ref, nbr);
607 			break;
608 		case IMSG_LS_UPD:
609 		case IMSG_LS_SNAP:
610 			/*
611 			 * IMSG_LS_UPD is used in two cases:
612 			 * 1. as response to ls requests
613 			 * 2. as response to ls updates where the DB
614 			 *    is newer then the sent LSA
615 			 * IMSG_LS_SNAP is used in one case:
616 			 *    in EXSTART when the LSA has age MaxAge
617 			 */
618 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
619 			if (l < sizeof(lsa_hdr))
620 				fatalx("ospfe_dispatch_rde: "
621 				    "bad imsg size");
622 
623 			nbr = nbr_find_peerid(imsg.hdr.peerid);
624 			if (nbr == NULL)
625 				break;
626 
627 			if (nbr->iface->self == nbr)
628 				break;
629 
630 			if (imsg.hdr.type == IMSG_LS_SNAP &&
631 			    nbr->state != NBR_STA_SNAP)
632 				break;
633 
634 			memcpy(&age, imsg.data, sizeof(age));
635 			ref = lsa_cache_add(imsg.data, l);
636 			if (ntohs(age) >= MAX_AGE)
637 				/* add to retransmit list */
638 				ls_retrans_list_add(nbr, imsg.data, 0, 0);
639 			else
640 				ls_retrans_list_add(nbr, imsg.data, 0, 1);
641 
642 			lsa_cache_put(ref, nbr);
643 			break;
644 		case IMSG_LS_ACK:
645 			/*
646 			 * IMSG_LS_ACK is used in two cases:
647 			 * 1. LSA was a duplicate
648 			 * 2. LS age is MaxAge and there is no current
649 			 *    instance in the DB plus no neighbor in state
650 			 *    Exchange or Loading
651 			 */
652 			nbr = nbr_find_peerid(imsg.hdr.peerid);
653 			if (nbr == NULL)
654 				break;
655 
656 			if (nbr->iface->self == nbr)
657 				break;
658 
659 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr))
660 				fatalx("ospfe_dispatch_rde: bad imsg size");
661 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
662 
663 			/* for case one check for implied acks */
664 			if (nbr->iface->state & IF_STA_DROTHER)
665 				if (ls_retrans_list_del(nbr->iface->self,
666 				    &lsa_hdr) == 0)
667 					break;
668 			if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
669 				break;
670 
671 			/* send a direct acknowledgement */
672 			send_direct_ack(nbr->iface, nbr->addr, imsg.data,
673 			    imsg.hdr.len - IMSG_HEADER_SIZE);
674 
675 			break;
676 		case IMSG_LS_BADREQ:
677 			nbr = nbr_find_peerid(imsg.hdr.peerid);
678 			if (nbr == NULL)
679 				break;
680 
681 			if (nbr->iface->self == nbr)
682 				fatalx("ospfe_dispatch_rde: "
683 				    "dummy neighbor got BADREQ");
684 
685 			nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
686 			break;
687 		case IMSG_ABR_UP:
688 			memcpy(&ar, imsg.data, sizeof(ar));
689 
690 			if ((iface = find_vlink(&ar)) != NULL &&
691 			    iface->state == IF_STA_DOWN)
692 				if (if_fsm(iface, IF_EVT_UP)) {
693 					log_debug("error starting interface %s",
694 					    iface->name);
695 				}
696 			break;
697 		case IMSG_ABR_DOWN:
698 			memcpy(&ar, imsg.data, sizeof(ar));
699 
700 			if ((iface = find_vlink(&ar)) != NULL &&
701 			    iface->state == IF_STA_POINTTOPOINT)
702 				if (if_fsm(iface, IF_EVT_DOWN)) {
703 					log_debug("error stopping interface %s",
704 					    iface->name);
705 				}
706 			break;
707 		case IMSG_CTL_AREA:
708 		case IMSG_CTL_IFACE:
709 		case IMSG_CTL_END:
710 		case IMSG_CTL_SHOW_DATABASE:
711 		case IMSG_CTL_SHOW_DB_EXT:
712 		case IMSG_CTL_SHOW_DB_LINK:
713 		case IMSG_CTL_SHOW_DB_NET:
714 		case IMSG_CTL_SHOW_DB_RTR:
715 		case IMSG_CTL_SHOW_DB_INTRA:
716 		case IMSG_CTL_SHOW_DB_SELF:
717 		case IMSG_CTL_SHOW_DB_SUM:
718 		case IMSG_CTL_SHOW_DB_ASBR:
719 		case IMSG_CTL_SHOW_RIB:
720 		case IMSG_CTL_SHOW_SUM:
721 		case IMSG_CTL_SHOW_SUM_AREA:
722 			control_imsg_relay(&imsg);
723 			break;
724 		default:
725 			log_debug("ospfe_dispatch_rde: error handling imsg %d",
726 			    imsg.hdr.type);
727 			break;
728 		}
729 		imsg_free(&imsg);
730 	}
731 	if (!shut)
732 		imsg_event_add(iev);
733 	else {
734 		/* this pipe is dead, so remove the event handler */
735 		event_del(&iev->ev);
736 		event_loopexit(NULL);
737 	}
738 }
739 
740 struct iface *
741 find_vlink(struct abr_rtr *ar)
742 {
743 	struct area	*area;
744 	struct iface	*iface = NULL;
745 
746 	LIST_FOREACH(area, &oeconf->area_list, entry)
747 		LIST_FOREACH(iface, &area->iface_list, entry)
748 			if (iface->abr_id.s_addr == ar->abr_id.s_addr &&
749 			    iface->type == IF_TYPE_VIRTUALLINK &&
750 			    iface->area->id.s_addr == ar->area.s_addr) {
751 				iface->dst = ar->dst_ip;
752 				iface->addr = ar->addr;
753 				iface->metric = ar->metric;
754 
755 				return (iface);
756 			}
757 
758 	return (iface);
759 }
760 
761 void
762 orig_rtr_lsa_all(struct area *area)
763 {
764 	struct area	*a;
765 
766 	/*
767 	 * update all router LSA in all areas except area itself,
768 	 * as this update is already running.
769 	 */
770 	LIST_FOREACH(a, &oeconf->area_list, entry)
771 		if (a != area)
772 			orig_rtr_lsa(a);
773 }
774 
775 void
776 orig_rtr_lsa(struct area *area)
777 {
778 	struct lsa_hdr		 lsa_hdr;
779 	struct lsa_rtr		 lsa_rtr;
780 	struct lsa_rtr_link	 rtr_link;
781 	struct iface		*iface;
782 	struct ibuf		*buf;
783 	struct nbr		*nbr, *self = NULL;
784 	u_int32_t		 flags;
785 	u_int16_t		 chksum;
786 	u_int8_t		 border, virtual = 0;
787 
788 	log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
789 
790 	/* XXX IBUF_READ_SIZE */
791 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
792 		fatal("orig_rtr_lsa");
793 
794 	/* reserve space for LSA header and LSA Router header */
795 	if (ibuf_add_zero(buf, sizeof(lsa_hdr)) == -1)
796 		fatal("orig_rtr_lsa: ibuf_add_zero failed");
797 
798 	if (ibuf_add_zero(buf, sizeof(lsa_rtr)) == -1)
799 		fatal("orig_rtr_lsa: ibuf_add_zero failed");
800 
801 	/* links */
802 	LIST_FOREACH(iface, &area->iface_list, entry) {
803 		if (self == NULL && iface->self != NULL)
804 			self = iface->self;
805 
806 		bzero(&rtr_link, sizeof(rtr_link));
807 
808 		switch (iface->type) {
809 		case IF_TYPE_POINTOPOINT:
810 			LIST_FOREACH(nbr, &iface->nbr_list, entry)
811 				if (nbr != iface->self &&
812 				    nbr->state & NBR_STA_FULL)
813 					break;
814 			if (nbr && iface->state & IF_STA_POINTTOPOINT) {
815 				log_debug("orig_rtr_lsa: point-to-point, "
816 				    "interface %s", iface->name);
817 				rtr_link.type = LINK_TYPE_POINTTOPOINT;
818 				if (iface->dependon[0] != '\0' &&
819 				    iface->depend_ok == 0)
820 					rtr_link.metric = MAX_METRIC;
821 				else
822 					rtr_link.metric = htons(iface->metric);
823 				rtr_link.iface_id = htonl(iface->ifindex);
824 				rtr_link.nbr_iface_id = htonl(nbr->iface_id);
825 				rtr_link.nbr_rtr_id = nbr->id.s_addr;
826 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
827 					fatalx("orig_rtr_lsa: ibuf_add failed");
828 			}
829 			continue;
830 		case IF_TYPE_BROADCAST:
831 		case IF_TYPE_NBMA:
832 			if ((iface->state & IF_STA_MULTI)) {
833 				if (iface->dr == iface->self) {
834 					LIST_FOREACH(nbr, &iface->nbr_list,
835 					    entry)
836 						if (nbr != iface->self &&
837 						    nbr->state & NBR_STA_FULL)
838 							break;
839 				} else
840 					nbr = iface->dr;
841 
842 				if (nbr && nbr->state & NBR_STA_FULL) {
843 					log_debug("orig_rtr_lsa: transit net, "
844 					    "interface %s", iface->name);
845 
846 					rtr_link.type = LINK_TYPE_TRANSIT_NET;
847 					if (iface->dependon[0] != '\0' &&
848 					    iface->depend_ok == 0)
849 						rtr_link.metric = MAX_METRIC;
850 					else
851 						rtr_link.metric =
852 						    htons(iface->metric);
853 					rtr_link.iface_id = htonl(iface->ifindex);
854 					rtr_link.nbr_iface_id = htonl(iface->dr->iface_id);
855 					rtr_link.nbr_rtr_id = iface->dr->id.s_addr;
856 					if (ibuf_add(buf, &rtr_link,
857 					    sizeof(rtr_link)))
858 						fatalx("orig_rtr_lsa: "
859 						    "ibuf_add failed");
860 					break;
861 				}
862 			}
863 			break;
864 #if 0 /* TODO virtualllink/pointtomulti */
865 		case IF_TYPE_VIRTUALLINK:
866 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
867 				if (nbr != iface->self &&
868 				    nbr->state & NBR_STA_FULL)
869 					break;
870 			}
871 			if (nbr) {
872 				rtr_link.id = nbr->id.s_addr;
873 //XXX				rtr_link.data = iface->addr.s_addr;
874 				rtr_link.type = LINK_TYPE_VIRTUAL;
875 				/* RFC 3137: stub router support */
876 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
877 				    oe_nofib)
878 					rtr_link.metric = 0xffff;
879 				else
880 					rtr_link.metric = htons(iface->metric);
881 				virtual = 1;
882 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
883 					fatalx("orig_rtr_lsa: ibuf_add failed");
884 
885 				log_debug("orig_rtr_lsa: virtual link, "
886 				    "interface %s", iface->name);
887 			}
888 			continue;
889 		case IF_TYPE_POINTOMULTIPOINT:
890 			log_debug("orig_rtr_lsa: stub net, "
891 			    "interface %s", iface->name);
892 //XXX			rtr_link.id = iface->addr.s_addr;
893 			rtr_link.data = 0xffffffff;
894 			rtr_link.type = LINK_TYPE_STUB_NET;
895 			rtr_link.metric = htons(iface->metric);
896 			if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
897 				fatalx("orig_rtr_lsa: ibuf_add failed");
898 
899 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
900 				if (nbr != iface->self &&
901 				    nbr->state & NBR_STA_FULL) {
902 					bzero(&rtr_link, sizeof(rtr_link));
903 					log_debug("orig_rtr_lsa: "
904 					    "point-to-multipoint, interface %s",
905 					    iface->name);
906 //XXX					rtr_link.id = nbr->addr.s_addr;
907 //XXX					rtr_link.data = iface->addr.s_addr;
908 					rtr_link.type = LINK_TYPE_POINTTOPOINT;
909 					/* RFC 3137: stub router support */
910 					if (oe_nofib || oeconf->flags &
911 					    OSPFD_FLAG_STUB_ROUTER)
912 						rtr_link.metric = MAX_METRIC;
913 					else if (iface->dependon[0] != '\0' &&
914 						 iface->dependon_ok == 0)
915 						rtr_link.metric = MAX_METRIC;
916 					else
917 						rtr_link.metric =
918 						    htons(iface->metric);
919 					if (ibuf_add(buf, &rtr_link,
920 					    sizeof(rtr_link)))
921 						fatalx("orig_rtr_lsa: "
922 						    "ibuf_add failed");
923 				}
924 			}
925 			continue;
926 #endif /* TODO virtualllink/pointtomulti */
927 		default:
928 			fatalx("orig_rtr_lsa: unknown interface type");
929 		}
930 	}
931 
932 	/* LSA router header */
933 	lsa_rtr.opts = 0;
934 	flags = 0;
935 
936 	/*
937 	 * Set the E bit as soon as an as-ext lsa may be redistributed, only
938 	 * setting it in case we redistribute something is not worth the fuss.
939 	 */
940 	if (oeconf->redistribute && !area->stub)
941 		flags |= OSPF_RTR_E;
942 
943 	border = (area_border_router(oeconf) != 0);
944 	if (border != oeconf->border) {
945 		oeconf->border = border;
946 		orig_rtr_lsa_all(area);
947 	}
948 
949 	if (oeconf->border)
950 		flags |= OSPF_RTR_B;
951 	/* TODO set V flag if a active virtual link ends here and the
952 	 * area is the transit area for this link. */
953 	if (virtual)
954 		flags |= OSPF_RTR_V;
955 
956 	LSA_24_SETLO(lsa_rtr.opts, area_ospf_options(area));
957 	LSA_24_SETHI(lsa_rtr.opts, flags);
958 	lsa_rtr.opts = htonl(lsa_rtr.opts);
959 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_rtr, sizeof(lsa_rtr)) == -1)
960 		fatal("orig_rtr_lsa: ibuf_set failed");
961 
962 	/* LSA header */
963 	lsa_hdr.age = htons(DEFAULT_AGE);
964 	lsa_hdr.type = htons(LSA_TYPE_ROUTER);
965 	/* XXX needs to be fixed if multiple router-lsa need to be announced */
966 	lsa_hdr.ls_id = 0;
967 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
968 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
969 	lsa_hdr.len = htons(ibuf_size(buf));
970 	lsa_hdr.ls_chksum = 0;		/* updated later */
971 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
972 		fatal("orig_rtr_lsa: ibuf_set failed");
973 
974 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
975 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
976 		fatal("orig_rtr_lsa: ibuf_set_n16 failed");
977 
978 	if (self)
979 		imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0,
980 		    -1, ibuf_data(buf), ibuf_size(buf));
981 	else
982 		log_warnx("orig_rtr_lsa: empty area %s",
983 		    inet_ntoa(area->id));
984 
985 	ibuf_free(buf);
986 }
987 
988 void
989 orig_net_lsa(struct iface *iface)
990 {
991 	struct lsa_hdr		 lsa_hdr;
992 	struct nbr		*nbr;
993 	struct ibuf		*buf;
994 	struct lsa_net		 lsa_net;
995 	int			 num_rtr = 0;
996 	u_int16_t		 chksum;
997 
998 	/* XXX IBUF_READ_SIZE */
999 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
1000 		fatal("orig_net_lsa");
1001 
1002 	/* reserve space for LSA header and options field */
1003 	if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_net)) == -1)
1004 		fatal("orig_net_lsa: ibuf_add_zero failed");
1005 
1006 	lsa_net.opts = 0;
1007 	/* fully adjacent neighbors + self */
1008 	LIST_FOREACH(nbr, &iface->nbr_list, entry)
1009 		if (nbr->state & NBR_STA_FULL) {
1010 			if (ibuf_add(buf, &nbr->id, sizeof(nbr->id)))
1011 				fatal("orig_net_lsa: ibuf_add failed");
1012 			lsa_net.opts |= nbr->link_options;
1013 			num_rtr++;
1014 		}
1015 
1016 	if (num_rtr == 1) {
1017 		/* non transit net therefore no need to generate a net lsa */
1018 		ibuf_free(buf);
1019 		return;
1020 	}
1021 
1022 	/* LSA header */
1023 	if (iface->state & IF_STA_DR)
1024 		lsa_hdr.age = htons(DEFAULT_AGE);
1025 	else
1026 		lsa_hdr.age = htons(MAX_AGE);
1027 
1028 	lsa_hdr.type = htons(LSA_TYPE_NETWORK);
1029 	/* for network LSAs, the link state ID equals the interface ID */
1030 	lsa_hdr.ls_id = htonl(iface->ifindex);
1031 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1032 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1033 	lsa_hdr.len = htons(ibuf_size(buf));
1034 	lsa_hdr.ls_chksum = 0;		/* updated later */
1035 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
1036 		fatal("orig_net_lsa: ibuf_set failed");
1037 
1038 	lsa_net.opts &= lsa_net.opts & htonl(LSA_24_MASK);
1039 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_net, sizeof(lsa_net)) == -1)
1040 		fatal("orig_net_lsa: ibuf_set failed");
1041 
1042 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
1043 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
1044 		fatal("orig_net_lsa: ibuf_set_n16 failed");
1045 
1046 	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1047 	    -1, ibuf_data(buf), ibuf_size(buf));
1048 
1049 	ibuf_free(buf);
1050 }
1051 
1052 void
1053 orig_link_lsa(struct iface *iface)
1054 {
1055 	struct lsa_hdr		 lsa_hdr;
1056 	struct lsa_link		 lsa_link;
1057 	struct lsa_prefix	 lsa_prefix;
1058 	struct ibuf		*buf;
1059 	struct iface_addr	*ia;
1060 	struct in6_addr		 prefix;
1061 	unsigned int		 num_prefix = 0;
1062 	u_int16_t		 chksum;
1063 	u_int32_t		 options;
1064 
1065 	log_debug("orig_link_lsa: interface %s", iface->name);
1066 
1067 	switch (iface->type) {
1068 	case IF_TYPE_VIRTUALLINK:	/* forbidden by rfc5340 */
1069 		return;
1070 	case IF_TYPE_BROADCAST:
1071 	case IF_TYPE_NBMA:
1072 		if ((iface->state & IF_STA_MULTI) == 0)
1073 			return;
1074 		break;
1075 	case IF_TYPE_POINTOPOINT:
1076 	case IF_TYPE_POINTOMULTIPOINT:
1077 		if ((iface->state & IF_STA_POINTTOPOINT) == 0)
1078 			return;
1079 		break;
1080 	default:
1081 		fatalx("orig_link_lsa: unknown interface type");
1082 	}
1083 
1084 	/* XXX IBUF_READ_SIZE */
1085 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr) + sizeof(lsa_link),
1086 	    IBUF_READ_SIZE)) == NULL)
1087 		fatal("orig_link_lsa");
1088 
1089 	/* reserve space for LSA header and LSA link header */
1090 	if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_link)) == -1)
1091 		fatal("orig_link_lsa: ibuf_add_zero failed");
1092 
1093 	/* link-local address, and all prefixes configured on interface */
1094 	TAILQ_FOREACH(ia, &iface->ifa_list, entry) {
1095 		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) {
1096 			log_debug("orig_link_lsa: link local address %s",
1097 			    log_in6addr(&ia->addr));
1098 			lsa_link.lladdr = ia->addr;
1099 			continue;
1100 		}
1101 
1102 		lsa_prefix.prefixlen = ia->prefixlen;
1103 		lsa_prefix.options = 0;
1104 		lsa_prefix.metric = 0;
1105 		inet6applymask(&prefix, &ia->addr, ia->prefixlen);
1106 		log_debug("orig_link_lsa: prefix %s", log_in6addr(&prefix));
1107 		if (ibuf_add(buf, &lsa_prefix, sizeof(lsa_prefix)))
1108 			fatal("orig_link_lsa: ibuf_add failed");
1109 		if (ibuf_add(buf, &prefix.s6_addr[0],
1110 		    LSA_PREFIXSIZE(ia->prefixlen)))
1111 			fatal("orig_link_lsa: ibuf_add failed");
1112 		num_prefix++;
1113 	}
1114 
1115 	/* LSA link header (lladdr has already been filled in above) */
1116 	LSA_24_SETHI(lsa_link.opts, iface->priority);
1117 	options = area_ospf_options(iface->area);
1118 	LSA_24_SETLO(lsa_link.opts, options);
1119 	lsa_link.opts = htonl(lsa_link.opts);
1120 	lsa_link.numprefix = htonl(num_prefix);
1121 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_link, sizeof(lsa_link)) == -1)
1122 		fatal("orig_link_lsa: ibuf_set failed");
1123 
1124 	/* LSA header */
1125 	lsa_hdr.age = htons(DEFAULT_AGE);
1126 	lsa_hdr.type = htons(LSA_TYPE_LINK);
1127 	/* for link LSAs, the link state ID equals the interface ID */
1128 	lsa_hdr.ls_id = htonl(iface->ifindex);
1129 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1130 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1131 	lsa_hdr.len = htons(ibuf_size(buf));
1132 	lsa_hdr.ls_chksum = 0;		/* updated later */
1133 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
1134 		fatal("orig_link_lsa: ibuf_set failed");
1135 
1136 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
1137 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
1138 		fatal("orig_link_lsa: ibuf_set_n16 failed");
1139 
1140 	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1141 	    -1, ibuf_data(buf), ibuf_size(buf));
1142 
1143 	ibuf_free(buf);
1144 }
1145 
1146 u_int32_t
1147 ospfe_router_id(void)
1148 {
1149 	return (oeconf->rtr_id.s_addr);
1150 }
1151 
1152 void
1153 ospfe_fib_update(int type)
1154 {
1155 	int	old = oe_nofib;
1156 
1157 	if (type == IMSG_CTL_FIB_COUPLE)
1158 		oe_nofib = 0;
1159 	if (type == IMSG_CTL_FIB_DECOUPLE)
1160 		oe_nofib = 1;
1161 	if (old != oe_nofib)
1162 		orig_rtr_lsa_all(NULL);
1163 }
1164 
1165 void
1166 ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
1167 {
1168 	struct area		*area;
1169 	struct iface		*iface;
1170 	struct ctl_iface	*ictl;
1171 
1172 	LIST_FOREACH(area, &oeconf->area_list, entry)
1173 		LIST_FOREACH(iface, &area->iface_list, entry)
1174 			if (idx == 0 || idx == iface->ifindex) {
1175 				ictl = if_to_ctl(iface);
1176 				imsg_compose_event(&c->iev,
1177 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
1178 				    ictl, sizeof(struct ctl_iface));
1179 			}
1180 }
1181 
1182 void
1183 ospfe_nbr_ctl(struct ctl_conn *c)
1184 {
1185 	struct area	*area;
1186 	struct iface	*iface;
1187 	struct nbr	*nbr;
1188 	struct ctl_nbr	*nctl;
1189 
1190 	LIST_FOREACH(area, &oeconf->area_list, entry)
1191 		LIST_FOREACH(iface, &area->iface_list, entry)
1192 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
1193 				if (iface->self != nbr) {
1194 					nctl = nbr_to_ctl(nbr);
1195 					imsg_compose_event(&c->iev,
1196 					    IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
1197 					    sizeof(struct ctl_nbr));
1198 				}
1199 			}
1200 
1201 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
1202 }
1203 
1204 void
1205 ospfe_demote_area(struct area *area, int active)
1206 {
1207 	struct demote_msg	dmsg;
1208 
1209 	if (ospfd_process != PROC_OSPF_ENGINE ||
1210 	    area->demote_group[0] == '\0')
1211 		return;
1212 
1213 	bzero(&dmsg, sizeof(dmsg));
1214 	strlcpy(dmsg.demote_group, area->demote_group,
1215 	    sizeof(dmsg.demote_group));
1216 	dmsg.level = area->demote_level;
1217 	if (active)
1218 		dmsg.level = -dmsg.level;
1219 
1220 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1221 }
1222 
1223 void
1224 ospfe_demote_iface(struct iface *iface, int active)
1225 {
1226 	struct demote_msg	dmsg;
1227 
1228 	if (ospfd_process != PROC_OSPF_ENGINE ||
1229 	    iface->demote_group[0] == '\0')
1230 		return;
1231 
1232 	bzero(&dmsg, sizeof(dmsg));
1233 	strlcpy(dmsg.demote_group, iface->demote_group,
1234 	sizeof(dmsg.demote_group));
1235 	if (active)
1236 		dmsg.level = -1;
1237 	else
1238 		dmsg.level = 1;
1239 
1240 	log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group,
1241 	    dmsg.level);
1242 
1243 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1244 }
1245