xref: /openbsd-src/usr.sbin/ospf6d/ospfe.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: ospfe.c,v 1.8 2007/12/13 08:54:05 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 "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("IFINFO 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 == 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 {
486 				/*
487 				 * flood on all area interfaces on
488 				 * area 0.0.0.0 include also virtual links.
489 				 */
490 				if ((area = area_find(oeconf,
491 				    nbr->iface->area_id)) == NULL)
492 					fatalx("interface lost area");
493 				LIST_FOREACH(iface, &area->iface_list, entry) {
494 					noack += lsa_flood(iface, nbr,
495 					    &lsa_hdr, imsg.data);
496 				}
497 				/* XXX virtual links */
498 			}
499 
500 			/* remove from ls_req_list */
501 			le = ls_req_list_get(nbr, &lsa_hdr);
502 			if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
503 				ls_req_list_free(nbr, le);
504 				/*
505 				 * XXX no need to ack requested lsa
506 				 * the problem is that the RFC is very
507 				 * unclear about this.
508 				 */
509 				noack = 1;
510 			}
511 
512 			if (!noack && nbr->iface != NULL &&
513 			    nbr->iface->self != nbr) {
514 				if (!(nbr->iface->state & IF_STA_BACKUP) ||
515 				    nbr->iface->dr == nbr) {
516 					/* delayed ack */
517 					lhp = lsa_hdr_new();
518 					memcpy(lhp, &lsa_hdr, sizeof(*lhp));
519 					ls_ack_list_add(nbr->iface, lhp);
520 				}
521 			}
522 
523 			lsa_cache_put(ref, nbr);
524 			break;
525 		case IMSG_LS_UPD:
526 			/*
527 			 * IMSG_LS_UPD is used in three cases:
528 			 * 1. as response to ls requests
529 			 * 2. as response to ls updates where the DB
530 			 *    is newer then the sent LSA
531 			 * 3. in EXSTART when the LSA has age MaxAge
532 			 */
533 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
534 			if (l < sizeof(lsa_hdr))
535 				fatalx("ospfe_dispatch_rde: "
536 				    "bad imsg size");
537 
538 			nbr = nbr_find_peerid(imsg.hdr.peerid);
539 			if (nbr == NULL)
540 				break;
541 
542 			if (nbr->iface->self == nbr)
543 				break;
544 
545 			memcpy(&age, imsg.data, sizeof(age));
546 			ref = lsa_cache_add(imsg.data, l);
547 			if (ntohs(age) >= MAX_AGE)
548 				/* add to retransmit list */
549 				ls_retrans_list_add(nbr, imsg.data, 0, 0);
550 			else
551 				ls_retrans_list_add(nbr, imsg.data, 0, 1);
552 
553 			lsa_cache_put(ref, nbr);
554 			break;
555 		case IMSG_LS_ACK:
556 			/*
557 			 * IMSG_LS_ACK is used in two cases:
558 			 * 1. LSA was a duplicate
559 			 * 2. LS age is MaxAge and there is no current
560 			 *    instance in the DB plus no neighbor in state
561 			 *    Exchange or Loading
562 			 */
563 			nbr = nbr_find_peerid(imsg.hdr.peerid);
564 			if (nbr == NULL)
565 				break;
566 
567 			if (nbr->iface->self == nbr)
568 				break;
569 
570 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr))
571 				fatalx("ospfe_dispatch_rde: bad imsg size");
572 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
573 
574 			/* for case one check for implied acks */
575 			if (nbr->iface->state & IF_STA_DROTHER)
576 				if (ls_retrans_list_del(nbr->iface->self,
577 				    &lsa_hdr) == 0)
578 					break;
579 			if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
580 				break;
581 
582 			/* send a direct acknowledgement */
583 			send_ls_ack(nbr->iface, nbr->addr, imsg.data,
584 			    imsg.hdr.len - IMSG_HEADER_SIZE);
585 
586 			break;
587 		case IMSG_LS_BADREQ:
588 			nbr = nbr_find_peerid(imsg.hdr.peerid);
589 			if (nbr == NULL)
590 				break;
591 
592 			if (nbr->iface->self == nbr)
593 				fatalx("ospfe_dispatch_rde: "
594 				    "dummy neighbor got BADREQ");
595 
596 			nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
597 			break;
598 		case IMSG_ABR_UP:
599 			memcpy(&ar, imsg.data, sizeof(ar));
600 
601 			if ((iface = find_vlink(&ar)) != NULL &&
602 			    iface->state == IF_STA_DOWN)
603 				if (if_fsm(iface, IF_EVT_UP)) {
604 					log_debug("error starting interface %s",
605 					    iface->name);
606 				}
607 			break;
608 		case IMSG_ABR_DOWN:
609 			memcpy(&ar, imsg.data, sizeof(ar));
610 
611 			if ((iface = find_vlink(&ar)) != NULL &&
612 			    iface->state == IF_STA_POINTTOPOINT)
613 				if (if_fsm(iface, IF_EVT_DOWN)) {
614 					log_debug("error stopping interface %s",
615 					    iface->name);
616 				}
617 			break;
618 		case IMSG_CTL_AREA:
619 		case IMSG_CTL_IFACE:
620 		case IMSG_CTL_END:
621 		case IMSG_CTL_SHOW_DATABASE:
622 		case IMSG_CTL_SHOW_DB_EXT:
623 		case IMSG_CTL_SHOW_DB_NET:
624 		case IMSG_CTL_SHOW_DB_RTR:
625 		case IMSG_CTL_SHOW_DB_SELF:
626 		case IMSG_CTL_SHOW_DB_SUM:
627 		case IMSG_CTL_SHOW_DB_ASBR:
628 		case IMSG_CTL_SHOW_RIB:
629 		case IMSG_CTL_SHOW_SUM:
630 		case IMSG_CTL_SHOW_SUM_AREA:
631 			control_imsg_relay(&imsg);
632 			break;
633 		default:
634 			log_debug("ospfe_dispatch_rde: error handling imsg %d",
635 			    imsg.hdr.type);
636 			break;
637 		}
638 		imsg_free(&imsg);
639 	}
640 	if (!shut)
641 		imsg_event_add(ibuf);
642 	else {
643 		/* this pipe is dead, so remove the event handler */
644 		event_del(&ibuf->ev);
645 		event_loopexit(NULL);
646 	}
647 }
648 
649 struct iface *
650 find_vlink(struct abr_rtr *ar)
651 {
652 	struct area	*area;
653 	struct iface	*iface = NULL;
654 
655 	LIST_FOREACH(area, &oeconf->area_list, entry)
656 		LIST_FOREACH(iface, &area->iface_list, entry)
657 			if (iface->abr_id.s_addr == ar->abr_id.s_addr &&
658 			    iface->type == IF_TYPE_VIRTUALLINK &&
659 //XXX			    iface->area->id.s_addr == ar->area.s_addr) {
660 			    iface->area_id.s_addr == ar->area.s_addr) {
661 //XXX				iface->dst.s_addr = ar->dst_ip.s_addr;
662 				iface->dst = ar->dst_ip;
663 //XXX				iface->addr.s_addr = ar->addr.s_addr;
664 				iface->addr = ar->addr;
665 				iface->metric = ar->metric;
666 
667 				return (iface);
668 			}
669 
670 	return (iface);
671 }
672 
673 void
674 orig_rtr_lsa_all(struct area *area)
675 {
676 	struct area	*a;
677 
678 	/*
679 	 * update all router LSA in all areas except area itself,
680 	 * as this update is already running.
681 	 */
682 	LIST_FOREACH(a, &oeconf->area_list, entry)
683 		if (a != area)
684 			orig_rtr_lsa_area(a);
685 }
686 
687 void
688 orig_rtr_lsa(struct iface *iface)
689 {
690 	struct area	*area;
691 
692 	if ((area = area_find(oeconf, iface->area_id)) == NULL)
693 		fatalx("interface lost area");
694 	orig_rtr_lsa_area(area);
695 }
696 
697 void
698 orig_rtr_lsa_area(struct area *area)
699 {
700 #if 0 /* XXX needs work */
701 	struct lsa_hdr		 lsa_hdr;
702 	struct lsa_rtr		 lsa_rtr;
703 	struct lsa_rtr_link	 rtr_link;
704 	struct iface		*iface;
705 	struct buf		*buf;
706 	struct nbr		*nbr, *self = NULL;
707 	u_int16_t		 num_links = 0;
708 	u_int16_t		 chksum;
709 	u_int8_t		 border, virtual = 0;
710 
711 	log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
712 
713 	/* XXX READ_BUF_SIZE */
714 	if ((buf = buf_dynamic(sizeof(lsa_hdr), READ_BUF_SIZE)) == NULL)
715 		fatal("orig_rtr_lsa");
716 
717 	/* reserve space for LSA header and LSA Router header */
718 	if (buf_reserve(buf, sizeof(lsa_hdr)) == NULL)
719 		fatal("orig_rtr_lsa: buf_reserve failed");
720 
721 	if (buf_reserve(buf, sizeof(lsa_rtr)) == NULL)
722 		fatal("orig_rtr_lsa: buf_reserve failed");
723 
724 	/* links */
725 	LIST_FOREACH(iface, &area->iface_list, entry) {
726 		if (self == NULL && iface->self != NULL)
727 			self = iface->self;
728 
729 		bzero(&rtr_link, sizeof(rtr_link));
730 
731 		if (iface->state & IF_STA_LOOPBACK) {
732 //XXX			rtr_link.id = iface->addr.s_addr;
733 			rtr_link.data = 0xffffffff;
734 			rtr_link.type = LINK_TYPE_STUB_NET;
735 			rtr_link.metric = htons(iface->metric);
736 			num_links++;
737 			if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
738 				fatalx("orig_rtr_lsa: buf_add failed");
739 			continue;
740 		}
741 
742 		switch (iface->type) {
743 		case IF_TYPE_POINTOPOINT:
744 			LIST_FOREACH(nbr, &iface->nbr_list, entry)
745 				if (nbr != iface->self &&
746 				    nbr->state & NBR_STA_FULL)
747 					break;
748 			if (nbr) {
749 				log_debug("orig_rtr_lsa: point-to-point, "
750 				    "interface %s", iface->name);
751 				rtr_link.id = nbr->id.s_addr;
752 //XXX				rtr_link.data = iface->addr.s_addr;
753 				rtr_link.type = LINK_TYPE_POINTTOPOINT;
754 				/* RFC 3137: stub router support */
755 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
756 				    oe_nofib)
757 					rtr_link.metric = 0xffff;
758 				else
759 					rtr_link.metric = htons(iface->metric);
760 				num_links++;
761 				if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
762 					fatalx("orig_rtr_lsa: buf_add failed");
763 			}
764 			if (iface->state & IF_STA_POINTTOPOINT) {
765 				log_debug("orig_rtr_lsa: stub net, "
766 				    "interface %s", iface->name);
767 				bzero(&rtr_link, sizeof(rtr_link));
768 				if (nbr) {
769 //XXX					rtr_link.id = nbr->addr.s_addr;
770 					rtr_link.data = 0xffffffff;
771 				} else {
772 //XXX					rtr_link.id = iface->addr.s_addr;
773 //XXX					rtr_link.data = iface->mask.s_addr;
774 				}
775 				rtr_link.type = LINK_TYPE_STUB_NET;
776 				rtr_link.metric = htons(iface->metric);
777 				num_links++;
778 				if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
779 					fatalx("orig_rtr_lsa: buf_add failed");
780 			}
781 			continue;
782 		case IF_TYPE_BROADCAST:
783 		case IF_TYPE_NBMA:
784 			if ((iface->state & IF_STA_MULTI)) {
785 				if (iface->dr == iface->self) {
786 					LIST_FOREACH(nbr, &iface->nbr_list,
787 					    entry)
788 						if (nbr != iface->self &&
789 						    nbr->state & NBR_STA_FULL)
790 							break;
791 				} else
792 					nbr = iface->dr;
793 
794 				if (nbr && nbr->state & NBR_STA_FULL) {
795 					log_debug("orig_rtr_lsa: transit net, "
796 					    "interface %s", iface->name);
797 
798 //XXX					rtr_link.id = iface->dr->addr.s_addr;
799 //XXX					rtr_link.data = iface->addr.s_addr;
800 					rtr_link.type = LINK_TYPE_TRANSIT_NET;
801 					break;
802 				}
803 			}
804 
805 			if ((iface->flags & IFF_UP) == 0 ||
806 			    iface->linkstate == LINK_STATE_DOWN ||
807 			    (!LINK_STATE_IS_UP(iface->linkstate) &&
808 			    iface->media_type == IFT_CARP))
809 				continue;
810 
811 			log_debug("orig_rtr_lsa: stub net, "
812 			    "interface %s", iface->name);
813 
814 /*XXX			rtr_link.id =
815 			    iface->addr.s_addr & iface->mask.s_addr;
816 			rtr_link.data = iface->mask.s_addr;
817 XXX*/
818 			rtr_link.type = LINK_TYPE_STUB_NET;
819 			break;
820 		case IF_TYPE_VIRTUALLINK:
821 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
822 				if (nbr != iface->self &&
823 				    nbr->state & NBR_STA_FULL)
824 					break;
825 			}
826 			if (nbr) {
827 				rtr_link.id = nbr->id.s_addr;
828 //XXX				rtr_link.data = iface->addr.s_addr;
829 				rtr_link.type = LINK_TYPE_VIRTUAL;
830 				/* RFC 3137: stub router support */
831 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
832 				    oe_nofib)
833 					rtr_link.metric = 0xffff;
834 				else
835 					rtr_link.metric = htons(iface->metric);
836 				num_links++;
837 				virtual = 1;
838 				if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
839 					fatalx("orig_rtr_lsa: buf_add failed");
840 
841 				log_debug("orig_rtr_lsa: virtual link, "
842 				    "interface %s", iface->name);
843 			}
844 			continue;
845 		case IF_TYPE_POINTOMULTIPOINT:
846 			log_debug("orig_rtr_lsa: stub net, "
847 			    "interface %s", iface->name);
848 //XXX			rtr_link.id = iface->addr.s_addr;
849 			rtr_link.data = 0xffffffff;
850 			rtr_link.type = LINK_TYPE_STUB_NET;
851 			rtr_link.metric = htons(iface->metric);
852 			num_links++;
853 			if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
854 				fatalx("orig_rtr_lsa: buf_add failed");
855 
856 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
857 				if (nbr != iface->self &&
858 				    nbr->state & NBR_STA_FULL) {
859 					bzero(&rtr_link, sizeof(rtr_link));
860 					log_debug("orig_rtr_lsa: "
861 					    "point-to-multipoint, interface %s",
862 					    iface->name);
863 //XXX					rtr_link.id = nbr->addr.s_addr;
864 //XXX					rtr_link.data = iface->addr.s_addr;
865 					rtr_link.type = LINK_TYPE_POINTTOPOINT;
866 					/* RFC 3137: stub router support */
867 					if (oe_nofib || oeconf->flags &
868 					    OSPFD_FLAG_STUB_ROUTER)
869 						rtr_link.metric = 0xffff;
870 					else
871 						rtr_link.metric =
872 						    htons(iface->metric);
873 					num_links++;
874 					if (buf_add(buf, &rtr_link,
875 					    sizeof(rtr_link)))
876 						fatalx("orig_rtr_lsa: "
877 						    "buf_add failed");
878 				}
879 			}
880 			continue;
881 		default:
882 			fatalx("orig_rtr_lsa: unknown interface type");
883 		}
884 
885 		rtr_link.num_tos = 0;
886 		/* RFC 3137: stub router support */
887 		if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER || oe_nofib) &&
888 		    rtr_link.type != LINK_TYPE_STUB_NET)
889 			rtr_link.metric = 0xffff;
890 		else
891 			rtr_link.metric = htons(iface->metric);
892 		num_links++;
893 		if (buf_add(buf, &rtr_link, sizeof(rtr_link)))
894 			fatalx("orig_rtr_lsa: buf_add failed");
895 	}
896 
897 	/* LSA router header */
898 	lsa_rtr.flags = 0;
899 	/*
900 	 * Set the E bit as soon as an as-ext lsa may be redistributed, only
901 	 * setting it in case we redistribute something is not worth the fuss.
902 	 */
903 	if (oeconf->redistribute && !area->stub)
904 		lsa_rtr.flags |= OSPF_RTR_E;
905 
906 	border = (area_border_router(oeconf) != 0);
907 	if (border != oeconf->border) {
908 		oeconf->border = border;
909 		orig_rtr_lsa_all(area);
910 	}
911 
912 	if (oeconf->border)
913 		lsa_rtr.flags |= OSPF_RTR_B;
914 	/* TODO set V flag if a active virtual link ends here and the
915 	 * area is the tranist area for this link. */
916 	if (virtual)
917 		lsa_rtr.flags |= OSPF_RTR_V;
918 
919 	lsa_rtr.dummy = 0;
920 	lsa_rtr.nlinks = htons(num_links);
921 	memcpy(buf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_rtr)),
922 	    &lsa_rtr, sizeof(lsa_rtr));
923 
924 	/* LSA header */
925 	lsa_hdr.age = htons(DEFAULT_AGE);
926 	lsa_hdr.type = LSA_TYPE_ROUTER;
927 	lsa_hdr.ls_id = oeconf->rtr_id.s_addr;
928 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
929 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
930 	lsa_hdr.len = htons(buf->wpos);
931 	lsa_hdr.ls_chksum = 0;		/* updated later */
932 	memcpy(buf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr));
933 
934 	chksum = htons(iso_cksum(buf->buf, buf->wpos, LS_CKSUM_OFFSET));
935 	memcpy(buf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)),
936 	    &chksum, sizeof(chksum));
937 
938 	if (self)
939 		imsg_compose(ibuf_rde, IMSG_LS_UPD, self->peerid, 0,
940 		    buf->buf, buf->wpos);
941 	else
942 		log_warnx("orig_rtr_lsa: empty area %s",
943 		    inet_ntoa(area->id));
944 
945 	buf_free(buf);
946 #endif
947 }
948 
949 void
950 orig_net_lsa(struct iface *iface)
951 {
952 #if 0	/* XXX needs work */
953 	struct lsa_hdr		 lsa_hdr;
954 	struct nbr		*nbr;
955 	struct buf		*buf;
956 	int			 num_rtr = 0;
957 	u_int16_t		 chksum;
958 
959 	/* XXX READ_BUF_SIZE */
960 	if ((buf = buf_dynamic(sizeof(lsa_hdr), READ_BUF_SIZE)) == NULL)
961 		fatal("orig_net_lsa");
962 
963 	/* reserve space for LSA header and LSA Router header */
964 	if (buf_reserve(buf, sizeof(lsa_hdr)) == NULL)
965 		fatal("orig_net_lsa: buf_reserve failed");
966 
967 	/* LSA net mask and then all fully adjacent routers */
968 	if (buf_add(buf, &iface->mask, sizeof(iface->mask)))
969 		fatal("orig_net_lsa: buf_add failed");
970 
971 	/* fully adjacent neighbors + self */
972 	LIST_FOREACH(nbr, &iface->nbr_list, entry)
973 		if (nbr->state & NBR_STA_FULL) {
974 			if (buf_add(buf, &nbr->id, sizeof(nbr->id)))
975 				fatal("orig_net_lsa: buf_add failed");
976 			num_rtr++;
977 		}
978 
979 	if (num_rtr == 1) {
980 		/* non transit net therefor no need to generate a net lsa */
981 		buf_free(buf);
982 		return;
983 	}
984 
985 	/* LSA header */
986 	if (iface->state & IF_STA_DR)
987 		lsa_hdr.age = htons(DEFAULT_AGE);
988 	else
989 		lsa_hdr.age = htons(MAX_AGE);
990 
991 	lsa_hdr.type = LSA_TYPE_NETWORK;
992 //XXX	lsa_hdr.ls_id = iface->addr.s_addr;
993 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
994 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
995 	lsa_hdr.len = htons(buf->wpos);
996 	lsa_hdr.ls_chksum = 0;		/* updated later */
997 	memcpy(buf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr));
998 
999 	chksum = htons(iso_cksum(buf->buf, buf->wpos, LS_CKSUM_OFFSET));
1000 	memcpy(buf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)),
1001 	    &chksum, sizeof(chksum));
1002 
1003 	imsg_compose(ibuf_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1004 	    buf->buf, buf->wpos);
1005 
1006 	buf_free(buf);
1007 #endif
1008 }
1009 
1010 u_int32_t
1011 ospfe_router_id(void)
1012 {
1013 	return (oeconf->rtr_id.s_addr);
1014 }
1015 
1016 void
1017 ospfe_fib_update(int type)
1018 {
1019 	int	old = oe_nofib;
1020 
1021 	if (type == IMSG_CTL_FIB_COUPLE)
1022 		oe_nofib = 0;
1023 	if (type == IMSG_CTL_FIB_DECOUPLE)
1024 		oe_nofib = 1;
1025 	if (old != oe_nofib)
1026 		orig_rtr_lsa_all(NULL);
1027 }
1028 
1029 void
1030 ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
1031 {
1032 	struct area		*area;
1033 	struct iface		*iface;
1034 	struct ctl_iface	*ictl;
1035 
1036 	LIST_FOREACH(area, &oeconf->area_list, entry)
1037 		LIST_FOREACH(iface, &area->iface_list, entry)
1038 			if (idx == 0 || idx == iface->ifindex) {
1039 				ictl = if_to_ctl(iface);
1040 				imsg_compose(&c->ibuf, IMSG_CTL_SHOW_INTERFACE,
1041 				    0, 0, ictl, sizeof(struct ctl_iface));
1042 			}
1043 }
1044 
1045 void
1046 ospfe_nbr_ctl(struct ctl_conn *c)
1047 {
1048 	struct area	*area;
1049 	struct iface	*iface;
1050 	struct nbr	*nbr;
1051 	struct ctl_nbr	*nctl;
1052 
1053 	LIST_FOREACH(area, &oeconf->area_list, entry)
1054 		LIST_FOREACH(iface, &area->iface_list, entry)
1055 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
1056 				if (iface->self != nbr) {
1057 					nctl = nbr_to_ctl(nbr);
1058 					imsg_compose(&c->ibuf,
1059 					    IMSG_CTL_SHOW_NBR, 0, 0, nctl,
1060 					    sizeof(struct ctl_nbr));
1061 				}
1062 			}
1063 
1064 	imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, NULL, 0);
1065 }
1066 
1067 void
1068 ospfe_demote_area(struct area *area, int active)
1069 {
1070 	struct demote_msg	dmsg;
1071 
1072 	if (ospfd_process != PROC_OSPF_ENGINE ||
1073 	    area->demote_group[0] == '\0')
1074 		return;
1075 
1076 	bzero(&dmsg, sizeof(dmsg));
1077 	strlcpy(dmsg.demote_group, area->demote_group,
1078 	sizeof(dmsg.demote_group));
1079 	dmsg.level = area->demote_level;
1080 	if (active)
1081 		dmsg.level = -dmsg.level;
1082 
1083 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1084 }
1085 
1086 void
1087 ospfe_demote_iface(struct iface *iface, int active)
1088 {
1089 	struct demote_msg	dmsg;
1090 
1091 	if (ospfd_process != PROC_OSPF_ENGINE ||
1092 	    iface->demote_group[0] == '\0')
1093 		return;
1094 
1095 	bzero(&dmsg, sizeof(dmsg));
1096 	strlcpy(dmsg.demote_group, iface->demote_group,
1097 	sizeof(dmsg.demote_group));
1098 	if (active)
1099 		dmsg.level = -1;
1100 	else
1101 		dmsg.level = 1;
1102 
1103 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1104 }
1105