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