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