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