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