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