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