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