xref: /openbsd-src/usr.sbin/ospf6d/ospf6d.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: ospf6d.c,v 1.61 2024/11/21 13:38:14 claudio Exp $ */
2a1a4e97bSnorby 
3a1a4e97bSnorby /*
4a1a4e97bSnorby  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5a1a4e97bSnorby  * Copyright (c) 2004, 2007 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 <sys/time.h>
25a1a4e97bSnorby #include <sys/stat.h>
26a1a4e97bSnorby #include <sys/wait.h>
27a1a4e97bSnorby #include <sys/sysctl.h>
28189fd1ceSbenno #include <syslog.h>
29a1a4e97bSnorby 
30a1a4e97bSnorby #include <netinet/in.h>
31a1a4e97bSnorby #include <arpa/inet.h>
32a66c91f2Sremi #include <net/if_types.h>
33a1a4e97bSnorby 
34a1a4e97bSnorby #include <event.h>
35a1a4e97bSnorby #include <err.h>
36a1a4e97bSnorby #include <errno.h>
37a1a4e97bSnorby #include <pwd.h>
38a1a4e97bSnorby #include <stdio.h>
39a1a4e97bSnorby #include <stdlib.h>
40a1a4e97bSnorby #include <string.h>
41a1a4e97bSnorby #include <signal.h>
42a1a4e97bSnorby #include <unistd.h>
43a1a4e97bSnorby 
44a1a4e97bSnorby #include "ospf6d.h"
45a1a4e97bSnorby #include "ospf6.h"
46a1a4e97bSnorby #include "ospfe.h"
47a1a4e97bSnorby #include "control.h"
48a1a4e97bSnorby #include "log.h"
49a1a4e97bSnorby #include "rde.h"
50a1a4e97bSnorby 
51a1a4e97bSnorby void		main_sig_handler(int, short, void *);
52a1a4e97bSnorby __dead void	usage(void);
53ee103ef4Srenato __dead void	ospfd_shutdown(void);
54a1a4e97bSnorby 
55a1a4e97bSnorby void	main_dispatch_ospfe(int, short, void *);
56a1a4e97bSnorby void	main_dispatch_rde(int, short, void *);
57a1a4e97bSnorby 
58a1a4e97bSnorby int	ospf_reload(void);
59a1a4e97bSnorby int	ospf_sendboth(enum imsg_type, void *, u_int16_t);
60a1a4e97bSnorby int	merge_interfaces(struct area *, struct area *);
61a1a4e97bSnorby struct iface *iface_lookup(struct area *, struct iface *);
62a1a4e97bSnorby 
63a1a4e97bSnorby int	pipe_parent2ospfe[2];
64a1a4e97bSnorby int	pipe_parent2rde[2];
65a1a4e97bSnorby int	pipe_ospfe2rde[2];
66a1a4e97bSnorby 
6778c7f53fSclaudio enum ospfd_process	 ospfd_process;
68a1a4e97bSnorby struct ospfd_conf	*ospfd_conf = NULL;
69ccbb71f5Sclaudio static struct imsgev	*iev_ospfe;
70ccbb71f5Sclaudio static struct imsgev	*iev_rde;
71a1a4e97bSnorby char			*conffile;
72a1a4e97bSnorby 
73a1a4e97bSnorby pid_t			 ospfe_pid = 0;
74a1a4e97bSnorby pid_t			 rde_pid = 0;
75a1a4e97bSnorby 
76a1a4e97bSnorby void
77a1a4e97bSnorby main_sig_handler(int sig, short event, void *arg)
78a1a4e97bSnorby {
79ee103ef4Srenato 	/* signal handler rules don't apply, libevent decouples for us */
80a1a4e97bSnorby 	switch (sig) {
81a1a4e97bSnorby 	case SIGTERM:
82a1a4e97bSnorby 	case SIGINT:
83a1a4e97bSnorby 		ospfd_shutdown();
84ee103ef4Srenato 		/* NOTREACHED */
85a1a4e97bSnorby 	case SIGHUP:
86a1a4e97bSnorby 		if (ospf_reload() == -1)
87a1a4e97bSnorby 			log_warnx("configuration reload failed");
88a1a4e97bSnorby 		else
89a1a4e97bSnorby 			log_debug("configuration reloaded");
90a1a4e97bSnorby 		break;
91a1a4e97bSnorby 	default:
92a1a4e97bSnorby 		fatalx("unexpected signal");
93a1a4e97bSnorby 		/* NOTREACHED */
94a1a4e97bSnorby 	}
95a1a4e97bSnorby }
96a1a4e97bSnorby 
97a1a4e97bSnorby __dead void
98a1a4e97bSnorby usage(void)
99a1a4e97bSnorby {
100a1a4e97bSnorby 	extern char *__progname;
101a1a4e97bSnorby 
102c2ca8945Ssthen 	fprintf(stderr, "usage: %s [-dnv] [-D macro=value]"
103c2ca8945Ssthen 	    " [-f file] [-s socket]\n",
104e5b5b453Sclaudio 	    __progname);
105a1a4e97bSnorby 	exit(1);
106a1a4e97bSnorby }
107a1a4e97bSnorby 
108a1a4e97bSnorby int
109a1a4e97bSnorby main(int argc, char *argv[])
110a1a4e97bSnorby {
111ee103ef4Srenato 	struct event		 ev_sigint, ev_sigterm, ev_sighup;
112a1a4e97bSnorby 	int			 ch, opts = 0;
113a1a4e97bSnorby 	int			 debug = 0;
114a1a4e97bSnorby 	int			 ipforwarding;
115a1a4e97bSnorby 	int			 mib[4];
116a1a4e97bSnorby 	size_t			 len;
1175d393f89Sremi 	char			*sockname = NULL;
118cb75d791Sremi 	int			 control_fd;
119a1a4e97bSnorby 
120a1a4e97bSnorby 	conffile = CONF_FILE;
121a1a4e97bSnorby 	ospfd_process = PROC_MAIN;
122a1a4e97bSnorby 
123189fd1ceSbenno 	log_init(1, LOG_DAEMON);	/* log to stderr until daemonized */
124189fd1ceSbenno 	log_procinit(log_procnames[ospfd_process]);
1256fa930c9Spyr 
126c2ca8945Ssthen 	while ((ch = getopt(argc, argv, "cdD:f:s:nv")) != -1) {
127a1a4e97bSnorby 		switch (ch) {
128a1a4e97bSnorby 		case 'c':
129a1a4e97bSnorby 			opts |= OSPFD_OPT_FORCE_DEMOTE;
130a1a4e97bSnorby 			break;
131a1a4e97bSnorby 		case 'd':
132a1a4e97bSnorby 			debug = 1;
133a1a4e97bSnorby 			break;
134e5b5b453Sclaudio 		case 'D':
135e5b5b453Sclaudio 			if (cmdline_symset(optarg) < 0)
136e5b5b453Sclaudio 				log_warnx("could not parse macro definition %s",
137e5b5b453Sclaudio 				    optarg);
138e5b5b453Sclaudio 			break;
139a1a4e97bSnorby 		case 'f':
140a1a4e97bSnorby 			conffile = optarg;
141a1a4e97bSnorby 			break;
142a1a4e97bSnorby 		case 'n':
143a1a4e97bSnorby 			opts |= OSPFD_OPT_NOACTION;
144a1a4e97bSnorby 			break;
145c2ca8945Ssthen 		case 's':
146c2ca8945Ssthen 			sockname = optarg;
147c2ca8945Ssthen 			break;
148a1a4e97bSnorby 		case 'v':
149a1a4e97bSnorby 			if (opts & OSPFD_OPT_VERBOSE)
150a1a4e97bSnorby 				opts |= OSPFD_OPT_VERBOSE2;
151a1a4e97bSnorby 			opts |= OSPFD_OPT_VERBOSE;
152189fd1ceSbenno 			log_setverbose(1);
153a1a4e97bSnorby 			break;
154a1a4e97bSnorby 		default:
155a1a4e97bSnorby 			usage();
156a1a4e97bSnorby 			/* NOTREACHED */
157a1a4e97bSnorby 		}
158a1a4e97bSnorby 	}
159a1a4e97bSnorby 
160fde55bc4Spyr 	argc -= optind;
161fde55bc4Spyr 	argv += optind;
162fde55bc4Spyr 	if (argc > 0)
163fde55bc4Spyr 		usage();
164fde55bc4Spyr 
165a1a4e97bSnorby 	mib[0] = CTL_NET;
166a1a4e97bSnorby 	mib[1] = PF_INET6;
167a1a4e97bSnorby 	mib[2] = IPPROTO_IPV6;
168a1a4e97bSnorby 	mib[3] = IPCTL_FORWARDING;
169a1a4e97bSnorby 	len = sizeof(ipforwarding);
170a1a4e97bSnorby 	if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1)
171a1a4e97bSnorby 		err(1, "sysctl");
172a1a4e97bSnorby 
173a1a4e97bSnorby 	if (ipforwarding != 1) {
174a1a4e97bSnorby 		log_warnx("WARNING: IPv6 forwarding NOT enabled, "
175a1a4e97bSnorby 		    "running as stub router");
176a1a4e97bSnorby 		opts |= OSPFD_OPT_STUB_ROUTER;
177a1a4e97bSnorby 	}
178a1a4e97bSnorby 
1796c9e7a5bSclaudio 	/* prepare and fetch interfaces early */
1806c9e7a5bSclaudio 	if_init();
181a1a4e97bSnorby 
182a1a4e97bSnorby 	/* parse config file */
183a1a4e97bSnorby 	if ((ospfd_conf = parse_config(conffile, opts)) == NULL )
184a1a4e97bSnorby 		exit(1);
1855d393f89Sremi 
1865d393f89Sremi 	if (sockname == NULL) {
1875d393f89Sremi 		if (asprintf(&sockname, "%s.%d", OSPF6D_SOCKET,
1885d393f89Sremi 		    ospfd_conf->rdomain) == -1)
1895d393f89Sremi 			err(1, "asprintf");
1905d393f89Sremi 	}
1915d393f89Sremi 
192c2ca8945Ssthen 	ospfd_conf->csock = sockname;
193a1a4e97bSnorby 
194a1a4e97bSnorby 	if (ospfd_conf->opts & OSPFD_OPT_NOACTION) {
195a1a4e97bSnorby 		if (ospfd_conf->opts & OSPFD_OPT_VERBOSE)
196a1a4e97bSnorby 			print_config(ospfd_conf);
197a1a4e97bSnorby 		else
198a1a4e97bSnorby 			fprintf(stderr, "configuration OK\n");
199a1a4e97bSnorby 		exit(0);
200a1a4e97bSnorby 	}
201a1a4e97bSnorby 
202a1a4e97bSnorby 	/* check for root privileges  */
203a1a4e97bSnorby 	if (geteuid())
204a1a4e97bSnorby 		errx(1, "need root privileges");
205a1a4e97bSnorby 
206a1a4e97bSnorby 	/* check for ospfd user */
207a1a4e97bSnorby 	if (getpwnam(OSPF6D_USER) == NULL)
208a1a4e97bSnorby 		errx(1, "unknown user %s", OSPF6D_USER);
209a1a4e97bSnorby 
210189fd1ceSbenno 	log_init(debug, LOG_DAEMON);
211189fd1ceSbenno 	log_setverbose(ospfd_conf->opts & OSPFD_OPT_VERBOSE);
2126fa930c9Spyr 
213cb75d791Sremi 	if ((control_check(ospfd_conf->csock)) == -1)
2140347b698Sflorian 		fatalx("ospf6d already running");
215cb75d791Sremi 
216a1a4e97bSnorby 	if (!debug)
217a1a4e97bSnorby 		daemon(1, 0);
218a1a4e97bSnorby 
219a1a4e97bSnorby 	log_info("startup");
220a1a4e97bSnorby 
22135251ca5Sclaudio 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
22235251ca5Sclaudio 	    PF_UNSPEC, pipe_parent2ospfe) == -1)
223a1a4e97bSnorby 		fatal("socketpair");
22435251ca5Sclaudio 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
22535251ca5Sclaudio 	    PF_UNSPEC, pipe_parent2rde) == -1)
226a1a4e97bSnorby 		fatal("socketpair");
22735251ca5Sclaudio 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
22835251ca5Sclaudio 	    PF_UNSPEC, pipe_ospfe2rde) == -1)
229a1a4e97bSnorby 		fatal("socketpair");
230a1a4e97bSnorby 
231a1a4e97bSnorby 	/* start children */
232a1a4e97bSnorby 	rde_pid = rde(ospfd_conf, pipe_parent2rde, pipe_ospfe2rde,
233a1a4e97bSnorby 	    pipe_parent2ospfe);
234a1a4e97bSnorby 	ospfe_pid = ospfe(ospfd_conf, pipe_parent2ospfe, pipe_ospfe2rde,
235a1a4e97bSnorby 	    pipe_parent2rde);
236a1a4e97bSnorby 
237a1a4e97bSnorby 	event_init();
238a1a4e97bSnorby 
239a1a4e97bSnorby 	/* setup signal handler */
240a1a4e97bSnorby 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
241a1a4e97bSnorby 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
242a1a4e97bSnorby 	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
243a1a4e97bSnorby 	signal_add(&ev_sigint, NULL);
244a1a4e97bSnorby 	signal_add(&ev_sigterm, NULL);
245a1a4e97bSnorby 	signal_add(&ev_sighup, NULL);
246a1a4e97bSnorby 	signal(SIGPIPE, SIG_IGN);
247a1a4e97bSnorby 
248a1a4e97bSnorby 	/* setup pipes to children */
249a1a4e97bSnorby 	close(pipe_parent2ospfe[1]);
250a1a4e97bSnorby 	close(pipe_parent2rde[1]);
251a1a4e97bSnorby 	close(pipe_ospfe2rde[0]);
252a1a4e97bSnorby 	close(pipe_ospfe2rde[1]);
253a1a4e97bSnorby 
254f78850efSeric 	if ((iev_ospfe = malloc(sizeof(struct imsgev))) == NULL ||
255f78850efSeric 	    (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
256a1a4e97bSnorby 		fatal(NULL);
257*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_ospfe->ibuf, pipe_parent2ospfe[0]) == -1)
258*f1b790a5Sclaudio 		fatal(NULL);
259*f1b790a5Sclaudio 	imsgbuf_allow_fdpass(&iev_ospfe->ibuf);
260f78850efSeric 	iev_ospfe->handler = main_dispatch_ospfe;
261*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1)
262*f1b790a5Sclaudio 		fatal(NULL);
263f78850efSeric 	iev_rde->handler = main_dispatch_rde;
264a1a4e97bSnorby 
265a1a4e97bSnorby 	/* setup event handler */
266f78850efSeric 	iev_ospfe->events = EV_READ;
267f78850efSeric 	event_set(&iev_ospfe->ev, iev_ospfe->ibuf.fd, iev_ospfe->events,
268f78850efSeric 	    iev_ospfe->handler, iev_ospfe);
269f78850efSeric 	event_add(&iev_ospfe->ev, NULL);
270a1a4e97bSnorby 
271f78850efSeric 	iev_rde->events = EV_READ;
272f78850efSeric 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
273f78850efSeric 	    iev_rde->handler, iev_rde);
274f78850efSeric 	event_add(&iev_rde->ev, NULL);
275a1a4e97bSnorby 
276cb75d791Sremi 	if ((control_fd = control_init(ospfd_conf->csock)) == -1)
277cb75d791Sremi 		fatalx("control socket setup failed");
278cb75d791Sremi 	main_imsg_compose_ospfe_fd(IMSG_CONTROLFD, 0, control_fd);
279cb75d791Sremi 
280faef135eSremi 	/* no filesystem visibility */
281faef135eSremi 	if (unveil("/", "") == -1)
282025f8c0aSderaadt 		fatal("unveil /");
28327dccea9Sremi 	if (unveil(NULL, NULL) == -1)
28427dccea9Sremi 		fatal("unveil");
28527dccea9Sremi 
2865d393f89Sremi 	if (kr_init(!(ospfd_conf->flags & OSPFD_FLAG_NO_FIB_UPDATE),
2874cf51530Sdenis 	    ospfd_conf->rdomain, ospfd_conf->redist_label_or_prefix,
2884cf51530Sdenis 	    ospfd_conf->fib_priority) == -1)
289a1a4e97bSnorby 		fatalx("kr_init failed");
290a1a4e97bSnorby 
291a1a4e97bSnorby 	event_dispatch();
292a1a4e97bSnorby 
293a1a4e97bSnorby 	ospfd_shutdown();
294a1a4e97bSnorby 	/* NOTREACHED */
295a1a4e97bSnorby 	return (0);
296a1a4e97bSnorby }
297a1a4e97bSnorby 
298ee103ef4Srenato __dead void
299a1a4e97bSnorby ospfd_shutdown(void)
300a1a4e97bSnorby {
301a1a4e97bSnorby 	pid_t	pid;
302ee103ef4Srenato 	int	status;
303a1a4e97bSnorby 
304ee103ef4Srenato 	/* close pipes */
3059cbf9e90Sclaudio 	imsgbuf_clear(&iev_ospfe->ibuf);
306ee103ef4Srenato 	close(iev_ospfe->ibuf.fd);
3079cbf9e90Sclaudio 	imsgbuf_clear(&iev_rde->ibuf);
308ee103ef4Srenato 	close(iev_rde->ibuf.fd);
309a1a4e97bSnorby 
310faef135eSremi 	control_cleanup();
311a1a4e97bSnorby 	kr_shutdown();
312a1a4e97bSnorby 	carp_demote_shutdown();
313a1a4e97bSnorby 
314ee103ef4Srenato 	log_debug("waiting for children to terminate");
315a1a4e97bSnorby 	do {
316ee103ef4Srenato 		pid = wait(&status);
317ee103ef4Srenato 		if (pid == -1) {
318ee103ef4Srenato 			if (errno != EINTR && errno != ECHILD)
319a1a4e97bSnorby 				fatal("wait");
320ee103ef4Srenato 		} else if (WIFSIGNALED(status))
321ee103ef4Srenato 			log_warnx("%s terminated; signal %d",
322ee103ef4Srenato 			    (pid == rde_pid) ? "route decision engine" :
323ee103ef4Srenato 			    "ospf engine", WTERMSIG(status));
324a1a4e97bSnorby 	} while (pid != -1 || (pid == -1 && errno == EINTR));
325a1a4e97bSnorby 
326f78850efSeric 	free(iev_ospfe);
327f78850efSeric 	free(iev_rde);
328a1a4e97bSnorby 	free(ospfd_conf);
329a1a4e97bSnorby 
330a1a4e97bSnorby 	log_info("terminating");
331a1a4e97bSnorby 	exit(0);
332a1a4e97bSnorby }
333a1a4e97bSnorby 
334a1a4e97bSnorby /* imsg handling */
335a1a4e97bSnorby void
336a1a4e97bSnorby main_dispatch_ospfe(int fd, short event, void *bula)
337a1a4e97bSnorby {
338f78850efSeric 	struct imsgev		*iev = bula;
339f78850efSeric 	struct imsgbuf		*ibuf = &iev->ibuf;
340a1a4e97bSnorby 	struct imsg		 imsg;
341a1a4e97bSnorby 	struct demote_msg	 dmsg;
342a1a4e97bSnorby 	ssize_t			 n;
343a97e7964Sclaudio 	int			 shut = 0, verbose;
344a1a4e97bSnorby 
34541e7b05eSclaudio 	if (event & EV_READ) {
346668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
347dd7efffeSclaudio 			fatal("imsgbuf_read error");
348a1a4e97bSnorby 		if (n == 0)	/* connection closed */
349a1a4e97bSnorby 			shut = 1;
35041e7b05eSclaudio 	}
35141e7b05eSclaudio 	if (event & EV_WRITE) {
352dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
353c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
3541203692fSkrw 				shut = 1;
355c1aa9554Sclaudio 			else
356dd7efffeSclaudio 				fatal("imsgbuf_write");
357c1aa9554Sclaudio 		}
358a1a4e97bSnorby 	}
359a1a4e97bSnorby 
360a1a4e97bSnorby 	for (;;) {
361a1a4e97bSnorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
362a1a4e97bSnorby 			fatal("imsg_get");
363a1a4e97bSnorby 
364a1a4e97bSnorby 		if (n == 0)
365a1a4e97bSnorby 			break;
366a1a4e97bSnorby 
367a1a4e97bSnorby 		switch (imsg.hdr.type) {
368a1a4e97bSnorby 		case IMSG_CTL_RELOAD:
369a1a4e97bSnorby 			if (ospf_reload() == -1)
370a1a4e97bSnorby 				log_warnx("configuration reload failed");
371a1a4e97bSnorby 			else
372a1a4e97bSnorby 				log_debug("configuration reloaded");
373a1a4e97bSnorby 			break;
374a1a4e97bSnorby 		case IMSG_CTL_FIB_COUPLE:
375a1a4e97bSnorby 			kr_fib_couple();
376a1a4e97bSnorby 			break;
377a1a4e97bSnorby 		case IMSG_CTL_FIB_DECOUPLE:
378a1a4e97bSnorby 			kr_fib_decouple();
379a1a4e97bSnorby 			break;
380dd3b9a80Ssthen 		case IMSG_CTL_FIB_RELOAD:
381dd3b9a80Ssthen 			kr_fib_reload();
382dd3b9a80Ssthen 			break;
383a1a4e97bSnorby 		case IMSG_CTL_KROUTE:
384a1a4e97bSnorby 		case IMSG_CTL_KROUTE_ADDR:
385a1a4e97bSnorby 			kr_show_route(&imsg);
386a1a4e97bSnorby 			break;
387a1a4e97bSnorby 		case IMSG_DEMOTE:
388a1a4e97bSnorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg))
389a1a4e97bSnorby 				fatalx("invalid size of OE request");
390a1a4e97bSnorby 			memcpy(&dmsg, imsg.data, sizeof(dmsg));
391a1a4e97bSnorby 			carp_demote_set(dmsg.demote_group, dmsg.level);
392a1a4e97bSnorby 			break;
393a97e7964Sclaudio 		case IMSG_CTL_LOG_VERBOSE:
394a97e7964Sclaudio 			/* already checked by ospfe */
395a97e7964Sclaudio 			memcpy(&verbose, imsg.data, sizeof(verbose));
396189fd1ceSbenno 			log_setverbose(verbose);
397a97e7964Sclaudio 			break;
398a1a4e97bSnorby 		default:
399a1a4e97bSnorby 			log_debug("main_dispatch_ospfe: error handling imsg %d",
400a1a4e97bSnorby 			    imsg.hdr.type);
401a1a4e97bSnorby 			break;
402a1a4e97bSnorby 		}
403a1a4e97bSnorby 		imsg_free(&imsg);
404a1a4e97bSnorby 	}
405a1a4e97bSnorby 	if (!shut)
406f78850efSeric 		imsg_event_add(iev);
407a1a4e97bSnorby 	else {
408a1a4e97bSnorby 		/* this pipe is dead, so remove the event handler */
409f78850efSeric 		event_del(&iev->ev);
410a1a4e97bSnorby 		event_loopexit(NULL);
411a1a4e97bSnorby 	}
412a1a4e97bSnorby }
413a1a4e97bSnorby 
414a1a4e97bSnorby void
415a1a4e97bSnorby main_dispatch_rde(int fd, short event, void *bula)
416a1a4e97bSnorby {
417f78850efSeric 	struct imsgev	*iev = bula;
418f78850efSeric 	struct imsgbuf	*ibuf = &iev->ibuf;
419a1a4e97bSnorby 	struct imsg	 imsg;
420a1a4e97bSnorby 	ssize_t		 n;
421722a4e30Sfriehm 	int		 count, shut = 0;
422a1a4e97bSnorby 
42341e7b05eSclaudio 	if (event & EV_READ) {
424668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
425dd7efffeSclaudio 			fatal("imsgbuf_read error");
426a1a4e97bSnorby 		if (n == 0)	/* connection closed */
427a1a4e97bSnorby 			shut = 1;
42841e7b05eSclaudio 	}
42941e7b05eSclaudio 	if (event & EV_WRITE) {
430dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
431c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
4321203692fSkrw 				shut = 1;
433c1aa9554Sclaudio 			else
434dd7efffeSclaudio 				fatal("imsgbuf_write");
435c1aa9554Sclaudio 		}
436a1a4e97bSnorby 	}
437a1a4e97bSnorby 
438a1a4e97bSnorby 	for (;;) {
439a1a4e97bSnorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
440a1a4e97bSnorby 			fatal("imsg_get");
441a1a4e97bSnorby 
442a1a4e97bSnorby 		if (n == 0)
443a1a4e97bSnorby 			break;
444a1a4e97bSnorby 
445a1a4e97bSnorby 		switch (imsg.hdr.type) {
446a1a4e97bSnorby 		case IMSG_KROUTE_CHANGE:
447722a4e30Sfriehm 			count = (imsg.hdr.len - IMSG_HEADER_SIZE) /
448722a4e30Sfriehm 			    sizeof(struct kroute);
449722a4e30Sfriehm 			if (kr_change(imsg.data, count))
450a1a4e97bSnorby 				log_warn("main_dispatch_rde: error changing "
451a1a4e97bSnorby 				    "route");
452a1a4e97bSnorby 			break;
453a1a4e97bSnorby 		case IMSG_KROUTE_DELETE:
454a1a4e97bSnorby 			if (kr_delete(imsg.data))
455a1a4e97bSnorby 				log_warn("main_dispatch_rde: error deleting "
456a1a4e97bSnorby 				    "route");
457a1a4e97bSnorby 			break;
458a1a4e97bSnorby 		default:
459a1a4e97bSnorby 			log_debug("main_dispatch_rde: error handling imsg %d",
460a1a4e97bSnorby 			    imsg.hdr.type);
461a1a4e97bSnorby 			break;
462a1a4e97bSnorby 		}
463a1a4e97bSnorby 		imsg_free(&imsg);
464a1a4e97bSnorby 	}
465a1a4e97bSnorby 	if (!shut)
466f78850efSeric 		imsg_event_add(iev);
467a1a4e97bSnorby 	else {
468a1a4e97bSnorby 		/* this pipe is dead, so remove the event handler */
469f78850efSeric 		event_del(&iev->ev);
470a1a4e97bSnorby 		event_loopexit(NULL);
471a1a4e97bSnorby 	}
472a1a4e97bSnorby }
473a1a4e97bSnorby 
474a1a4e97bSnorby void
475a1a4e97bSnorby main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen)
476a1a4e97bSnorby {
4778e1674f3Sbluhm 	if (iev_ospfe == NULL)
4788e1674f3Sbluhm 		return;
479f78850efSeric 	imsg_compose_event(iev_ospfe, type, 0, pid, -1, data, datalen);
480a1a4e97bSnorby }
481a1a4e97bSnorby 
482a1a4e97bSnorby void
483cb75d791Sremi main_imsg_compose_ospfe_fd(int type, pid_t pid, int fd)
484cb75d791Sremi {
485cb75d791Sremi 	if (iev_ospfe == NULL)
486cb75d791Sremi 		return;
487cb75d791Sremi 	imsg_compose_event(iev_ospfe, type, 0, pid, fd, NULL, 0);
488cb75d791Sremi }
489cb75d791Sremi 
490cb75d791Sremi void
491a1a4e97bSnorby main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
492a1a4e97bSnorby {
493787da5a7Sbluhm 	if (iev_rde == NULL)
494787da5a7Sbluhm 		return;
495f78850efSeric 	imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
496a1a4e97bSnorby }
497a1a4e97bSnorby 
498a1a4e97bSnorby void
499f78850efSeric imsg_event_add(struct imsgev *iev)
500a1a4e97bSnorby {
501f78850efSeric 	iev->events = EV_READ;
50231be28caSclaudio 	if (imsgbuf_queuelen(&iev->ibuf) > 0)
503f78850efSeric 		iev->events |= EV_WRITE;
504a1a4e97bSnorby 
505f78850efSeric 	event_del(&iev->ev);
506f78850efSeric 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
507f78850efSeric 	event_add(&iev->ev, NULL);
508f78850efSeric }
509f78850efSeric 
510f78850efSeric int
511f78850efSeric imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
512f78850efSeric     pid_t pid, int fd, void *data, u_int16_t datalen)
513f78850efSeric {
514f78850efSeric 	int	ret;
515f78850efSeric 
516f78850efSeric 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
517f78850efSeric 	    pid, fd, data, datalen)) != -1)
518f78850efSeric 		imsg_event_add(iev);
519f78850efSeric 	return (ret);
520a1a4e97bSnorby }
521a1a4e97bSnorby 
522a1a4e97bSnorby int
523a1a4e97bSnorby ospf_redistribute(struct kroute *kr, u_int32_t *metric)
524a1a4e97bSnorby {
525a1a4e97bSnorby 	struct redistribute	*r;
526f8efa005Sclaudio 	struct in6_addr		 ina, inb;
527a66c91f2Sremi 	struct iface		*iface;
52893c5cf97Sbluhm 	u_int8_t		 is_default = 0;
529a66c91f2Sremi 	int			 depend_ok;
530a1a4e97bSnorby 
53193c5cf97Sbluhm 	/* only allow ::/0 via REDIST_DEFAULT */
532f8efa005Sclaudio 	if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) && kr->prefixlen == 0)
53393c5cf97Sbluhm 		is_default = 1;
534a1a4e97bSnorby 
535a1a4e97bSnorby 	SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) {
536a66c91f2Sremi 		if (r->dependon[0] != '\0') {
537a66c91f2Sremi 			if ((iface = if_findname(r->dependon)))
538a66c91f2Sremi 				depend_ok = ifstate_is_up(iface);
539a66c91f2Sremi 			else
540a66c91f2Sremi 				depend_ok = 0;
541a66c91f2Sremi 		} else
542a66c91f2Sremi 			depend_ok = 1;
543a66c91f2Sremi 
544a1a4e97bSnorby 		switch (r->type & ~REDIST_NO) {
545a1a4e97bSnorby 		case REDIST_LABEL:
546a1a4e97bSnorby 			if (kr->rtlabel == r->label) {
54717e34b32Sremi 				*metric = depend_ok ? r->metric :
54817e34b32Sremi 				    r->metric | MAX_METRIC;
549a1a4e97bSnorby 				return (r->type & REDIST_NO ? 0 : 1);
550a1a4e97bSnorby 			}
551a1a4e97bSnorby 			break;
552a1a4e97bSnorby 		case REDIST_STATIC:
553a1a4e97bSnorby 			/*
554a1a4e97bSnorby 			 * Dynamic routes are not redistributable. Placed here
555a1a4e97bSnorby 			 * so that link local addresses can be redistributed
556a1a4e97bSnorby 			 * via a rtlabel.
557a1a4e97bSnorby 			 */
55893c5cf97Sbluhm 			if (is_default)
55993c5cf97Sbluhm 				continue;
560a1a4e97bSnorby 			if (kr->flags & F_DYNAMIC)
561a1a4e97bSnorby 				continue;
562a1a4e97bSnorby 			if (kr->flags & F_STATIC) {
56317e34b32Sremi 				*metric = depend_ok ? r->metric :
56417e34b32Sremi 				    r->metric | MAX_METRIC;
565a1a4e97bSnorby 				return (r->type & REDIST_NO ? 0 : 1);
566a1a4e97bSnorby 			}
567a1a4e97bSnorby 			break;
568a1a4e97bSnorby 		case REDIST_CONNECTED:
56993c5cf97Sbluhm 			if (is_default)
57093c5cf97Sbluhm 				continue;
571a1a4e97bSnorby 			if (kr->flags & F_DYNAMIC)
572a1a4e97bSnorby 				continue;
573a1a4e97bSnorby 			if (kr->flags & F_CONNECTED) {
57417e34b32Sremi 				*metric = depend_ok ? r->metric :
57517e34b32Sremi 				    r->metric | MAX_METRIC;
576a1a4e97bSnorby 				return (r->type & REDIST_NO ? 0 : 1);
577a1a4e97bSnorby 			}
578a1a4e97bSnorby 			break;
579a1a4e97bSnorby 		case REDIST_ADDR:
580a1a4e97bSnorby 			if (kr->flags & F_DYNAMIC)
581a1a4e97bSnorby 				continue;
58293c5cf97Sbluhm 
58393c5cf97Sbluhm 			if (IN6_IS_ADDR_UNSPECIFIED(&r->addr) &&
58493c5cf97Sbluhm 			    r->prefixlen == 0) {
58593c5cf97Sbluhm 				if (is_default) {
586a66c91f2Sremi 					*metric = depend_ok ? r->metric :
58717e34b32Sremi 					    r->metric | MAX_METRIC;
58893c5cf97Sbluhm 					return (r->type & REDIST_NO ? 0 : 1);
58993c5cf97Sbluhm 				} else
59093c5cf97Sbluhm 					return (0);
59193c5cf97Sbluhm 			}
59293c5cf97Sbluhm 
59393c5cf97Sbluhm 			inet6applymask(&ina, &kr->prefix, r->prefixlen);
594f8efa005Sclaudio 			inet6applymask(&inb, &r->addr, r->prefixlen);
595f8efa005Sclaudio 			if (IN6_ARE_ADDR_EQUAL(&ina, &inb) &&
596f8efa005Sclaudio 			    kr->prefixlen >= r->prefixlen) {
59717e34b32Sremi 				*metric = depend_ok ? r->metric :
59817e34b32Sremi 				    r->metric | MAX_METRIC;
599a1a4e97bSnorby 				return (r->type & REDIST_NO ? 0 : 1);
600a1a4e97bSnorby 			}
601a1a4e97bSnorby 			break;
60293c5cf97Sbluhm 		case REDIST_DEFAULT:
60393c5cf97Sbluhm 			if (is_default) {
60417e34b32Sremi 				*metric = depend_ok ? r->metric :
60517e34b32Sremi 				    r->metric | MAX_METRIC;
60693c5cf97Sbluhm 				return (r->type & REDIST_NO ? 0 : 1);
60793c5cf97Sbluhm 			}
60893c5cf97Sbluhm 			break;
609a1a4e97bSnorby 		}
610a1a4e97bSnorby 	}
611a1a4e97bSnorby 
612a1a4e97bSnorby 	return (0);
613a1a4e97bSnorby }
614a1a4e97bSnorby 
615a1a4e97bSnorby int
616a1a4e97bSnorby ospf_reload(void)
617a1a4e97bSnorby {
6188bf9509aSjca #ifdef notyet
619a1a4e97bSnorby 	struct area		*area;
620a1a4e97bSnorby 	struct ospfd_conf	*xconf;
621a1a4e97bSnorby 
622a1a4e97bSnorby 	if ((xconf = parse_config(conffile, ospfd_conf->opts)) == NULL)
623a1a4e97bSnorby 		return (-1);
624a1a4e97bSnorby 
62544dcc3eeSjca 	/* XXX bail out if router-id changed */
62644dcc3eeSjca 
627a1a4e97bSnorby 	/* send config to childs */
628a1a4e97bSnorby 	if (ospf_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
629a1a4e97bSnorby 		return (-1);
630a1a4e97bSnorby 
6316c9e7a5bSclaudio 	/* send areas, interfaces happen out of band */
632a1a4e97bSnorby 	LIST_FOREACH(area, &xconf->area_list, entry) {
633a1a4e97bSnorby 		if (ospf_sendboth(IMSG_RECONF_AREA, area, sizeof(*area)) == -1)
634a1a4e97bSnorby 			return (-1);
635a1a4e97bSnorby 	}
636a1a4e97bSnorby 
637a1a4e97bSnorby 	if (ospf_sendboth(IMSG_RECONF_END, NULL, 0) == -1)
638a1a4e97bSnorby 		return (-1);
639a1a4e97bSnorby 
6406c9e7a5bSclaudio 	/* XXX send newly available interfaces to the childs */
6416c9e7a5bSclaudio 
642a1a4e97bSnorby 	merge_config(ospfd_conf, xconf);
643a1a4e97bSnorby 	/* update redistribute lists */
6444cf51530Sdenis 	kr_reload(ospfd_conf->redist_label_or_prefix);
645a1a4e97bSnorby 	return (0);
6468bf9509aSjca #else
6478bf9509aSjca 	return (-1);
6488bf9509aSjca #endif
649a1a4e97bSnorby }
650a1a4e97bSnorby 
651a1a4e97bSnorby int
652a1a4e97bSnorby ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len)
653a1a4e97bSnorby {
654f78850efSeric 	if (imsg_compose_event(iev_ospfe, type, 0, 0, -1, buf, len) == -1)
655a1a4e97bSnorby 		return (-1);
656f78850efSeric 	if (imsg_compose_event(iev_rde, type, 0, 0, -1, buf, len) == -1)
657a1a4e97bSnorby 		return (-1);
658a1a4e97bSnorby 	return (0);
659a1a4e97bSnorby }
660a1a4e97bSnorby 
661a1a4e97bSnorby void
662a1a4e97bSnorby merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf)
663a1a4e97bSnorby {
664a1a4e97bSnorby 	struct area		*a, *xa, *na;
665a1a4e97bSnorby 	struct iface		*iface;
666a1a4e97bSnorby 	struct redistribute	*r;
6674cf51530Sdenis 	int			 rchange = 0;
668a1a4e97bSnorby 
669a1a4e97bSnorby 	/* change of rtr_id needs a restart */
670a1a4e97bSnorby 	conf->flags = xconf->flags;
671a1a4e97bSnorby 	conf->spf_delay = xconf->spf_delay;
672a1a4e97bSnorby 	conf->spf_hold_time = xconf->spf_hold_time;
6734cf51530Sdenis 	if (SIMPLEQ_EMPTY(&conf->redist_list) !=
6744cf51530Sdenis 	    SIMPLEQ_EMPTY(&xconf->redist_list))
6754cf51530Sdenis 		rchange = 1;
6764cf51530Sdenis 	conf->redist_label_or_prefix = xconf->redist_label_or_prefix;
677a1a4e97bSnorby 
678a1a4e97bSnorby 	if (ospfd_process == PROC_MAIN) {
679a1a4e97bSnorby 		/* main process does neither use areas nor interfaces */
680a1a4e97bSnorby 		while ((r = SIMPLEQ_FIRST(&conf->redist_list)) != NULL) {
681a1a4e97bSnorby 			SIMPLEQ_REMOVE_HEAD(&conf->redist_list, entry);
682a1a4e97bSnorby 			free(r);
683a1a4e97bSnorby 		}
68461b37dc2Sbket 		SIMPLEQ_CONCAT(&conf->redist_list, &xconf->redist_list);
6854cf51530Sdenis 
6864cf51530Sdenis 		/* adjust FIB priority if changed */
6874cf51530Sdenis 		if (conf->fib_priority != xconf->fib_priority) {
6884cf51530Sdenis 			kr_fib_decouple();
6894cf51530Sdenis 			kr_fib_update_prio(xconf->fib_priority);
6904cf51530Sdenis 			conf->fib_priority = xconf->fib_priority;
6914cf51530Sdenis 			kr_fib_couple();
6924cf51530Sdenis 		}
6934cf51530Sdenis 
694a1a4e97bSnorby 		goto done;
695a1a4e97bSnorby 	}
696a1a4e97bSnorby 
697a1a4e97bSnorby 	/* merge areas and interfaces */
698a1a4e97bSnorby 	for (a = LIST_FIRST(&conf->area_list); a != NULL; a = na) {
699a1a4e97bSnorby 		na = LIST_NEXT(a, entry);
700a1a4e97bSnorby 		/* find deleted areas */
701a1a4e97bSnorby 		if ((xa = area_find(xconf, a->id)) == NULL) {
702a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE) {
703a1a4e97bSnorby 				LIST_FOREACH(iface, &a->iface_list, entry)
704a1a4e97bSnorby 					if_fsm(iface, IF_EVT_DOWN);
705a1a4e97bSnorby 			}
706a1a4e97bSnorby 			LIST_REMOVE(a, entry);
707a1a4e97bSnorby 			area_del(a);
708a1a4e97bSnorby 		}
709a1a4e97bSnorby 	}
710a1a4e97bSnorby 
711a1a4e97bSnorby 	for (xa = LIST_FIRST(&xconf->area_list); xa != NULL; xa = na) {
712a1a4e97bSnorby 		na = LIST_NEXT(xa, entry);
713a1a4e97bSnorby 		if ((a = area_find(conf, xa->id)) == NULL) {
714a1a4e97bSnorby 			LIST_REMOVE(xa, entry);
715a1a4e97bSnorby 			LIST_INSERT_HEAD(&conf->area_list, xa, entry);
716a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE) {
717a1a4e97bSnorby 				/* start interfaces */
718a1a4e97bSnorby 				ospfe_demote_area(xa, 0);
7196c9e7a5bSclaudio 				LIST_FOREACH(iface, &xa->iface_list, entry)
7206c9e7a5bSclaudio 					if_start(conf, iface);
721a1a4e97bSnorby 			}
722a1a4e97bSnorby 			/* no need to merge interfaces */
723a1a4e97bSnorby 			continue;
724a1a4e97bSnorby 		}
725a1a4e97bSnorby 		/*
726a1a4e97bSnorby 		 * stub is not yet used but switching between stub and normal
727a1a4e97bSnorby 		 * will be another painful job.
728a1a4e97bSnorby 		 */
729a1a4e97bSnorby 		a->stub = xa->stub;
730a1a4e97bSnorby 		a->stub_default_cost = xa->stub_default_cost;
731a1a4e97bSnorby 		if (ospfd_process == PROC_RDE_ENGINE)
732a1a4e97bSnorby 			a->dirty = 1; /* force SPF tree recalculation */
733a1a4e97bSnorby 
734a1a4e97bSnorby 		/* merge interfaces */
735a1a4e97bSnorby 		if (merge_interfaces(a, xa) &&
736a1a4e97bSnorby 		    ospfd_process == PROC_OSPF_ENGINE)
737a1a4e97bSnorby 			a->dirty = 1; /* force rtr LSA update */
738a1a4e97bSnorby 	}
739a1a4e97bSnorby 
740a1a4e97bSnorby 	if (ospfd_process == PROC_OSPF_ENGINE) {
741a1a4e97bSnorby 		LIST_FOREACH(a, &conf->area_list, entry) {
742a1a4e97bSnorby 			LIST_FOREACH(iface, &a->iface_list, entry) {
743a1a4e97bSnorby 				if (iface->state == IF_STA_NEW) {
744a1a4e97bSnorby 					iface->state = IF_STA_DOWN;
7456c9e7a5bSclaudio 					if_start(conf, iface);
746a1a4e97bSnorby 				}
747a1a4e97bSnorby 			}
7485aa580cfSnaddy 			if (a->dirty || rchange) {
749a1a4e97bSnorby 				a->dirty = 0;
750d18517d2Sdenis 				orig_rtr_lsa(LIST_FIRST(&a->iface_list)->area);
751a1a4e97bSnorby 			}
752a1a4e97bSnorby 		}
753a1a4e97bSnorby 	}
754a1a4e97bSnorby 
755a1a4e97bSnorby done:
756a1a4e97bSnorby 	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
757a1a4e97bSnorby 		LIST_REMOVE(a, entry);
758a1a4e97bSnorby 		area_del(a);
759a1a4e97bSnorby 	}
760a1a4e97bSnorby 	free(xconf);
761a1a4e97bSnorby }
762a1a4e97bSnorby 
763a1a4e97bSnorby int
764a1a4e97bSnorby merge_interfaces(struct area *a, struct area *xa)
765a1a4e97bSnorby {
766a1a4e97bSnorby 	struct iface	*i, *xi, *ni;
767a1a4e97bSnorby 	int		 dirty = 0;
768a1a4e97bSnorby 
769a1a4e97bSnorby 	/* problems:
770a1a4e97bSnorby 	 * - new interfaces (easy)
771a1a4e97bSnorby 	 * - deleted interfaces (needs to be done via fsm?)
772a1a4e97bSnorby 	 * - changing passive (painful?)
773a1a4e97bSnorby 	 */
774a1a4e97bSnorby 	for (i = LIST_FIRST(&a->iface_list); i != NULL; i = ni) {
775a1a4e97bSnorby 		ni = LIST_NEXT(i, entry);
776a1a4e97bSnorby 		if (iface_lookup(xa, i) == NULL) {
77760657642Smichele 			log_debug("merge_interfaces: proc %d area %s removing "
778a1a4e97bSnorby 			    "interface %s", ospfd_process, inet_ntoa(a->id),
779a1a4e97bSnorby 			    i->name);
780a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE)
781a1a4e97bSnorby 				if_fsm(i, IF_EVT_DOWN);
782a1a4e97bSnorby 			LIST_REMOVE(i, entry);
783a1a4e97bSnorby 			if_del(i);
784a1a4e97bSnorby 		}
785a1a4e97bSnorby 	}
786a1a4e97bSnorby 
787a1a4e97bSnorby 	for (xi = LIST_FIRST(&xa->iface_list); xi != NULL; xi = ni) {
788a1a4e97bSnorby 		ni = LIST_NEXT(xi, entry);
789a1a4e97bSnorby 		if ((i = iface_lookup(a, xi)) == NULL) {
790a1a4e97bSnorby 			/* new interface but delay initialisation */
79160657642Smichele 			log_debug("merge_interfaces: proc %d area %s adding "
792a1a4e97bSnorby 			    "interface %s", ospfd_process, inet_ntoa(a->id),
793a1a4e97bSnorby 			    xi->name);
794a1a4e97bSnorby 			LIST_REMOVE(xi, entry);
795a1a4e97bSnorby 			LIST_INSERT_HEAD(&a->iface_list, xi, entry);
796a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE)
797a1a4e97bSnorby 				xi->state = IF_STA_NEW;
798a1a4e97bSnorby 			continue;
799a1a4e97bSnorby 		}
80060657642Smichele 		log_debug("merge_interfaces: proc %d area %s merging "
80160657642Smichele 		    "interface %s", ospfd_process, inet_ntoa(a->id), i->name);
802a1a4e97bSnorby 		i->addr = xi->addr;
803a1a4e97bSnorby 		i->dst = xi->dst;
804a1a4e97bSnorby 		i->abr_id = xi->abr_id;
805a1a4e97bSnorby 		i->baudrate = xi->baudrate;
806a1a4e97bSnorby 		i->dead_interval = xi->dead_interval;
807a1a4e97bSnorby 		i->mtu = xi->mtu;
808a1a4e97bSnorby 		i->transmit_delay = xi->transmit_delay;
809a1a4e97bSnorby 		i->hello_interval = xi->hello_interval;
810a1a4e97bSnorby 		i->rxmt_interval = xi->rxmt_interval;
811a1a4e97bSnorby 		if (i->metric != xi->metric)
812a1a4e97bSnorby 			dirty = 1;
813a1a4e97bSnorby 		i->metric = xi->metric;
814a1a4e97bSnorby 		i->priority = xi->priority;
8154cf51530Sdenis 		if (i->self)
8164cf51530Sdenis 			i->self->priority = i->priority;
817a1a4e97bSnorby 		i->flags = xi->flags; /* needed? */
818a1a4e97bSnorby 		i->type = xi->type; /* needed? */
81918ffdd94Sstsp 		i->if_type = xi->if_type; /* needed? */
820a1a4e97bSnorby 		i->linkstate = xi->linkstate; /* needed? */
821a1a4e97bSnorby 
8226c9e7a5bSclaudio #if 0 /* XXX needs some kind of love */
823a1a4e97bSnorby 		if (i->passive != xi->passive) {
824a1a4e97bSnorby 			/* need to restart interface to cope with this change */
825a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE)
826a1a4e97bSnorby 				if_fsm(i, IF_EVT_DOWN);
827a1a4e97bSnorby 			i->passive = xi->passive;
828a1a4e97bSnorby 			if (ospfd_process == PROC_OSPF_ENGINE)
829a1a4e97bSnorby 				if_fsm(i, IF_EVT_UP);
830a1a4e97bSnorby 		}
8316c9e7a5bSclaudio #endif
832a1a4e97bSnorby 	}
833a1a4e97bSnorby 	return (dirty);
834a1a4e97bSnorby }
835a1a4e97bSnorby 
836a1a4e97bSnorby struct iface *
837a1a4e97bSnorby iface_lookup(struct area *area, struct iface *iface)
838a1a4e97bSnorby {
839a1a4e97bSnorby 	struct iface	*i;
840a1a4e97bSnorby 
841a1a4e97bSnorby 	LIST_FOREACH(i, &area->iface_list, entry)
842a1a4e97bSnorby 		if (i->ifindex == iface->ifindex)
843a1a4e97bSnorby 			return (i);
844a1a4e97bSnorby 	return (NULL);
845a1a4e97bSnorby }
846a66c91f2Sremi 
847a66c91f2Sremi int
848a66c91f2Sremi ifstate_is_up(struct iface *iface)
849a66c91f2Sremi {
850a66c91f2Sremi 	if (!(iface->flags & IFF_UP))
851a66c91f2Sremi 		return (0);
852a66c91f2Sremi 	if (iface->if_type == IFT_CARP &&
853a66c91f2Sremi 	    iface->linkstate == LINK_STATE_UNKNOWN)
854a66c91f2Sremi 		return (0);
855a66c91f2Sremi 	return LINK_STATE_IS_UP(iface->linkstate);
856a66c91f2Sremi }
857