xref: /openbsd-src/usr.sbin/ospf6d/ospfe.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: ospfe.c,v 1.78 2024/11/21 13:38:14 claudio Exp $ */
2a1a4e97bSnorby 
3a1a4e97bSnorby /*
4a1a4e97bSnorby  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5a1a4e97bSnorby  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6a1a4e97bSnorby  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7a1a4e97bSnorby  *
8a1a4e97bSnorby  * Permission to use, copy, modify, and distribute this software for any
9a1a4e97bSnorby  * purpose with or without fee is hereby granted, provided that the above
10a1a4e97bSnorby  * copyright notice and this permission notice appear in all copies.
11a1a4e97bSnorby  *
12a1a4e97bSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13a1a4e97bSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14a1a4e97bSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15a1a4e97bSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16a1a4e97bSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17a1a4e97bSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18a1a4e97bSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19a1a4e97bSnorby  */
20a1a4e97bSnorby 
21a1a4e97bSnorby #include <sys/types.h>
22a1a4e97bSnorby #include <sys/socket.h>
23a1a4e97bSnorby #include <sys/queue.h>
24a1a4e97bSnorby #include <netinet/in.h>
25a1a4e97bSnorby #include <arpa/inet.h>
26a1a4e97bSnorby #include <net/if_types.h>
27a1a4e97bSnorby #include <stdlib.h>
28a1a4e97bSnorby #include <signal.h>
29a1a4e97bSnorby #include <string.h>
30a1a4e97bSnorby #include <fcntl.h>
31a1a4e97bSnorby #include <pwd.h>
32a1a4e97bSnorby #include <unistd.h>
33a1a4e97bSnorby #include <event.h>
34a1a4e97bSnorby #include <err.h>
35a1a4e97bSnorby #include <errno.h>
36a1a4e97bSnorby #include <stdio.h>
37a1a4e97bSnorby 
38a1a4e97bSnorby #include "ospf6.h"
39a1a4e97bSnorby #include "ospf6d.h"
40a1a4e97bSnorby #include "ospfe.h"
41a1a4e97bSnorby #include "rde.h"
42a1a4e97bSnorby #include "control.h"
43a1a4e97bSnorby #include "log.h"
44a1a4e97bSnorby 
45a1a4e97bSnorby void		 ospfe_sig_handler(int, short, void *);
46ee103ef4Srenato __dead void	 ospfe_shutdown(void);
47a1a4e97bSnorby void		 orig_rtr_lsa_all(struct area *);
48a1a4e97bSnorby struct iface	*find_vlink(struct abr_rtr *);
49a1a4e97bSnorby 
5077138d9fSclaudio struct ospfd_conf	*oeconf = NULL, *noeconf;
51ccbb71f5Sclaudio static struct imsgev	*iev_main;
52ccbb71f5Sclaudio static struct imsgev	*iev_rde;
53a1a4e97bSnorby int			 oe_nofib;
54a1a4e97bSnorby 
55a1a4e97bSnorby void
56a1a4e97bSnorby ospfe_sig_handler(int sig, short event, void *bula)
57a1a4e97bSnorby {
58a1a4e97bSnorby 	switch (sig) {
59a1a4e97bSnorby 	case SIGINT:
60a1a4e97bSnorby 	case SIGTERM:
61a1a4e97bSnorby 		ospfe_shutdown();
62a1a4e97bSnorby 		/* NOTREACHED */
63a1a4e97bSnorby 	default:
64a1a4e97bSnorby 		fatalx("unexpected signal");
65a1a4e97bSnorby 	}
66a1a4e97bSnorby }
67a1a4e97bSnorby 
68a1a4e97bSnorby /* ospf engine */
69a1a4e97bSnorby pid_t
70a1a4e97bSnorby ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2],
71a1a4e97bSnorby     int pipe_parent2rde[2])
72a1a4e97bSnorby {
73a1a4e97bSnorby 	struct area	*area;
74a1a4e97bSnorby 	struct iface	*iface;
75a1a4e97bSnorby 	struct passwd	*pw;
76a1a4e97bSnorby 	struct event	 ev_sigint, ev_sigterm;
77a1a4e97bSnorby 	pid_t		 pid;
783b835e81Sjob 	int		 pre = IPTOS_PREC_INTERNETCONTROL;
79a1a4e97bSnorby 
80a1a4e97bSnorby 	switch (pid = fork()) {
81a1a4e97bSnorby 	case -1:
82a1a4e97bSnorby 		fatal("cannot fork");
83a1a4e97bSnorby 	case 0:
84a1a4e97bSnorby 		break;
85a1a4e97bSnorby 	default:
86a1a4e97bSnorby 		return (pid);
87a1a4e97bSnorby 	}
88a1a4e97bSnorby 
89a1a4e97bSnorby 	/* create the raw ip socket */
9035251ca5Sclaudio 	if ((xconf->ospf_socket = socket(AF_INET6,
9135251ca5Sclaudio 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_OSPF)) == -1)
92a1a4e97bSnorby 		fatal("error creating raw socket");
93a1a4e97bSnorby 
943b835e81Sjob 	if (setsockopt(xconf->ospf_socket, IPPROTO_IPV6, IPV6_TCLASS, &pre,
953b835e81Sjob 	    sizeof(pre)) == -1)
963b835e81Sjob 		fatal("setsockopt IPV6_TCLASS");
973b835e81Sjob 
98a1a4e97bSnorby 	/* set some defaults */
99a1a4e97bSnorby 	if (if_set_mcast_loop(xconf->ospf_socket) == -1)
100a1a4e97bSnorby 		fatal("if_set_mcast_loop");
10177b36df3Sclaudio 	if (if_set_ipv6_checksum(xconf->ospf_socket) == -1)
10277b36df3Sclaudio 		fatal("if_set_ipv6_checksum");
10377b36df3Sclaudio 	if (if_set_ipv6_pktinfo(xconf->ospf_socket, 1) == -1)
10477b36df3Sclaudio 		fatal("if_set_ipv6_pktinfo");
105678bb30aSdenis 	if_set_sockbuf(xconf->ospf_socket);
106a1a4e97bSnorby 
107a1a4e97bSnorby 	oeconf = xconf;
108a1a4e97bSnorby 	if (oeconf->flags & OSPFD_FLAG_NO_FIB_UPDATE)
109a1a4e97bSnorby 		oe_nofib = 1;
110a1a4e97bSnorby 
111a1a4e97bSnorby 	if ((pw = getpwnam(OSPF6D_USER)) == NULL)
112a1a4e97bSnorby 		fatal("getpwnam");
113a1a4e97bSnorby 
114a1a4e97bSnorby 	if (chroot(pw->pw_dir) == -1)
115a1a4e97bSnorby 		fatal("chroot");
116a1a4e97bSnorby 	if (chdir("/") == -1)
117a1a4e97bSnorby 		fatal("chdir(\"/\")");
118a1a4e97bSnorby 
119a1a4e97bSnorby 	setproctitle("ospf engine");
120189fd1ceSbenno 	/*
121189fd1ceSbenno 	 * XXX needed with fork+exec
122189fd1ceSbenno 	 * log_init(debug, LOG_DAEMON);
123189fd1ceSbenno 	 * log_setverbose(verbose);
124189fd1ceSbenno 	 */
125189fd1ceSbenno 
126a1a4e97bSnorby 	ospfd_process = PROC_OSPF_ENGINE;
127189fd1ceSbenno 	log_procinit(log_procnames[ospfd_process]);
128a1a4e97bSnorby 
129a1a4e97bSnorby 	if (setgroups(1, &pw->pw_gid) ||
130a1a4e97bSnorby 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
131a1a4e97bSnorby 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
132a1a4e97bSnorby 		fatal("can't drop privileges");
133a1a4e97bSnorby 
134cb75d791Sremi 	if (pledge("stdio inet mcast recvfd", NULL) == -1)
135b165ff27Sfriehm 		fatal("pledge");
136b165ff27Sfriehm 
137a1a4e97bSnorby 	event_init();
138a1a4e97bSnorby 	nbr_init(NBR_HASHSIZE);
139a1a4e97bSnorby 	lsa_cache_init(LSA_HASHSIZE);
140a1a4e97bSnorby 
141a1a4e97bSnorby 	/* setup signal handler */
142a1a4e97bSnorby 	signal_set(&ev_sigint, SIGINT, ospfe_sig_handler, NULL);
143a1a4e97bSnorby 	signal_set(&ev_sigterm, SIGTERM, ospfe_sig_handler, NULL);
144a1a4e97bSnorby 	signal_add(&ev_sigint, NULL);
145a1a4e97bSnorby 	signal_add(&ev_sigterm, NULL);
146a1a4e97bSnorby 	signal(SIGPIPE, SIG_IGN);
147a1a4e97bSnorby 	signal(SIGHUP, SIG_IGN);
148a1a4e97bSnorby 
149a1a4e97bSnorby 	/* setup pipes */
150a1a4e97bSnorby 	close(pipe_parent2ospfe[0]);
151a1a4e97bSnorby 	close(pipe_ospfe2rde[1]);
152a1a4e97bSnorby 	close(pipe_parent2rde[0]);
153a1a4e97bSnorby 	close(pipe_parent2rde[1]);
154a1a4e97bSnorby 
155f78850efSeric 	if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL ||
156f78850efSeric 	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
157a1a4e97bSnorby 		fatal(NULL);
158*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_rde->ibuf, pipe_ospfe2rde[0]) == -1)
159*f1b790a5Sclaudio 		fatal(NULL);
160f78850efSeric 	iev_rde->handler = ospfe_dispatch_rde;
161*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_main->ibuf, pipe_parent2ospfe[1]) == -1)
162*f1b790a5Sclaudio 		fatal(NULL);
163*f1b790a5Sclaudio 	imsgbuf_allow_fdpass(&iev_main->ibuf);
164f78850efSeric 	iev_main->handler = ospfe_dispatch_main;
165a1a4e97bSnorby 
166a1a4e97bSnorby 	/* setup event handler */
167f78850efSeric 	iev_rde->events = EV_READ;
168f78850efSeric 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
169f78850efSeric 	    iev_rde->handler, iev_rde);
170f78850efSeric 	event_add(&iev_rde->ev, NULL);
171a1a4e97bSnorby 
172f78850efSeric 	iev_main->events = EV_READ;
173f78850efSeric 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
174f78850efSeric 	    iev_main->handler, iev_main);
175f78850efSeric 	event_add(&iev_main->ev, NULL);
176a1a4e97bSnorby 
177a1a4e97bSnorby 	event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST,
178a1a4e97bSnorby 	    recv_packet, oeconf);
179a1a4e97bSnorby 	event_add(&oeconf->ev, NULL);
180a1a4e97bSnorby 
181a1a4e97bSnorby 	/* remove unneeded config stuff */
18202570afaSremi 	conf_clear_redist_list(&oeconf->redist_list);
183a1a4e97bSnorby 
184a1a4e97bSnorby 	/* start interfaces */
185a1a4e97bSnorby 	LIST_FOREACH(area, &oeconf->area_list, entry) {
186a1a4e97bSnorby 		ospfe_demote_area(area, 0);
1876c9e7a5bSclaudio 		LIST_FOREACH(iface, &area->iface_list, entry)
1886c9e7a5bSclaudio 			if_start(xconf, iface);
189a1a4e97bSnorby 	}
190a1a4e97bSnorby 
191a1a4e97bSnorby 	event_dispatch();
192a1a4e97bSnorby 
193a1a4e97bSnorby 	ospfe_shutdown();
194a1a4e97bSnorby 	/* NOTREACHED */
195a1a4e97bSnorby 	return (0);
196a1a4e97bSnorby }
197a1a4e97bSnorby 
198ee103ef4Srenato __dead void
199a1a4e97bSnorby ospfe_shutdown(void)
200a1a4e97bSnorby {
201a1a4e97bSnorby 	struct area	*area;
202a1a4e97bSnorby 	struct iface	*iface;
203a1a4e97bSnorby 
204ee103ef4Srenato 	/* close pipes */
205dd7efffeSclaudio 	imsgbuf_write(&iev_rde->ibuf);
2069cbf9e90Sclaudio 	imsgbuf_clear(&iev_rde->ibuf);
207ee103ef4Srenato 	close(iev_rde->ibuf.fd);
208dd7efffeSclaudio 	imsgbuf_write(&iev_main->ibuf);
2099cbf9e90Sclaudio 	imsgbuf_clear(&iev_main->ibuf);
210ee103ef4Srenato 	close(iev_main->ibuf.fd);
211ee103ef4Srenato 
212a1a4e97bSnorby 	/* stop all interfaces and remove all areas */
213a1a4e97bSnorby 	while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) {
214a1a4e97bSnorby 		LIST_FOREACH(iface, &area->iface_list, entry) {
215a1a4e97bSnorby 			if (if_fsm(iface, IF_EVT_DOWN)) {
216a1a4e97bSnorby 				log_debug("error stopping interface %s",
217a1a4e97bSnorby 				    iface->name);
218a1a4e97bSnorby 			}
219a1a4e97bSnorby 		}
220a1a4e97bSnorby 		LIST_REMOVE(area, entry);
221a1a4e97bSnorby 		area_del(area);
222a1a4e97bSnorby 	}
223a1a4e97bSnorby 
224a1a4e97bSnorby 	close(oeconf->ospf_socket);
225a1a4e97bSnorby 
226a1a4e97bSnorby 	/* clean up */
227f78850efSeric 	free(iev_rde);
228f78850efSeric 	free(iev_main);
229a1a4e97bSnorby 	free(oeconf);
230a1a4e97bSnorby 
231a1a4e97bSnorby 	log_info("ospf engine exiting");
232a1a4e97bSnorby 	_exit(0);
233a1a4e97bSnorby }
234a1a4e97bSnorby 
235a1a4e97bSnorby /* imesg */
236a1a4e97bSnorby int
237a1a4e97bSnorby ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
238a1a4e97bSnorby {
239f78850efSeric 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
240a1a4e97bSnorby }
241a1a4e97bSnorby 
242a1a4e97bSnorby int
243a1a4e97bSnorby ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
244a1a4e97bSnorby     void *data, u_int16_t datalen)
245a1a4e97bSnorby {
246f78850efSeric 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
247f78850efSeric 	    data, datalen));
248a1a4e97bSnorby }
249a1a4e97bSnorby 
250a1a4e97bSnorby void
251a1a4e97bSnorby ospfe_dispatch_main(int fd, short event, void *bula)
252a1a4e97bSnorby {
253a1a4e97bSnorby 	static struct area	*narea;
254f11dc975Sbluhm 	struct area		*area;
255a66c91f2Sremi 	struct iface		*iface, *ifp, *i;
2568e1674f3Sbluhm 	struct ifaddrchange	*ifc;
2578e1674f3Sbluhm 	struct iface_addr	*ia, *nia;
258a1a4e97bSnorby 	struct imsg		 imsg;
259f78850efSeric 	struct imsgev		*iev = bula;
260f78850efSeric 	struct imsgbuf		*ibuf = &iev->ibuf;
2610dcde55eSjca 	int			 n, stub_changed, shut = 0, isvalid, wasvalid;
262a1a4e97bSnorby 
26341e7b05eSclaudio 	if (event & EV_READ) {
264668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
265dd7efffeSclaudio 			fatal("imsgbuf_read error");
266a1a4e97bSnorby 		if (n == 0)	/* connection closed */
267a1a4e97bSnorby 			shut = 1;
26841e7b05eSclaudio 	}
26941e7b05eSclaudio 	if (event & EV_WRITE) {
270dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
271c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
2721203692fSkrw 				shut = 1;
273c1aa9554Sclaudio 			else
274dd7efffeSclaudio 				fatal("imsgbuf_write");
275c1aa9554Sclaudio 		}
276a1a4e97bSnorby 	}
277a1a4e97bSnorby 
278a1a4e97bSnorby 	for (;;) {
279a1a4e97bSnorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
280262992b2Sclaudio 			fatal("ospfe_dispatch_main: imsg_get error");
281a1a4e97bSnorby 		if (n == 0)
282a1a4e97bSnorby 			break;
283a1a4e97bSnorby 
284a1a4e97bSnorby 		switch (imsg.hdr.type) {
285a1a4e97bSnorby 		case IMSG_IFINFO:
286a1a4e97bSnorby 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
2876c9e7a5bSclaudio 			    sizeof(struct iface))
288a1a4e97bSnorby 				fatalx("IFINFO imsg with wrong len");
2896c9e7a5bSclaudio 			ifp = imsg.data;
290a1a4e97bSnorby 
291a66c91f2Sremi 			LIST_FOREACH(area, &oeconf->area_list, entry) {
292a66c91f2Sremi 				LIST_FOREACH(i, &area->iface_list, entry) {
293a66c91f2Sremi 					if (strcmp(i->dependon,
294a66c91f2Sremi 					    ifp->name) == 0) {
295a66c91f2Sremi 						log_warnx("interface %s"
296a66c91f2Sremi 						    " changed state, %s"
297a66c91f2Sremi 						    " depends on it",
298a66c91f2Sremi 						    ifp->name, i->name);
299a66c91f2Sremi 						i->depend_ok =
300a66c91f2Sremi 						    ifstate_is_up(ifp);
301a66c91f2Sremi 						if (ifstate_is_up(i))
302d18517d2Sdenis 							orig_rtr_lsa(i->area);
303a66c91f2Sremi 					}
304a66c91f2Sremi 				}
305a66c91f2Sremi 			}
306a66c91f2Sremi 
307a66c91f2Sremi 			if (!(ifp->cflags & F_IFACE_CONFIGURED))
308a66c91f2Sremi 				break;
3096c9e7a5bSclaudio 			iface = if_find(ifp->ifindex);
3106c9e7a5bSclaudio 			if (iface == NULL)
3116c9e7a5bSclaudio 				fatalx("interface lost in ospfe");
31242176c47Sclaudio 
3130dcde55eSjca 			wasvalid = (iface->flags & IFF_UP) &&
3140dcde55eSjca 			    LINK_STATE_IS_UP(iface->linkstate);
3150dcde55eSjca 
31618ffdd94Sstsp 			if_update(iface, ifp->mtu, ifp->flags, ifp->if_type,
3175d393f89Sremi 			    ifp->linkstate, ifp->baudrate, ifp->rdomain);
318a1a4e97bSnorby 
3190dcde55eSjca 			isvalid = (iface->flags & IFF_UP) &&
3200dcde55eSjca 			    LINK_STATE_IS_UP(iface->linkstate);
3210dcde55eSjca 
3220dcde55eSjca 			if (wasvalid == isvalid)
3230dcde55eSjca 				break;
3240dcde55eSjca 
3250dcde55eSjca 			if (isvalid) {
3266c9e7a5bSclaudio 				if_fsm(iface, IF_EVT_UP);
3276c9e7a5bSclaudio 				log_warnx("interface %s up", iface->name);
328a1a4e97bSnorby 			} else {
3296c9e7a5bSclaudio 				if_fsm(iface, IF_EVT_DOWN);
3306c9e7a5bSclaudio 				log_warnx("interface %s down", iface->name);
331a1a4e97bSnorby 			}
3326c9e7a5bSclaudio 			break;
3338e1674f3Sbluhm 		case IMSG_IFADDRNEW:
3348e1674f3Sbluhm 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
3358e1674f3Sbluhm 			    sizeof(struct ifaddrchange))
3368e1674f3Sbluhm 				fatalx("IFADDRNEW imsg with wrong len");
3378e1674f3Sbluhm 			ifc = imsg.data;
3388e1674f3Sbluhm 
3398e1674f3Sbluhm 			iface = if_find(ifc->ifindex);
3408e1674f3Sbluhm 			if (iface == NULL)
3418e1674f3Sbluhm 				fatalx("IFADDRNEW interface lost in ospfe");
3428e1674f3Sbluhm 
3438e1674f3Sbluhm 			if ((ia = calloc(1, sizeof(struct iface_addr))) ==
3448e1674f3Sbluhm 			    NULL)
3458e1674f3Sbluhm 				fatal("ospfe_dispatch_main IFADDRNEW");
3468e1674f3Sbluhm 			ia->addr = ifc->addr;
3478e1674f3Sbluhm 			ia->dstbrd = ifc->dstbrd;
3488e1674f3Sbluhm 			ia->prefixlen = ifc->prefixlen;
3498e1674f3Sbluhm 
3508e1674f3Sbluhm 			TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry);
3518e1674f3Sbluhm 			orig_link_lsa(iface);
3528e1674f3Sbluhm 			break;
3538e1674f3Sbluhm 		case IMSG_IFADDRDEL:
3548e1674f3Sbluhm 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
3558e1674f3Sbluhm 			    sizeof(struct ifaddrchange))
3568e1674f3Sbluhm 				fatalx("IFADDRDEL imsg with wrong len");
3578e1674f3Sbluhm 			ifc = imsg.data;
3588e1674f3Sbluhm 
3598e1674f3Sbluhm 			iface = if_find(ifc->ifindex);
3608e1674f3Sbluhm 			if (iface == NULL)
3618e1674f3Sbluhm 				fatalx("IFADDRDEL interface lost in ospfe");
3628e1674f3Sbluhm 
3638e1674f3Sbluhm 			for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL;
3648e1674f3Sbluhm 			    ia = nia) {
3658e1674f3Sbluhm 				nia = TAILQ_NEXT(ia, entry);
3668e1674f3Sbluhm 
3678e1674f3Sbluhm 				if (IN6_ARE_ADDR_EQUAL(&ia->addr,
3688e1674f3Sbluhm 				    &ifc->addr)) {
3698e1674f3Sbluhm 					TAILQ_REMOVE(&iface->ifa_list, ia,
3708e1674f3Sbluhm 					    entry);
3718e1674f3Sbluhm 					free(ia);
3728e1674f3Sbluhm 					break;
3738e1674f3Sbluhm 				}
3748e1674f3Sbluhm 			}
3758e1674f3Sbluhm 			orig_link_lsa(iface);
3768e1674f3Sbluhm 			break;
377a1a4e97bSnorby 		case IMSG_RECONF_CONF:
37877138d9fSclaudio 			if ((noeconf = malloc(sizeof(struct ospfd_conf))) ==
379a1a4e97bSnorby 			    NULL)
380a1a4e97bSnorby 				fatal(NULL);
38177138d9fSclaudio 			memcpy(noeconf, imsg.data, sizeof(struct ospfd_conf));
382a1a4e97bSnorby 
38377138d9fSclaudio 			LIST_INIT(&noeconf->area_list);
38477138d9fSclaudio 			LIST_INIT(&noeconf->cand_list);
385a1a4e97bSnorby 			break;
386a1a4e97bSnorby 		case IMSG_RECONF_AREA:
387a1a4e97bSnorby 			if ((narea = area_new()) == NULL)
388a1a4e97bSnorby 				fatal(NULL);
389a1a4e97bSnorby 			memcpy(narea, imsg.data, sizeof(struct area));
390a1a4e97bSnorby 
391a1a4e97bSnorby 			LIST_INIT(&narea->iface_list);
392a1a4e97bSnorby 			LIST_INIT(&narea->nbr_list);
393a1a4e97bSnorby 			RB_INIT(&narea->lsa_tree);
394a1a4e97bSnorby 
39577138d9fSclaudio 			LIST_INSERT_HEAD(&noeconf->area_list, narea, entry);
396a1a4e97bSnorby 			break;
397a1a4e97bSnorby 		case IMSG_RECONF_END:
398a1a4e97bSnorby 			if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) !=
39977138d9fSclaudio 			    (noeconf->flags & OSPFD_FLAG_STUB_ROUTER))
400a1a4e97bSnorby 				stub_changed = 1;
401a1a4e97bSnorby 			else
402a1a4e97bSnorby 				stub_changed = 0;
40377138d9fSclaudio 			merge_config(oeconf, noeconf);
40477138d9fSclaudio 			noeconf = NULL;
405a1a4e97bSnorby 			if (stub_changed)
406a1a4e97bSnorby 				orig_rtr_lsa_all(NULL);
407a1a4e97bSnorby 			break;
408a1a4e97bSnorby 		case IMSG_CTL_KROUTE:
409a1a4e97bSnorby 		case IMSG_CTL_KROUTE_ADDR:
410a1a4e97bSnorby 		case IMSG_CTL_END:
411a1a4e97bSnorby 			control_imsg_relay(&imsg);
412a1a4e97bSnorby 			break;
413cb75d791Sremi 		case IMSG_CONTROLFD:
4145608ad94Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1)
415cb75d791Sremi 				fatalx("%s: expected to receive imsg control"
416cb75d791Sremi 				    "fd but didn't receive any", __func__);
417cb75d791Sremi 			/* Listen on control socket. */
418bf1e0606Sclaudio 			control_listen(fd);
419cb75d791Sremi 			if (pledge("stdio inet mcast", NULL) == -1)
420cb75d791Sremi 				fatal("pledge");
421cb75d791Sremi 			break;
422a1a4e97bSnorby 		default:
423a1a4e97bSnorby 			log_debug("ospfe_dispatch_main: error handling imsg %d",
424a1a4e97bSnorby 			    imsg.hdr.type);
425a1a4e97bSnorby 			break;
426a1a4e97bSnorby 		}
427a1a4e97bSnorby 		imsg_free(&imsg);
428a1a4e97bSnorby 	}
429a1a4e97bSnorby 	if (!shut)
430f78850efSeric 		imsg_event_add(iev);
431a1a4e97bSnorby 	else {
432a1a4e97bSnorby 		/* this pipe is dead, so remove the event handler */
433f78850efSeric 		event_del(&iev->ev);
434a1a4e97bSnorby 		event_loopexit(NULL);
435a1a4e97bSnorby 	}
436a1a4e97bSnorby }
437a1a4e97bSnorby 
438a1a4e97bSnorby void
439a1a4e97bSnorby ospfe_dispatch_rde(int fd, short event, void *bula)
440a1a4e97bSnorby {
441a1a4e97bSnorby 	struct lsa_hdr		 lsa_hdr;
4423608871eSbluhm 	struct lsa_link		 lsa_link;
443f78850efSeric 	struct imsgev		*iev = bula;
444f78850efSeric 	struct imsgbuf		*ibuf = &iev->ibuf;
445a1a4e97bSnorby 	struct nbr		*nbr;
446a1a4e97bSnorby 	struct lsa_hdr		*lhp;
447a1a4e97bSnorby 	struct lsa_ref		*ref;
448a1a4e97bSnorby 	struct area		*area;
449a1a4e97bSnorby 	struct iface		*iface;
450a1a4e97bSnorby 	struct lsa_entry	*le;
451a1a4e97bSnorby 	struct imsg		 imsg;
452a1a4e97bSnorby 	struct abr_rtr		 ar;
453a1a4e97bSnorby 	int			 n, noack = 0, shut = 0;
454a1a4e97bSnorby 	u_int16_t		 l, age;
455a1a4e97bSnorby 
45641e7b05eSclaudio 	if (event & EV_READ) {
457668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
458dd7efffeSclaudio 			fatal("imsgbuf_read error");
459a1a4e97bSnorby 		if (n == 0)	/* connection closed */
460a1a4e97bSnorby 			shut = 1;
46141e7b05eSclaudio 	}
46241e7b05eSclaudio 	if (event & EV_WRITE) {
463dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
464c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
4651203692fSkrw 				shut = 1;
466c1aa9554Sclaudio 			else
467dd7efffeSclaudio 				fatal("imsgbuf_write");
468c1aa9554Sclaudio 		}
469a1a4e97bSnorby 	}
470a1a4e97bSnorby 
471a1a4e97bSnorby 	for (;;) {
472a1a4e97bSnorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
473262992b2Sclaudio 			fatal("ospfe_dispatch_rde: imsg_get error");
474a1a4e97bSnorby 		if (n == 0)
475a1a4e97bSnorby 			break;
476a1a4e97bSnorby 
477a1a4e97bSnorby 		switch (imsg.hdr.type) {
478a1a4e97bSnorby 		case IMSG_DD:
479a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
480a1a4e97bSnorby 			if (nbr == NULL)
481a1a4e97bSnorby 				break;
482a1a4e97bSnorby 
483a1a4e97bSnorby 			/* put these on my ls_req_list for retrieval */
484a1a4e97bSnorby 			lhp = lsa_hdr_new();
485a1a4e97bSnorby 			memcpy(lhp, imsg.data, sizeof(*lhp));
486a1a4e97bSnorby 			ls_req_list_add(nbr, lhp);
487a1a4e97bSnorby 			break;
488a1a4e97bSnorby 		case IMSG_DD_END:
489a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
490a1a4e97bSnorby 			if (nbr == NULL)
491a1a4e97bSnorby 				break;
492a1a4e97bSnorby 
493a1a4e97bSnorby 			nbr->dd_pending--;
494a1a4e97bSnorby 			if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) {
495a1a4e97bSnorby 				if (ls_req_list_empty(nbr))
496a1a4e97bSnorby 					nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
497a1a4e97bSnorby 				else
498a1a4e97bSnorby 					start_ls_req_tx_timer(nbr);
499a1a4e97bSnorby 			}
500a1a4e97bSnorby 			break;
501a1a4e97bSnorby 		case IMSG_DB_SNAPSHOT:
502a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
503a1a4e97bSnorby 			if (nbr == NULL)
504a1a4e97bSnorby 				break;
50525bf10dbSmarkus 			if (nbr->state != NBR_STA_SNAP)	/* discard */
50625bf10dbSmarkus 				break;
507a1a4e97bSnorby 
508a1a4e97bSnorby 			/* add LSA header to the neighbor db_sum_list */
509a1a4e97bSnorby 			lhp = lsa_hdr_new();
510a1a4e97bSnorby 			memcpy(lhp, imsg.data, sizeof(*lhp));
511a1a4e97bSnorby 			db_sum_list_add(nbr, lhp);
512a1a4e97bSnorby 			break;
513a1a4e97bSnorby 		case IMSG_DB_END:
514a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
515a1a4e97bSnorby 			if (nbr == NULL)
516a1a4e97bSnorby 				break;
517a1a4e97bSnorby 
51825bf10dbSmarkus 			nbr->dd_snapshot = 0;
51925bf10dbSmarkus 			if (nbr->state != NBR_STA_SNAP)
52025bf10dbSmarkus 				break;
52125bf10dbSmarkus 
522a1a4e97bSnorby 			/* snapshot done, start tx of dd packets */
523a1a4e97bSnorby 			nbr_fsm(nbr, NBR_EVT_SNAP_DONE);
524a1a4e97bSnorby 			break;
525a1a4e97bSnorby 		case IMSG_LS_FLOOD:
526a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
527a1a4e97bSnorby 			if (nbr == NULL)
528a1a4e97bSnorby 				break;
529a1a4e97bSnorby 
530a1a4e97bSnorby 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
531a1a4e97bSnorby 			if (l < sizeof(lsa_hdr))
532a1a4e97bSnorby 				fatalx("ospfe_dispatch_rde: "
533a1a4e97bSnorby 				    "bad imsg size");
534a1a4e97bSnorby 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
535a1a4e97bSnorby 
536a1a4e97bSnorby 			ref = lsa_cache_add(imsg.data, l);
537a1a4e97bSnorby 
538d913b22eSclaudio 			if (lsa_hdr.type == htons(LSA_TYPE_EXTERNAL)) {
539a1a4e97bSnorby 				/*
540a1a4e97bSnorby 				 * flood on all areas but stub areas and
541a1a4e97bSnorby 				 * virtual links
542a1a4e97bSnorby 				 */
543a1a4e97bSnorby 				LIST_FOREACH(area, &oeconf->area_list, entry) {
544a1a4e97bSnorby 					if (area->stub)
545a1a4e97bSnorby 						continue;
546a1a4e97bSnorby 					LIST_FOREACH(iface, &area->iface_list,
547a1a4e97bSnorby 					    entry) {
548a1a4e97bSnorby 						noack += lsa_flood(iface, nbr,
549a1a4e97bSnorby 						    &lsa_hdr, imsg.data);
550a1a4e97bSnorby 					}
551a1a4e97bSnorby 				}
552d913b22eSclaudio 			} else if (lsa_hdr.type == htons(LSA_TYPE_LINK)) {
553d913b22eSclaudio 				/*
5543608871eSbluhm 				 * Save link-LSA options of neighbor.
5553608871eSbluhm 				 * This is needed to originate network-LSA.
5563608871eSbluhm 				 */
5573608871eSbluhm 				if (l - sizeof(lsa_hdr) < sizeof(lsa_link))
5583608871eSbluhm 					fatalx("ospfe_dispatch_rde: "
5593608871eSbluhm 					    "bad imsg link size");
5603608871eSbluhm 				memcpy(&lsa_link, (char *)imsg.data +
5613608871eSbluhm 				    sizeof(lsa_hdr), sizeof(lsa_link));
5623608871eSbluhm 				nbr->link_options = lsa_link.opts &
5633608871eSbluhm 				    htonl(LSA_24_MASK);
5643608871eSbluhm 
5653608871eSbluhm 				/*
566d913b22eSclaudio 				 * flood on interface only
567d913b22eSclaudio 				 */
568d913b22eSclaudio 				noack += lsa_flood(nbr->iface, nbr,
569d913b22eSclaudio 				    &lsa_hdr, imsg.data);
570a1a4e97bSnorby 			} else {
571a1a4e97bSnorby 				/*
572a1a4e97bSnorby 				 * flood on all area interfaces on
573a1a4e97bSnorby 				 * area 0.0.0.0 include also virtual links.
574a1a4e97bSnorby 				 */
57577fbfa19Sdenis 				LIST_FOREACH(iface,
57677fbfa19Sdenis 				    &nbr->iface->area->iface_list, entry) {
577a1a4e97bSnorby 					noack += lsa_flood(iface, nbr,
578a1a4e97bSnorby 					    &lsa_hdr, imsg.data);
579a1a4e97bSnorby 				}
580a1a4e97bSnorby 				/* XXX virtual links */
581a1a4e97bSnorby 			}
582a1a4e97bSnorby 
583a1a4e97bSnorby 			/* remove from ls_req_list */
584a1a4e97bSnorby 			le = ls_req_list_get(nbr, &lsa_hdr);
585a1a4e97bSnorby 			if (!(nbr->state & NBR_STA_FULL) && le != NULL) {
586a1a4e97bSnorby 				ls_req_list_free(nbr, le);
587a1a4e97bSnorby 				/*
588a1a4e97bSnorby 				 * XXX no need to ack requested lsa
589a1a4e97bSnorby 				 * the problem is that the RFC is very
590a1a4e97bSnorby 				 * unclear about this.
591a1a4e97bSnorby 				 */
592a1a4e97bSnorby 				noack = 1;
593a1a4e97bSnorby 			}
594a1a4e97bSnorby 
595a1a4e97bSnorby 			if (!noack && nbr->iface != NULL &&
596a1a4e97bSnorby 			    nbr->iface->self != nbr) {
597a1a4e97bSnorby 				if (!(nbr->iface->state & IF_STA_BACKUP) ||
598a1a4e97bSnorby 				    nbr->iface->dr == nbr) {
599a1a4e97bSnorby 					/* delayed ack */
600a1a4e97bSnorby 					lhp = lsa_hdr_new();
601a1a4e97bSnorby 					memcpy(lhp, &lsa_hdr, sizeof(*lhp));
602a1a4e97bSnorby 					ls_ack_list_add(nbr->iface, lhp);
603a1a4e97bSnorby 				}
604a1a4e97bSnorby 			}
605a1a4e97bSnorby 
606a1a4e97bSnorby 			lsa_cache_put(ref, nbr);
607a1a4e97bSnorby 			break;
608a1a4e97bSnorby 		case IMSG_LS_UPD:
60925bf10dbSmarkus 		case IMSG_LS_SNAP:
610a1a4e97bSnorby 			/*
61125bf10dbSmarkus 			 * IMSG_LS_UPD is used in two cases:
612a1a4e97bSnorby 			 * 1. as response to ls requests
613a1a4e97bSnorby 			 * 2. as response to ls updates where the DB
614a1a4e97bSnorby 			 *    is newer then the sent LSA
61525bf10dbSmarkus 			 * IMSG_LS_SNAP is used in one case:
61625bf10dbSmarkus 			 *    in EXSTART when the LSA has age MaxAge
617a1a4e97bSnorby 			 */
618a1a4e97bSnorby 			l = imsg.hdr.len - IMSG_HEADER_SIZE;
619a1a4e97bSnorby 			if (l < sizeof(lsa_hdr))
620a1a4e97bSnorby 				fatalx("ospfe_dispatch_rde: "
621a1a4e97bSnorby 				    "bad imsg size");
622a1a4e97bSnorby 
623a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
624a1a4e97bSnorby 			if (nbr == NULL)
625a1a4e97bSnorby 				break;
626a1a4e97bSnorby 
627a1a4e97bSnorby 			if (nbr->iface->self == nbr)
628a1a4e97bSnorby 				break;
629a1a4e97bSnorby 
63025bf10dbSmarkus 			if (imsg.hdr.type == IMSG_LS_SNAP &&
63125bf10dbSmarkus 			    nbr->state != NBR_STA_SNAP)
63225bf10dbSmarkus 				break;
63325bf10dbSmarkus 
634a1a4e97bSnorby 			memcpy(&age, imsg.data, sizeof(age));
635a1a4e97bSnorby 			ref = lsa_cache_add(imsg.data, l);
636a1a4e97bSnorby 			if (ntohs(age) >= MAX_AGE)
637a1a4e97bSnorby 				/* add to retransmit list */
638a1a4e97bSnorby 				ls_retrans_list_add(nbr, imsg.data, 0, 0);
639a1a4e97bSnorby 			else
640a1a4e97bSnorby 				ls_retrans_list_add(nbr, imsg.data, 0, 1);
641a1a4e97bSnorby 
642a1a4e97bSnorby 			lsa_cache_put(ref, nbr);
643a1a4e97bSnorby 			break;
644a1a4e97bSnorby 		case IMSG_LS_ACK:
645a1a4e97bSnorby 			/*
646a1a4e97bSnorby 			 * IMSG_LS_ACK is used in two cases:
647a1a4e97bSnorby 			 * 1. LSA was a duplicate
648a1a4e97bSnorby 			 * 2. LS age is MaxAge and there is no current
649a1a4e97bSnorby 			 *    instance in the DB plus no neighbor in state
650a1a4e97bSnorby 			 *    Exchange or Loading
651a1a4e97bSnorby 			 */
652a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
653a1a4e97bSnorby 			if (nbr == NULL)
654a1a4e97bSnorby 				break;
655a1a4e97bSnorby 
656a1a4e97bSnorby 			if (nbr->iface->self == nbr)
657a1a4e97bSnorby 				break;
658a1a4e97bSnorby 
659a1a4e97bSnorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr))
660a1a4e97bSnorby 				fatalx("ospfe_dispatch_rde: bad imsg size");
661a1a4e97bSnorby 			memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr));
662a1a4e97bSnorby 
663a1a4e97bSnorby 			/* for case one check for implied acks */
664a1a4e97bSnorby 			if (nbr->iface->state & IF_STA_DROTHER)
665a1a4e97bSnorby 				if (ls_retrans_list_del(nbr->iface->self,
666a1a4e97bSnorby 				    &lsa_hdr) == 0)
667a1a4e97bSnorby 					break;
668a1a4e97bSnorby 			if (ls_retrans_list_del(nbr, &lsa_hdr) == 0)
669a1a4e97bSnorby 				break;
670a1a4e97bSnorby 
671a1a4e97bSnorby 			/* send a direct acknowledgement */
6720a137951Sdenis 			send_direct_ack(nbr->iface, nbr->addr, imsg.data,
673a1a4e97bSnorby 			    imsg.hdr.len - IMSG_HEADER_SIZE);
674a1a4e97bSnorby 
675a1a4e97bSnorby 			break;
676a1a4e97bSnorby 		case IMSG_LS_BADREQ:
677a1a4e97bSnorby 			nbr = nbr_find_peerid(imsg.hdr.peerid);
678a1a4e97bSnorby 			if (nbr == NULL)
679a1a4e97bSnorby 				break;
680a1a4e97bSnorby 
681a1a4e97bSnorby 			if (nbr->iface->self == nbr)
682a1a4e97bSnorby 				fatalx("ospfe_dispatch_rde: "
683a1a4e97bSnorby 				    "dummy neighbor got BADREQ");
684a1a4e97bSnorby 
685a1a4e97bSnorby 			nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ);
686a1a4e97bSnorby 			break;
687a1a4e97bSnorby 		case IMSG_ABR_UP:
688a1a4e97bSnorby 			memcpy(&ar, imsg.data, sizeof(ar));
689a1a4e97bSnorby 
690a1a4e97bSnorby 			if ((iface = find_vlink(&ar)) != NULL &&
691a1a4e97bSnorby 			    iface->state == IF_STA_DOWN)
692a1a4e97bSnorby 				if (if_fsm(iface, IF_EVT_UP)) {
693a1a4e97bSnorby 					log_debug("error starting interface %s",
694a1a4e97bSnorby 					    iface->name);
695a1a4e97bSnorby 				}
696a1a4e97bSnorby 			break;
697a1a4e97bSnorby 		case IMSG_ABR_DOWN:
698a1a4e97bSnorby 			memcpy(&ar, imsg.data, sizeof(ar));
699a1a4e97bSnorby 
700a1a4e97bSnorby 			if ((iface = find_vlink(&ar)) != NULL &&
701a1a4e97bSnorby 			    iface->state == IF_STA_POINTTOPOINT)
702a1a4e97bSnorby 				if (if_fsm(iface, IF_EVT_DOWN)) {
703a1a4e97bSnorby 					log_debug("error stopping interface %s",
704a1a4e97bSnorby 					    iface->name);
705a1a4e97bSnorby 				}
706a1a4e97bSnorby 			break;
707a1a4e97bSnorby 		case IMSG_CTL_AREA:
7084ae44e47Sclaudio 		case IMSG_CTL_IFACE:
709a1a4e97bSnorby 		case IMSG_CTL_END:
710a1a4e97bSnorby 		case IMSG_CTL_SHOW_DATABASE:
711a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_EXT:
712d913b22eSclaudio 		case IMSG_CTL_SHOW_DB_LINK:
713a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_NET:
714a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_RTR:
715d5dafa54Sstsp 		case IMSG_CTL_SHOW_DB_INTRA:
716a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_SELF:
717a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_SUM:
718a1a4e97bSnorby 		case IMSG_CTL_SHOW_DB_ASBR:
719a1a4e97bSnorby 		case IMSG_CTL_SHOW_RIB:
720a1a4e97bSnorby 		case IMSG_CTL_SHOW_SUM:
721a1a4e97bSnorby 		case IMSG_CTL_SHOW_SUM_AREA:
722a1a4e97bSnorby 			control_imsg_relay(&imsg);
723a1a4e97bSnorby 			break;
724a1a4e97bSnorby 		default:
725a1a4e97bSnorby 			log_debug("ospfe_dispatch_rde: error handling imsg %d",
726a1a4e97bSnorby 			    imsg.hdr.type);
727a1a4e97bSnorby 			break;
728a1a4e97bSnorby 		}
729a1a4e97bSnorby 		imsg_free(&imsg);
730a1a4e97bSnorby 	}
731a1a4e97bSnorby 	if (!shut)
732f78850efSeric 		imsg_event_add(iev);
733a1a4e97bSnorby 	else {
734a1a4e97bSnorby 		/* this pipe is dead, so remove the event handler */
735f78850efSeric 		event_del(&iev->ev);
736a1a4e97bSnorby 		event_loopexit(NULL);
737a1a4e97bSnorby 	}
738a1a4e97bSnorby }
739a1a4e97bSnorby 
740a1a4e97bSnorby struct iface *
741a1a4e97bSnorby find_vlink(struct abr_rtr *ar)
742a1a4e97bSnorby {
743a1a4e97bSnorby 	struct area	*area;
744a1a4e97bSnorby 	struct iface	*iface = NULL;
745a1a4e97bSnorby 
746a1a4e97bSnorby 	LIST_FOREACH(area, &oeconf->area_list, entry)
747a1a4e97bSnorby 		LIST_FOREACH(iface, &area->iface_list, entry)
748a1a4e97bSnorby 			if (iface->abr_id.s_addr == ar->abr_id.s_addr &&
749a1a4e97bSnorby 			    iface->type == IF_TYPE_VIRTUALLINK &&
75077fbfa19Sdenis 			    iface->area->id.s_addr == ar->area.s_addr) {
751a1a4e97bSnorby 				iface->dst = ar->dst_ip;
752a1a4e97bSnorby 				iface->addr = ar->addr;
753a1a4e97bSnorby 				iface->metric = ar->metric;
754a1a4e97bSnorby 
755a1a4e97bSnorby 				return (iface);
756a1a4e97bSnorby 			}
757a1a4e97bSnorby 
758a1a4e97bSnorby 	return (iface);
759a1a4e97bSnorby }
760a1a4e97bSnorby 
761a1a4e97bSnorby void
762a1a4e97bSnorby orig_rtr_lsa_all(struct area *area)
763a1a4e97bSnorby {
764a1a4e97bSnorby 	struct area	*a;
765a1a4e97bSnorby 
766a1a4e97bSnorby 	/*
767a1a4e97bSnorby 	 * update all router LSA in all areas except area itself,
768a1a4e97bSnorby 	 * as this update is already running.
769a1a4e97bSnorby 	 */
770a1a4e97bSnorby 	LIST_FOREACH(a, &oeconf->area_list, entry)
771a1a4e97bSnorby 		if (a != area)
772d18517d2Sdenis 			orig_rtr_lsa(a);
773a1a4e97bSnorby }
774a1a4e97bSnorby 
775a1a4e97bSnorby void
776d18517d2Sdenis orig_rtr_lsa(struct area *area)
777a1a4e97bSnorby {
778a1a4e97bSnorby 	struct lsa_hdr		 lsa_hdr;
779a1a4e97bSnorby 	struct lsa_rtr		 lsa_rtr;
780a1a4e97bSnorby 	struct lsa_rtr_link	 rtr_link;
781a1a4e97bSnorby 	struct iface		*iface;
782e39620e5Snicm 	struct ibuf		*buf;
783a1a4e97bSnorby 	struct nbr		*nbr, *self = NULL;
7848c389b43Sclaudio 	u_int32_t		 flags;
785a1a4e97bSnorby 	u_int16_t		 chksum;
786a1a4e97bSnorby 	u_int8_t		 border, virtual = 0;
787a1a4e97bSnorby 
788a1a4e97bSnorby 	log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
789a1a4e97bSnorby 
790e39620e5Snicm 	/* XXX IBUF_READ_SIZE */
791e39620e5Snicm 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
792a1a4e97bSnorby 		fatal("orig_rtr_lsa");
793a1a4e97bSnorby 
794a1a4e97bSnorby 	/* reserve space for LSA header and LSA Router header */
795297c3ba2Sclaudio 	if (ibuf_add_zero(buf, sizeof(lsa_hdr)) == -1)
796297c3ba2Sclaudio 		fatal("orig_rtr_lsa: ibuf_add_zero failed");
797a1a4e97bSnorby 
798297c3ba2Sclaudio 	if (ibuf_add_zero(buf, sizeof(lsa_rtr)) == -1)
799297c3ba2Sclaudio 		fatal("orig_rtr_lsa: ibuf_add_zero failed");
800a1a4e97bSnorby 
801a1a4e97bSnorby 	/* links */
802a1a4e97bSnorby 	LIST_FOREACH(iface, &area->iface_list, entry) {
803a1a4e97bSnorby 		if (self == NULL && iface->self != NULL)
804a1a4e97bSnorby 			self = iface->self;
805a1a4e97bSnorby 
806a1a4e97bSnorby 		bzero(&rtr_link, sizeof(rtr_link));
807a1a4e97bSnorby 
808a1a4e97bSnorby 		switch (iface->type) {
809a1a4e97bSnorby 		case IF_TYPE_POINTOPOINT:
810a1a4e97bSnorby 			LIST_FOREACH(nbr, &iface->nbr_list, entry)
811a1a4e97bSnorby 				if (nbr != iface->self &&
812a1a4e97bSnorby 				    nbr->state & NBR_STA_FULL)
813a1a4e97bSnorby 					break;
814273e69bcSstsp 			if (nbr && iface->state & IF_STA_POINTTOPOINT) {
815a1a4e97bSnorby 				log_debug("orig_rtr_lsa: point-to-point, "
816a1a4e97bSnorby 				    "interface %s", iface->name);
817a1a4e97bSnorby 				rtr_link.type = LINK_TYPE_POINTTOPOINT;
818a66c91f2Sremi 				if (iface->dependon[0] != '\0' &&
819a66c91f2Sremi 				    iface->depend_ok == 0)
820a66c91f2Sremi 					rtr_link.metric = MAX_METRIC;
821a66c91f2Sremi 				else
822a1a4e97bSnorby 					rtr_link.metric = htons(iface->metric);
823273e69bcSstsp 				rtr_link.iface_id = htonl(iface->ifindex);
824273e69bcSstsp 				rtr_link.nbr_iface_id = htonl(nbr->iface_id);
825273e69bcSstsp 				rtr_link.nbr_rtr_id = nbr->id.s_addr;
826e39620e5Snicm 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
8272c6b772cSclaudio 					fatalx("orig_rtr_lsa: ibuf_add failed");
828a1a4e97bSnorby 			}
829a1a4e97bSnorby 			continue;
830a1a4e97bSnorby 		case IF_TYPE_BROADCAST:
831a1a4e97bSnorby 		case IF_TYPE_NBMA:
832a1a4e97bSnorby 			if ((iface->state & IF_STA_MULTI)) {
833a1a4e97bSnorby 				if (iface->dr == iface->self) {
834a1a4e97bSnorby 					LIST_FOREACH(nbr, &iface->nbr_list,
835a1a4e97bSnorby 					    entry)
836a1a4e97bSnorby 						if (nbr != iface->self &&
837a1a4e97bSnorby 						    nbr->state & NBR_STA_FULL)
838a1a4e97bSnorby 							break;
839a1a4e97bSnorby 				} else
840a1a4e97bSnorby 					nbr = iface->dr;
841a1a4e97bSnorby 
842a1a4e97bSnorby 				if (nbr && nbr->state & NBR_STA_FULL) {
843a1a4e97bSnorby 					log_debug("orig_rtr_lsa: transit net, "
844a1a4e97bSnorby 					    "interface %s", iface->name);
845a1a4e97bSnorby 
846a1a4e97bSnorby 					rtr_link.type = LINK_TYPE_TRANSIT_NET;
847a66c91f2Sremi 					if (iface->dependon[0] != '\0' &&
848a66c91f2Sremi 					    iface->depend_ok == 0)
849a66c91f2Sremi 						rtr_link.metric = MAX_METRIC;
850a66c91f2Sremi 					else
851a66c91f2Sremi 						rtr_link.metric =
852a66c91f2Sremi 						    htons(iface->metric);
8538c389b43Sclaudio 					rtr_link.iface_id = htonl(iface->ifindex);
8548c389b43Sclaudio 					rtr_link.nbr_iface_id = htonl(iface->dr->iface_id);
8558c389b43Sclaudio 					rtr_link.nbr_rtr_id = iface->dr->id.s_addr;
856e39620e5Snicm 					if (ibuf_add(buf, &rtr_link,
8578c389b43Sclaudio 					    sizeof(rtr_link)))
8588c389b43Sclaudio 						fatalx("orig_rtr_lsa: "
8592c6b772cSclaudio 						    "ibuf_add failed");
860a1a4e97bSnorby 					break;
861a1a4e97bSnorby 				}
862a1a4e97bSnorby 			}
863a1a4e97bSnorby 			break;
8648c389b43Sclaudio #if 0 /* TODO virtualllink/pointtomulti */
865a1a4e97bSnorby 		case IF_TYPE_VIRTUALLINK:
866a1a4e97bSnorby 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
867a1a4e97bSnorby 				if (nbr != iface->self &&
868a1a4e97bSnorby 				    nbr->state & NBR_STA_FULL)
869a1a4e97bSnorby 					break;
870a1a4e97bSnorby 			}
871a1a4e97bSnorby 			if (nbr) {
872a1a4e97bSnorby 				rtr_link.id = nbr->id.s_addr;
873a1a4e97bSnorby //XXX				rtr_link.data = iface->addr.s_addr;
874a1a4e97bSnorby 				rtr_link.type = LINK_TYPE_VIRTUAL;
875a1a4e97bSnorby 				/* RFC 3137: stub router support */
876a1a4e97bSnorby 				if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER ||
877a1a4e97bSnorby 				    oe_nofib)
878a1a4e97bSnorby 					rtr_link.metric = 0xffff;
879a1a4e97bSnorby 				else
880a1a4e97bSnorby 					rtr_link.metric = htons(iface->metric);
881a1a4e97bSnorby 				virtual = 1;
882e39620e5Snicm 				if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
8832c6b772cSclaudio 					fatalx("orig_rtr_lsa: ibuf_add failed");
884a1a4e97bSnorby 
885a1a4e97bSnorby 				log_debug("orig_rtr_lsa: virtual link, "
886a1a4e97bSnorby 				    "interface %s", iface->name);
887a1a4e97bSnorby 			}
888a1a4e97bSnorby 			continue;
889a1a4e97bSnorby 		case IF_TYPE_POINTOMULTIPOINT:
890a1a4e97bSnorby 			log_debug("orig_rtr_lsa: stub net, "
891a1a4e97bSnorby 			    "interface %s", iface->name);
892a1a4e97bSnorby //XXX			rtr_link.id = iface->addr.s_addr;
893a1a4e97bSnorby 			rtr_link.data = 0xffffffff;
894a1a4e97bSnorby 			rtr_link.type = LINK_TYPE_STUB_NET;
895a1a4e97bSnorby 			rtr_link.metric = htons(iface->metric);
896e39620e5Snicm 			if (ibuf_add(buf, &rtr_link, sizeof(rtr_link)))
8972c6b772cSclaudio 				fatalx("orig_rtr_lsa: ibuf_add failed");
898a1a4e97bSnorby 
899a1a4e97bSnorby 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
900a1a4e97bSnorby 				if (nbr != iface->self &&
901a1a4e97bSnorby 				    nbr->state & NBR_STA_FULL) {
902a1a4e97bSnorby 					bzero(&rtr_link, sizeof(rtr_link));
903a1a4e97bSnorby 					log_debug("orig_rtr_lsa: "
904a1a4e97bSnorby 					    "point-to-multipoint, interface %s",
905a1a4e97bSnorby 					    iface->name);
906a1a4e97bSnorby //XXX					rtr_link.id = nbr->addr.s_addr;
907a1a4e97bSnorby //XXX					rtr_link.data = iface->addr.s_addr;
908a1a4e97bSnorby 					rtr_link.type = LINK_TYPE_POINTTOPOINT;
909a1a4e97bSnorby 					/* RFC 3137: stub router support */
910a1a4e97bSnorby 					if (oe_nofib || oeconf->flags &
911a1a4e97bSnorby 					    OSPFD_FLAG_STUB_ROUTER)
912a66c91f2Sremi 						rtr_link.metric = MAX_METRIC;
913a66c91f2Sremi 					else if (iface->dependon[0] != '\0' &&
914a66c91f2Sremi 						 iface->dependon_ok == 0)
915a66c91f2Sremi 						rtr_link.metric = MAX_METRIC;
916a1a4e97bSnorby 					else
917a1a4e97bSnorby 						rtr_link.metric =
918a1a4e97bSnorby 						    htons(iface->metric);
919e39620e5Snicm 					if (ibuf_add(buf, &rtr_link,
920a1a4e97bSnorby 					    sizeof(rtr_link)))
921a1a4e97bSnorby 						fatalx("orig_rtr_lsa: "
9222c6b772cSclaudio 						    "ibuf_add failed");
923a1a4e97bSnorby 				}
924a1a4e97bSnorby 			}
925a1a4e97bSnorby 			continue;
9268c389b43Sclaudio #endif /* TODO virtualllink/pointtomulti */
927a1a4e97bSnorby 		default:
928a1a4e97bSnorby 			fatalx("orig_rtr_lsa: unknown interface type");
929a1a4e97bSnorby 		}
930a1a4e97bSnorby 	}
931a1a4e97bSnorby 
932a1a4e97bSnorby 	/* LSA router header */
9338c389b43Sclaudio 	lsa_rtr.opts = 0;
9348c389b43Sclaudio 	flags = 0;
9358c389b43Sclaudio 
936a1a4e97bSnorby 	/*
937a1a4e97bSnorby 	 * Set the E bit as soon as an as-ext lsa may be redistributed, only
938a1a4e97bSnorby 	 * setting it in case we redistribute something is not worth the fuss.
939a1a4e97bSnorby 	 */
940c2625c19Sclaudio 	if (oeconf->redistribute && !area->stub)
9418c389b43Sclaudio 		flags |= OSPF_RTR_E;
942a1a4e97bSnorby 
943a1a4e97bSnorby 	border = (area_border_router(oeconf) != 0);
944a1a4e97bSnorby 	if (border != oeconf->border) {
945a1a4e97bSnorby 		oeconf->border = border;
946a1a4e97bSnorby 		orig_rtr_lsa_all(area);
947a1a4e97bSnorby 	}
948a1a4e97bSnorby 
949a1a4e97bSnorby 	if (oeconf->border)
9508c389b43Sclaudio 		flags |= OSPF_RTR_B;
951a1a4e97bSnorby 	/* TODO set V flag if a active virtual link ends here and the
9525934d87dSsthen 	 * area is the transit area for this link. */
953a1a4e97bSnorby 	if (virtual)
9548c389b43Sclaudio 		flags |= OSPF_RTR_V;
955a1a4e97bSnorby 
9568c389b43Sclaudio 	LSA_24_SETLO(lsa_rtr.opts, area_ospf_options(area));
9578c389b43Sclaudio 	LSA_24_SETHI(lsa_rtr.opts, flags);
9582773be1bSclaudio 	lsa_rtr.opts = htonl(lsa_rtr.opts);
959297c3ba2Sclaudio 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_rtr, sizeof(lsa_rtr)) == -1)
960297c3ba2Sclaudio 		fatal("orig_rtr_lsa: ibuf_set failed");
961a1a4e97bSnorby 
962a1a4e97bSnorby 	/* LSA header */
963a1a4e97bSnorby 	lsa_hdr.age = htons(DEFAULT_AGE);
9648c389b43Sclaudio 	lsa_hdr.type = htons(LSA_TYPE_ROUTER);
9658c389b43Sclaudio 	/* XXX needs to be fixed if multiple router-lsa need to be announced */
9668c389b43Sclaudio 	lsa_hdr.ls_id = 0;
967a1a4e97bSnorby 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
968a1a4e97bSnorby 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
969bf2cf305Sclaudio 	lsa_hdr.len = htons(ibuf_size(buf));
970a1a4e97bSnorby 	lsa_hdr.ls_chksum = 0;		/* updated later */
971297c3ba2Sclaudio 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
972297c3ba2Sclaudio 		fatal("orig_rtr_lsa: ibuf_set failed");
973a1a4e97bSnorby 
974bf2cf305Sclaudio 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
975297c3ba2Sclaudio 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
976297c3ba2Sclaudio 		fatal("orig_rtr_lsa: ibuf_set_n16 failed");
977a1a4e97bSnorby 
978a1a4e97bSnorby 	if (self)
979f78850efSeric 		imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0,
980bf2cf305Sclaudio 		    -1, ibuf_data(buf), ibuf_size(buf));
981a1a4e97bSnorby 	else
982a1a4e97bSnorby 		log_warnx("orig_rtr_lsa: empty area %s",
983a1a4e97bSnorby 		    inet_ntoa(area->id));
984a1a4e97bSnorby 
985e39620e5Snicm 	ibuf_free(buf);
986a1a4e97bSnorby }
987a1a4e97bSnorby 
988a1a4e97bSnorby void
989a1a4e97bSnorby orig_net_lsa(struct iface *iface)
990a1a4e97bSnorby {
991a1a4e97bSnorby 	struct lsa_hdr		 lsa_hdr;
992a1a4e97bSnorby 	struct nbr		*nbr;
993e39620e5Snicm 	struct ibuf		*buf;
9946663ca32Sstsp 	struct lsa_net		 lsa_net;
995a1a4e97bSnorby 	int			 num_rtr = 0;
996a1a4e97bSnorby 	u_int16_t		 chksum;
997a1a4e97bSnorby 
998e39620e5Snicm 	/* XXX IBUF_READ_SIZE */
999e39620e5Snicm 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
1000a1a4e97bSnorby 		fatal("orig_net_lsa");
1001a1a4e97bSnorby 
1002bf7812beSclaudio 	/* reserve space for LSA header and options field */
1003297c3ba2Sclaudio 	if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_net)) == -1)
1004297c3ba2Sclaudio 		fatal("orig_net_lsa: ibuf_add_zero failed");
1005a1a4e97bSnorby 
10066663ca32Sstsp 	lsa_net.opts = 0;
1007a1a4e97bSnorby 	/* fully adjacent neighbors + self */
1008a1a4e97bSnorby 	LIST_FOREACH(nbr, &iface->nbr_list, entry)
1009a1a4e97bSnorby 		if (nbr->state & NBR_STA_FULL) {
1010e39620e5Snicm 			if (ibuf_add(buf, &nbr->id, sizeof(nbr->id)))
1011e39620e5Snicm 				fatal("orig_net_lsa: ibuf_add failed");
10123608871eSbluhm 			lsa_net.opts |= nbr->link_options;
1013a1a4e97bSnorby 			num_rtr++;
1014a1a4e97bSnorby 		}
1015a1a4e97bSnorby 
1016a1a4e97bSnorby 	if (num_rtr == 1) {
10172c6b772cSclaudio 		/* non transit net therefore no need to generate a net lsa */
1018e39620e5Snicm 		ibuf_free(buf);
1019a1a4e97bSnorby 		return;
1020a1a4e97bSnorby 	}
1021a1a4e97bSnorby 
1022a1a4e97bSnorby 	/* LSA header */
1023a1a4e97bSnorby 	if (iface->state & IF_STA_DR)
1024a1a4e97bSnorby 		lsa_hdr.age = htons(DEFAULT_AGE);
1025a1a4e97bSnorby 	else
1026a1a4e97bSnorby 		lsa_hdr.age = htons(MAX_AGE);
1027a1a4e97bSnorby 
102867b3ede7Sclaudio 	lsa_hdr.type = htons(LSA_TYPE_NETWORK);
102967b3ede7Sclaudio 	/* for network LSAs, the link state ID equals the interface ID */
103067b3ede7Sclaudio 	lsa_hdr.ls_id = htonl(iface->ifindex);
1031a1a4e97bSnorby 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1032a1a4e97bSnorby 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1033bf2cf305Sclaudio 	lsa_hdr.len = htons(ibuf_size(buf));
1034a1a4e97bSnorby 	lsa_hdr.ls_chksum = 0;		/* updated later */
1035297c3ba2Sclaudio 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
1036297c3ba2Sclaudio 		fatal("orig_net_lsa: ibuf_set failed");
1037a1a4e97bSnorby 
10386663ca32Sstsp 	lsa_net.opts &= lsa_net.opts & htonl(LSA_24_MASK);
1039297c3ba2Sclaudio 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_net, sizeof(lsa_net)) == -1)
1040297c3ba2Sclaudio 		fatal("orig_net_lsa: ibuf_set failed");
1041bf7812beSclaudio 
1042bf2cf305Sclaudio 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
1043297c3ba2Sclaudio 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
1044297c3ba2Sclaudio 		fatal("orig_net_lsa: ibuf_set_n16 failed");
1045a1a4e97bSnorby 
1046f78850efSeric 	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1047bf2cf305Sclaudio 	    -1, ibuf_data(buf), ibuf_size(buf));
1048a1a4e97bSnorby 
1049e39620e5Snicm 	ibuf_free(buf);
1050a1a4e97bSnorby }
1051a1a4e97bSnorby 
1052d913b22eSclaudio void
1053d913b22eSclaudio orig_link_lsa(struct iface *iface)
1054d913b22eSclaudio {
1055d913b22eSclaudio 	struct lsa_hdr		 lsa_hdr;
1056d913b22eSclaudio 	struct lsa_link		 lsa_link;
1057d913b22eSclaudio 	struct lsa_prefix	 lsa_prefix;
1058e39620e5Snicm 	struct ibuf		*buf;
1059d913b22eSclaudio 	struct iface_addr	*ia;
1060d913b22eSclaudio 	struct in6_addr		 prefix;
1061d913b22eSclaudio 	unsigned int		 num_prefix = 0;
1062d913b22eSclaudio 	u_int16_t		 chksum;
1063d913b22eSclaudio 	u_int32_t		 options;
1064d913b22eSclaudio 
1065d913b22eSclaudio 	log_debug("orig_link_lsa: interface %s", iface->name);
1066d913b22eSclaudio 
1067412b2c53Sstsp 	switch (iface->type) {
1068412b2c53Sstsp 	case IF_TYPE_VIRTUALLINK:	/* forbidden by rfc5340 */
1069d913b22eSclaudio 		return;
1070412b2c53Sstsp 	case IF_TYPE_BROADCAST:
1071412b2c53Sstsp 	case IF_TYPE_NBMA:
1072d913b22eSclaudio 		if ((iface->state & IF_STA_MULTI) == 0)
1073d913b22eSclaudio 			return;
1074412b2c53Sstsp 		break;
1075412b2c53Sstsp 	case IF_TYPE_POINTOPOINT:
1076412b2c53Sstsp 	case IF_TYPE_POINTOMULTIPOINT:
1077412b2c53Sstsp 		if ((iface->state & IF_STA_POINTTOPOINT) == 0)
1078412b2c53Sstsp 			return;
1079412b2c53Sstsp 		break;
1080412b2c53Sstsp 	default:
1081412b2c53Sstsp 		fatalx("orig_link_lsa: unknown interface type");
1082412b2c53Sstsp 	}
1083d913b22eSclaudio 
1084e39620e5Snicm 	/* XXX IBUF_READ_SIZE */
1085e39620e5Snicm 	if ((buf = ibuf_dynamic(sizeof(lsa_hdr) + sizeof(lsa_link),
1086e39620e5Snicm 	    IBUF_READ_SIZE)) == NULL)
1087d913b22eSclaudio 		fatal("orig_link_lsa");
1088d913b22eSclaudio 
1089d913b22eSclaudio 	/* reserve space for LSA header and LSA link header */
1090297c3ba2Sclaudio 	if (ibuf_add_zero(buf, sizeof(lsa_hdr) + sizeof(lsa_link)) == -1)
1091297c3ba2Sclaudio 		fatal("orig_link_lsa: ibuf_add_zero failed");
1092d913b22eSclaudio 
1093d913b22eSclaudio 	/* link-local address, and all prefixes configured on interface */
1094d913b22eSclaudio 	TAILQ_FOREACH(ia, &iface->ifa_list, entry) {
1095d913b22eSclaudio 		if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) {
1096d913b22eSclaudio 			log_debug("orig_link_lsa: link local address %s",
1097d913b22eSclaudio 			    log_in6addr(&ia->addr));
1098d913b22eSclaudio 			lsa_link.lladdr = ia->addr;
1099d913b22eSclaudio 			continue;
1100d913b22eSclaudio 		}
1101d913b22eSclaudio 
1102d913b22eSclaudio 		lsa_prefix.prefixlen = ia->prefixlen;
1103d913b22eSclaudio 		lsa_prefix.options = 0;
1104d913b22eSclaudio 		lsa_prefix.metric = 0;
1105d913b22eSclaudio 		inet6applymask(&prefix, &ia->addr, ia->prefixlen);
1106d913b22eSclaudio 		log_debug("orig_link_lsa: prefix %s", log_in6addr(&prefix));
1107e39620e5Snicm 		if (ibuf_add(buf, &lsa_prefix, sizeof(lsa_prefix)))
1108e39620e5Snicm 			fatal("orig_link_lsa: ibuf_add failed");
1109e39620e5Snicm 		if (ibuf_add(buf, &prefix.s6_addr[0],
1110f3f203f1Sstsp 		    LSA_PREFIXSIZE(ia->prefixlen)))
1111e39620e5Snicm 			fatal("orig_link_lsa: ibuf_add failed");
1112d913b22eSclaudio 		num_prefix++;
1113d913b22eSclaudio 	}
1114d913b22eSclaudio 
1115d913b22eSclaudio 	/* LSA link header (lladdr has already been filled in above) */
1116d913b22eSclaudio 	LSA_24_SETHI(lsa_link.opts, iface->priority);
111777fbfa19Sdenis 	options = area_ospf_options(iface->area);
1118d913b22eSclaudio 	LSA_24_SETLO(lsa_link.opts, options);
1119d913b22eSclaudio 	lsa_link.opts = htonl(lsa_link.opts);
1120d913b22eSclaudio 	lsa_link.numprefix = htonl(num_prefix);
1121297c3ba2Sclaudio 	if (ibuf_set(buf, sizeof(lsa_hdr), &lsa_link, sizeof(lsa_link)) == -1)
1122297c3ba2Sclaudio 		fatal("orig_link_lsa: ibuf_set failed");
1123d913b22eSclaudio 
1124d913b22eSclaudio 	/* LSA header */
1125d913b22eSclaudio 	lsa_hdr.age = htons(DEFAULT_AGE);
1126d913b22eSclaudio 	lsa_hdr.type = htons(LSA_TYPE_LINK);
1127d913b22eSclaudio 	/* for link LSAs, the link state ID equals the interface ID */
1128d913b22eSclaudio 	lsa_hdr.ls_id = htonl(iface->ifindex);
1129d913b22eSclaudio 	lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr;
1130d913b22eSclaudio 	lsa_hdr.seq_num = htonl(INIT_SEQ_NUM);
1131bf2cf305Sclaudio 	lsa_hdr.len = htons(ibuf_size(buf));
1132d913b22eSclaudio 	lsa_hdr.ls_chksum = 0;		/* updated later */
1133297c3ba2Sclaudio 	if (ibuf_set(buf, 0, &lsa_hdr, sizeof(lsa_hdr)) == -1)
1134297c3ba2Sclaudio 		fatal("orig_link_lsa: ibuf_set failed");
1135d913b22eSclaudio 
1136bf2cf305Sclaudio 	chksum = iso_cksum(ibuf_data(buf), ibuf_size(buf), LS_CKSUM_OFFSET);
1137297c3ba2Sclaudio 	if (ibuf_set_n16(buf, LS_CKSUM_OFFSET, chksum) == -1)
1138297c3ba2Sclaudio 		fatal("orig_link_lsa: ibuf_set_n16 failed");
1139d913b22eSclaudio 
1140f78850efSeric 	imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0,
1141bf2cf305Sclaudio 	    -1, ibuf_data(buf), ibuf_size(buf));
1142d913b22eSclaudio 
1143e39620e5Snicm 	ibuf_free(buf);
1144d913b22eSclaudio }
1145d913b22eSclaudio 
1146a1a4e97bSnorby u_int32_t
1147a1a4e97bSnorby ospfe_router_id(void)
1148a1a4e97bSnorby {
1149a1a4e97bSnorby 	return (oeconf->rtr_id.s_addr);
1150a1a4e97bSnorby }
1151a1a4e97bSnorby 
1152a1a4e97bSnorby void
1153d7a89a67Sclaudio ospfe_fib_update(int type)
1154a1a4e97bSnorby {
1155a1a4e97bSnorby 	int	old = oe_nofib;
1156a1a4e97bSnorby 
1157a1a4e97bSnorby 	if (type == IMSG_CTL_FIB_COUPLE)
1158a1a4e97bSnorby 		oe_nofib = 0;
1159a1a4e97bSnorby 	if (type == IMSG_CTL_FIB_DECOUPLE)
1160a1a4e97bSnorby 		oe_nofib = 1;
1161a1a4e97bSnorby 	if (old != oe_nofib)
1162a1a4e97bSnorby 		orig_rtr_lsa_all(NULL);
1163a1a4e97bSnorby }
1164a1a4e97bSnorby 
1165a1a4e97bSnorby void
1166a1a4e97bSnorby ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx)
1167a1a4e97bSnorby {
1168a1a4e97bSnorby 	struct area		*area;
1169a1a4e97bSnorby 	struct iface		*iface;
1170a1a4e97bSnorby 	struct ctl_iface	*ictl;
1171a1a4e97bSnorby 
1172a1a4e97bSnorby 	LIST_FOREACH(area, &oeconf->area_list, entry)
1173a1a4e97bSnorby 		LIST_FOREACH(iface, &area->iface_list, entry)
1174a1a4e97bSnorby 			if (idx == 0 || idx == iface->ifindex) {
1175a1a4e97bSnorby 				ictl = if_to_ctl(iface);
1176f78850efSeric 				imsg_compose_event(&c->iev,
11772c6b772cSclaudio 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
11782c6b772cSclaudio 				    ictl, sizeof(struct ctl_iface));
1179a1a4e97bSnorby 			}
1180a1a4e97bSnorby }
1181a1a4e97bSnorby 
1182a1a4e97bSnorby void
1183a1a4e97bSnorby ospfe_nbr_ctl(struct ctl_conn *c)
1184a1a4e97bSnorby {
1185a1a4e97bSnorby 	struct area	*area;
1186a1a4e97bSnorby 	struct iface	*iface;
1187a1a4e97bSnorby 	struct nbr	*nbr;
1188a1a4e97bSnorby 	struct ctl_nbr	*nctl;
1189a1a4e97bSnorby 
1190a1a4e97bSnorby 	LIST_FOREACH(area, &oeconf->area_list, entry)
1191a1a4e97bSnorby 		LIST_FOREACH(iface, &area->iface_list, entry)
1192a1a4e97bSnorby 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
1193a1a4e97bSnorby 				if (iface->self != nbr) {
1194a1a4e97bSnorby 					nctl = nbr_to_ctl(nbr);
1195f78850efSeric 					imsg_compose_event(&c->iev,
1196f78850efSeric 					    IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
1197a1a4e97bSnorby 					    sizeof(struct ctl_nbr));
1198a1a4e97bSnorby 				}
1199a1a4e97bSnorby 			}
1200a1a4e97bSnorby 
1201f78850efSeric 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
1202a1a4e97bSnorby }
1203a1a4e97bSnorby 
1204a1a4e97bSnorby void
1205a1a4e97bSnorby ospfe_demote_area(struct area *area, int active)
1206a1a4e97bSnorby {
1207a1a4e97bSnorby 	struct demote_msg	dmsg;
1208a1a4e97bSnorby 
1209a1a4e97bSnorby 	if (ospfd_process != PROC_OSPF_ENGINE ||
1210a1a4e97bSnorby 	    area->demote_group[0] == '\0')
1211a1a4e97bSnorby 		return;
1212a1a4e97bSnorby 
1213a1a4e97bSnorby 	bzero(&dmsg, sizeof(dmsg));
1214a1a4e97bSnorby 	strlcpy(dmsg.demote_group, area->demote_group,
1215a1a4e97bSnorby 	    sizeof(dmsg.demote_group));
1216a1a4e97bSnorby 	dmsg.level = area->demote_level;
1217a1a4e97bSnorby 	if (active)
1218a1a4e97bSnorby 		dmsg.level = -dmsg.level;
1219a1a4e97bSnorby 
1220a1a4e97bSnorby 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1221a1a4e97bSnorby }
1222a1a4e97bSnorby 
1223a1a4e97bSnorby void
1224a1a4e97bSnorby ospfe_demote_iface(struct iface *iface, int active)
1225a1a4e97bSnorby {
1226a1a4e97bSnorby 	struct demote_msg	dmsg;
1227a1a4e97bSnorby 
1228a1a4e97bSnorby 	if (ospfd_process != PROC_OSPF_ENGINE ||
1229a1a4e97bSnorby 	    iface->demote_group[0] == '\0')
1230a1a4e97bSnorby 		return;
1231a1a4e97bSnorby 
1232a1a4e97bSnorby 	bzero(&dmsg, sizeof(dmsg));
1233a1a4e97bSnorby 	strlcpy(dmsg.demote_group, iface->demote_group,
1234a1a4e97bSnorby 	sizeof(dmsg.demote_group));
1235a1a4e97bSnorby 	if (active)
1236a1a4e97bSnorby 		dmsg.level = -1;
1237a1a4e97bSnorby 	else
1238a1a4e97bSnorby 		dmsg.level = 1;
1239a1a4e97bSnorby 
12402c6b772cSclaudio 	log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group,
12412c6b772cSclaudio 	    dmsg.level);
12422c6b772cSclaudio 
1243a1a4e97bSnorby 	ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg));
1244a1a4e97bSnorby }
1245