xref: /openbsd-src/usr.sbin/ospfd/parse.y (revision d2a044ef87d19b9796f1fdd0b283448d5a58c6c5)
1*d2a044efStb /*	$OpenBSD: parse.y,v 1.106 2024/08/22 08:34:51 tb Exp $ */
2204df0f8Sclaudio 
3204df0f8Sclaudio /*
43ada9d8fSnorby  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5204df0f8Sclaudio  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6204df0f8Sclaudio  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7204df0f8Sclaudio  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8204df0f8Sclaudio  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9204df0f8Sclaudio  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10204df0f8Sclaudio  *
11204df0f8Sclaudio  * Permission to use, copy, modify, and distribute this software for any
12204df0f8Sclaudio  * purpose with or without fee is hereby granted, provided that the above
13204df0f8Sclaudio  * copyright notice and this permission notice appear in all copies.
14204df0f8Sclaudio  *
15204df0f8Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16204df0f8Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17204df0f8Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18204df0f8Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19204df0f8Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20204df0f8Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21204df0f8Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22204df0f8Sclaudio  */
23204df0f8Sclaudio 
24204df0f8Sclaudio %{
25204df0f8Sclaudio #include <sys/types.h>
26204df0f8Sclaudio #include <sys/socket.h>
2720741916Sderaadt #include <sys/stat.h>
284c260f66Sremi #include <net/route.h>
29204df0f8Sclaudio #include <netinet/in.h>
30204df0f8Sclaudio #include <arpa/inet.h>
31204df0f8Sclaudio #include <ctype.h>
32204df0f8Sclaudio #include <err.h>
33204df0f8Sclaudio #include <errno.h>
3420741916Sderaadt #include <unistd.h>
35f12637e5Smsf #include <ifaddrs.h>
362e8dee25Smillert #include <limits.h>
37204df0f8Sclaudio #include <stdarg.h>
38204df0f8Sclaudio #include <stdio.h>
39204df0f8Sclaudio #include <string.h>
4036f8cec5Ssthen #include <syslog.h>
41204df0f8Sclaudio 
42204df0f8Sclaudio #include "ospf.h"
43204df0f8Sclaudio #include "ospfd.h"
44204df0f8Sclaudio #include "ospfe.h"
45204df0f8Sclaudio #include "log.h"
46204df0f8Sclaudio 
4720741916Sderaadt TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
4820741916Sderaadt static struct file {
4920741916Sderaadt 	TAILQ_ENTRY(file)	 entry;
5020741916Sderaadt 	FILE			*stream;
5120741916Sderaadt 	char			*name;
52a8823310Sdenis 	size_t			 ungetpos;
53a8823310Sdenis 	size_t			 ungetsize;
54a8823310Sdenis 	u_char			*ungetbuf;
55a8823310Sdenis 	int			 eof_reached;
5620741916Sderaadt 	int			 lineno;
5720741916Sderaadt 	int			 errors;
58c6004ab9Smpf } *file, *topfile;
5920741916Sderaadt struct file	*pushfile(const char *, int);
6020741916Sderaadt int		 popfile(void);
6120741916Sderaadt int		 check_file_secrecy(int, const char *);
62204df0f8Sclaudio int		 yyparse(void);
6320741916Sderaadt int		 yylex(void);
649c81ce9fSdoug int		 yyerror(const char *, ...)
659c81ce9fSdoug     __attribute__((__format__ (printf, 1, 2)))
669c81ce9fSdoug     __attribute__((__nonnull__ (1)));
67204df0f8Sclaudio int		 kw_cmp(const void *, const void *);
68204df0f8Sclaudio int		 lookup(char *);
69a8823310Sdenis int		 igetc(void);
70d5d66eaeSderaadt int		 lgetc(int);
71a8823310Sdenis void		 lungetc(int);
72204df0f8Sclaudio int		 findeol(void);
7320741916Sderaadt 
7420741916Sderaadt TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
7520741916Sderaadt struct sym {
7620741916Sderaadt 	TAILQ_ENTRY(sym)	 entry;
7720741916Sderaadt 	int			 used;
7820741916Sderaadt 	int			 persist;
7920741916Sderaadt 	char			*nam;
8020741916Sderaadt 	char			*val;
8120741916Sderaadt };
8220741916Sderaadt int		 symset(const char *, const char *, int);
8320741916Sderaadt char		*symget(const char *);
8420741916Sderaadt 
85204df0f8Sclaudio void		 clear_config(struct ospfd_conf *xconf);
86471ee2ebSclaudio int		 host(const char *, struct in_addr *, struct in_addr *);
87204df0f8Sclaudio 
8820741916Sderaadt static struct ospfd_conf	*conf;
8920741916Sderaadt static int			 errors = 0;
9020741916Sderaadt 
9120741916Sderaadt struct area	*area = NULL;
9220741916Sderaadt struct iface	*iface = NULL;
9320741916Sderaadt 
94627c6412Sclaudio struct config_defaults {
9576b51f83Sclaudio 	char		auth_key[MAX_SIMPLE_AUTH_LEN];
9676b51f83Sclaudio 	struct auth_md_head	 md_list;
97204df0f8Sclaudio 	u_int32_t	dead_interval;
987afdfd2dSdlg 	u_int32_t	fast_hello_interval;
991d3a1c7dSnorby 	u_int16_t	transmit_delay;
100204df0f8Sclaudio 	u_int16_t	hello_interval;
101204df0f8Sclaudio 	u_int16_t	rxmt_interval;
102204df0f8Sclaudio 	u_int16_t	metric;
10376b51f83Sclaudio 	enum auth_type	auth_type;
10476b51f83Sclaudio 	u_int8_t	auth_keyid;
105204df0f8Sclaudio 	u_int8_t	priority;
10609e8f780Sremi 	u_int8_t	p2p;
107627c6412Sclaudio };
108627c6412Sclaudio 
109627c6412Sclaudio struct config_defaults	 globaldefs;
110627c6412Sclaudio struct config_defaults	 areadefs;
111627c6412Sclaudio struct config_defaults	 ifacedefs;
112627c6412Sclaudio struct config_defaults	*defs;
113204df0f8Sclaudio 
114204df0f8Sclaudio struct area	*conf_get_area(struct in_addr);
11566dd3991Sclaudio struct iface	*conf_get_if(struct kif *, struct kif_addr *);
116358269bbSclaudio int		 conf_check_rdomain(unsigned int);
117204df0f8Sclaudio 
118204df0f8Sclaudio typedef struct {
119204df0f8Sclaudio 	union {
12091d3283aSclaudio 		int64_t		 number;
121204df0f8Sclaudio 		char		*string;
1226fa28760Sclaudio 		struct redistribute *redist;
123cacfc040Sdlg 		struct in_addr	 id;
124204df0f8Sclaudio 	} v;
125204df0f8Sclaudio 	int lineno;
126204df0f8Sclaudio } YYSTYPE;
127204df0f8Sclaudio 
128204df0f8Sclaudio %}
129204df0f8Sclaudio 
1304c260f66Sremi %token	AREA INTERFACE ROUTERID FIBPRIORITY FIBUPDATE REDISTRIBUTE RTLABEL
1314c260f66Sremi %token	RDOMAIN RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
13203431b74Snorby %token	AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
133ef209401Sremi %token	METRIC P2P PASSIVE
1347afdfd2dSdlg %token	HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY
135204df0f8Sclaudio %token	RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
136f373ed5aSclaudio %token	SET TYPE
137619421e7Sclaudio %token	YES NO
1387afdfd2dSdlg %token	MSEC MINIMAL
139fba2d3d0Sclaudio %token	DEMOTE
1404fd4397dSdlg %token	INCLUDE
141204df0f8Sclaudio %token	ERROR
142ac149fe2Sremi %token	DEPEND ON
143204df0f8Sclaudio %token	<v.string>	STRING
14491d3283aSclaudio %token	<v.number>	NUMBER
14537877ca4Sdlg %type	<v.number>	yesno no optlist optlist_l option demotecount msec
1467afdfd2dSdlg %type	<v.number>	deadtime
147a3f6d01eSclaudio %type	<v.string>	string dependon dependonopt
1486fa28760Sclaudio %type	<v.redist>	redistribute
149cacfc040Sdlg %type	<v.id>		areaid
150204df0f8Sclaudio 
151204df0f8Sclaudio %%
152204df0f8Sclaudio 
153204df0f8Sclaudio grammar		: /* empty */
1544fd4397dSdlg 		| grammar include '\n'
155204df0f8Sclaudio 		| grammar '\n'
156204df0f8Sclaudio 		| grammar conf_main '\n'
157204df0f8Sclaudio 		| grammar varset '\n'
158204df0f8Sclaudio 		| grammar area '\n'
15920741916Sderaadt 		| grammar error '\n'		{ file->errors++; }
160204df0f8Sclaudio 		;
161204df0f8Sclaudio 
1624fd4397dSdlg include		: INCLUDE STRING		{
1634fd4397dSdlg 			struct file	*nfile;
1644fd4397dSdlg 
165a8823310Sdenis 			if ((nfile = pushfile($2,
166a8823310Sdenis 			    !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1674fd4397dSdlg 				yyerror("failed to include file %s", $2);
1684fd4397dSdlg 				free($2);
1694fd4397dSdlg 				YYERROR;
1704fd4397dSdlg 			}
1714fd4397dSdlg 			free($2);
1724fd4397dSdlg 
1734fd4397dSdlg 			file = nfile;
1744fd4397dSdlg 			lungetc('\n');
1754fd4397dSdlg 		}
1764fd4397dSdlg 		;
1774fd4397dSdlg 
178204df0f8Sclaudio string		: string STRING	{
179204df0f8Sclaudio 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
180204df0f8Sclaudio 				free($1);
181204df0f8Sclaudio 				free($2);
182204df0f8Sclaudio 				yyerror("string: asprintf");
183204df0f8Sclaudio 				YYERROR;
184204df0f8Sclaudio 			}
185204df0f8Sclaudio 			free($1);
186204df0f8Sclaudio 			free($2);
187204df0f8Sclaudio 		}
188204df0f8Sclaudio 		| STRING
189204df0f8Sclaudio 		;
190204df0f8Sclaudio 
191619421e7Sclaudio yesno		: YES	{ $$ = 1; }
192619421e7Sclaudio 		| NO	{ $$ = 0; }
193204df0f8Sclaudio 		;
194204df0f8Sclaudio 
195619421e7Sclaudio no		: /* empty */	{ $$ = 0; }
196619421e7Sclaudio 		| NO		{ $$ = 1; }
197bc5f24a9Ssimon 		;
198619421e7Sclaudio 
19937877ca4Sdlg msec		: MSEC NUMBER {
20037877ca4Sdlg 			$$ = $2;
20137877ca4Sdlg 		}
20237877ca4Sdlg 		| NUMBER {
20337877ca4Sdlg 			$$ = $1 * 1000;
20437877ca4Sdlg 		}
20537877ca4Sdlg 		;
20637877ca4Sdlg 
207204df0f8Sclaudio varset		: STRING '=' string		{
2080c7b4ca6Sbenno 			char *s = $1;
209204df0f8Sclaudio 			if (conf->opts & OSPFD_OPT_VERBOSE)
210204df0f8Sclaudio 				printf("%s = \"%s\"\n", $1, $3);
2110c7b4ca6Sbenno 			while (*s++) {
2120c7b4ca6Sbenno 				if (isspace((unsigned char)*s)) {
2130c7b4ca6Sbenno 					yyerror("macro name cannot contain "
2140c7b4ca6Sbenno 					    "whitespace");
21516a0a906Skrw 					free($1);
21616a0a906Skrw 					free($3);
2170c7b4ca6Sbenno 					YYERROR;
2180c7b4ca6Sbenno 				}
2190c7b4ca6Sbenno 			}
220204df0f8Sclaudio 			if (symset($1, $3, 0) == -1)
221204df0f8Sclaudio 				fatal("cannot store variable");
222204df0f8Sclaudio 			free($1);
223204df0f8Sclaudio 			free($3);
224204df0f8Sclaudio 		}
225204df0f8Sclaudio 		;
226204df0f8Sclaudio 
227627c6412Sclaudio conf_main	: ROUTERID STRING {
22882905b67Sflorian 			if (inet_pton(AF_INET, $2, &conf->rtr_id) != 1) {
229204df0f8Sclaudio 				yyerror("error parsing router-id");
230204df0f8Sclaudio 				free($2);
231204df0f8Sclaudio 				YYERROR;
232204df0f8Sclaudio 			}
2331436b306Sclaudio 			free($2);
234204df0f8Sclaudio 		}
2354c260f66Sremi 		| FIBPRIORITY NUMBER {
2364c260f66Sremi 			if ($2 <= RTP_NONE || $2 > RTP_MAX) {
2374c260f66Sremi 				yyerror("invalid fib-priority");
2384c260f66Sremi 				YYERROR;
2394c260f66Sremi 			}
2404c260f66Sremi 			conf->fib_priority = $2;
2414c260f66Sremi 		}
242204df0f8Sclaudio 		| FIBUPDATE yesno {
243204df0f8Sclaudio 			if ($2 == 0)
244204df0f8Sclaudio 				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
245204df0f8Sclaudio 			else
246204df0f8Sclaudio 				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
247204df0f8Sclaudio 		}
2486fa28760Sclaudio 		| redistribute {
2496fa28760Sclaudio 			SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
2506fa28760Sclaudio 			conf->redistribute = 1;
251e2993955Sclaudio 		}
25291d3283aSclaudio 		| RTLABEL STRING EXTTAG NUMBER {
25391d3283aSclaudio 			if ($4 < 0 || $4 > UINT_MAX) {
254fcb4545bSreyk 				yyerror("invalid external route tag");
255fcb4545bSreyk 				free($2);
256fcb4545bSreyk 				YYERROR;
257fcb4545bSreyk 			}
258fcb4545bSreyk 			rtlabel_tag(rtlabel_name2id($2), $4);
259fcb4545bSreyk 			free($2);
260fcb4545bSreyk 		}
261e4caa3d9Sclaudio 		| RDOMAIN NUMBER {
262e4caa3d9Sclaudio 			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
263e4caa3d9Sclaudio 				yyerror("invalid rdomain");
264e4caa3d9Sclaudio 				YYERROR;
265e4caa3d9Sclaudio 			}
266e4caa3d9Sclaudio 			conf->rdomain = $2;
267e4caa3d9Sclaudio 		}
268bbb7cc9cSnorby 		| RFC1583COMPAT yesno {
269bbb7cc9cSnorby 			conf->rfc1583compat = $2;
270bbb7cc9cSnorby 		}
27137877ca4Sdlg 		| SPFDELAY msec {
2723ada9d8fSnorby 			if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
2733ada9d8fSnorby 				yyerror("spf-delay out of range "
2743ada9d8fSnorby 				    "(%d-%d)", MIN_SPF_DELAY,
2753ada9d8fSnorby 				    MAX_SPF_DELAY);
2763ada9d8fSnorby 				YYERROR;
2773ada9d8fSnorby 			}
2783ada9d8fSnorby 			conf->spf_delay = $2;
2793ada9d8fSnorby 		}
28037877ca4Sdlg 		| SPFHOLDTIME msec {
2813ada9d8fSnorby 			if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
2823ada9d8fSnorby 				yyerror("spf-holdtime out of range "
2833ada9d8fSnorby 				    "(%d-%d)", MIN_SPF_HOLDTIME,
2843ada9d8fSnorby 				    MAX_SPF_HOLDTIME);
2853ada9d8fSnorby 				YYERROR;
2863ada9d8fSnorby 			}
2873ada9d8fSnorby 			conf->spf_hold_time = $2;
2883ada9d8fSnorby 		}
2891891964aSclaudio 		| STUB ROUTER yesno {
2901891964aSclaudio 			if ($3)
2911891964aSclaudio 				conf->flags |= OSPFD_FLAG_STUB_ROUTER;
2921891964aSclaudio 			else
2931891964aSclaudio 				/* allow to force non stub mode */
2941891964aSclaudio 				conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
2951891964aSclaudio 		}
296627c6412Sclaudio 		| defaults
297204df0f8Sclaudio 		;
298204df0f8Sclaudio 
2996fa28760Sclaudio 
300a3f6d01eSclaudio redistribute	: no REDISTRIBUTE NUMBER '/' NUMBER optlist dependonopt {
3016fa28760Sclaudio 			struct redistribute	*r;
3026fa28760Sclaudio 
3036fa28760Sclaudio 			if ((r = calloc(1, sizeof(*r))) == NULL)
3046fa28760Sclaudio 				fatal(NULL);
3056fa28760Sclaudio 			r->type = REDIST_ADDR;
3066fa28760Sclaudio 			if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
3076fa28760Sclaudio 				yyerror("bad network: %llu/%llu", $3, $5);
3086fa28760Sclaudio 				free(r);
3096fa28760Sclaudio 				YYERROR;
3106fa28760Sclaudio 			}
3116fa28760Sclaudio 			r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
3126fa28760Sclaudio 			r->mask.s_addr = prefixlen2mask($5);
3136fa28760Sclaudio 
3146fa28760Sclaudio 			if ($1)
3156fa28760Sclaudio 				r->type |= REDIST_NO;
316ad4152efSbenno 			else
317ad4152efSbenno 				conf->redist_label_or_prefix = 1;
3186fa28760Sclaudio 			r->metric = $6;
31902ba2abaSjca 			if ($7)
320ac149fe2Sremi 				strlcpy(r->dependon, $7, sizeof(r->dependon));
32102ba2abaSjca 			else
322ac149fe2Sremi 				r->dependon[0] = '\0';
323ac149fe2Sremi 			free($7);
3246fa28760Sclaudio 			$$ = r;
3256fa28760Sclaudio 		}
326a3f6d01eSclaudio 		| no REDISTRIBUTE STRING optlist dependonopt {
3276fa28760Sclaudio 			struct redistribute	*r;
3286fa28760Sclaudio 
3296fa28760Sclaudio 			if ((r = calloc(1, sizeof(*r))) == NULL)
3306fa28760Sclaudio 				fatal(NULL);
3316fa28760Sclaudio 			if (!strcmp($3, "default"))
3326fa28760Sclaudio 				r->type = REDIST_DEFAULT;
3336fa28760Sclaudio 			else if (!strcmp($3, "static"))
3346fa28760Sclaudio 				r->type = REDIST_STATIC;
3356fa28760Sclaudio 			else if (!strcmp($3, "connected"))
3366fa28760Sclaudio 				r->type = REDIST_CONNECTED;
337ad4152efSbenno 			else if (host($3, &r->addr, &r->mask)) {
3386fa28760Sclaudio 				r->type = REDIST_ADDR;
339ad4152efSbenno 				conf->redist_label_or_prefix = !$1;
340ad4152efSbenno 			} else {
3416fa28760Sclaudio 				yyerror("unknown redistribute type");
3426fa28760Sclaudio 				free($3);
3436fa28760Sclaudio 				free(r);
3446fa28760Sclaudio 				YYERROR;
3456fa28760Sclaudio 			}
3466fa28760Sclaudio 
3476fa28760Sclaudio 			if ($1)
3486fa28760Sclaudio 				r->type |= REDIST_NO;
3496fa28760Sclaudio 			r->metric = $4;
35002ba2abaSjca 			if ($5)
351ac149fe2Sremi 				strlcpy(r->dependon, $5, sizeof(r->dependon));
35202ba2abaSjca 			else
353ac149fe2Sremi 				r->dependon[0] = '\0';
3546fa28760Sclaudio 			free($3);
355ac149fe2Sremi 			free($5);
3566fa28760Sclaudio 			$$ = r;
3576fa28760Sclaudio 		}
358c36a82f5Sdlg 		| no REDISTRIBUTE RTLABEL STRING optlist dependonopt {
3596fa28760Sclaudio 			struct redistribute	*r;
3606fa28760Sclaudio 
3616fa28760Sclaudio 			if ((r = calloc(1, sizeof(*r))) == NULL)
3626fa28760Sclaudio 				fatal(NULL);
3636fa28760Sclaudio 			r->type = REDIST_LABEL;
3646fa28760Sclaudio 			r->label = rtlabel_name2id($4);
3656fa28760Sclaudio 			if ($1)
3666fa28760Sclaudio 				r->type |= REDIST_NO;
367ad4152efSbenno 			else
368ad4152efSbenno 				conf->redist_label_or_prefix = 1;
3696fa28760Sclaudio 			r->metric = $5;
370ac149fe2Sremi 			if ($6)
371ac149fe2Sremi 				strlcpy(r->dependon, $6, sizeof(r->dependon));
372ac149fe2Sremi 			else
373ac149fe2Sremi 				r->dependon[0] = '\0';
3746fa28760Sclaudio 			free($4);
375ac149fe2Sremi 			free($6);
3766fa28760Sclaudio 			$$ = r;
3776fa28760Sclaudio 		}
3786fa28760Sclaudio 		;
3796fa28760Sclaudio 
380f373ed5aSclaudio optlist		: /* empty */ 			{ $$ = DEFAULT_REDIST_METRIC; }
381a5443f34Sclaudio 		| SET option 			{
382a5443f34Sclaudio 			$$ = $2;
383a5443f34Sclaudio 			if (($$ & LSA_METRIC_MASK) == 0)
384a5443f34Sclaudio 				$$ |= DEFAULT_REDIST_METRIC;
385a5443f34Sclaudio 		}
386a5443f34Sclaudio 		| SET optnl '{' optnl optlist_l optnl '}' {
387a5443f34Sclaudio 			$$ = $5;
388a5443f34Sclaudio 			if (($$ & LSA_METRIC_MASK) == 0)
389a5443f34Sclaudio 				$$ |= DEFAULT_REDIST_METRIC;
390a5443f34Sclaudio 		}
391f373ed5aSclaudio 		;
392f373ed5aSclaudio 
393f373ed5aSclaudio optlist_l	: optlist_l comma option {
394f373ed5aSclaudio 			if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
395f373ed5aSclaudio 				yyerror("redistribute type already defined");
396f373ed5aSclaudio 				YYERROR;
397f373ed5aSclaudio 			}
398f373ed5aSclaudio 			if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
3991e96e0a1Smichele 				yyerror("redistribute metric already defined");
400f373ed5aSclaudio 				YYERROR;
401f373ed5aSclaudio 			}
402f373ed5aSclaudio 			$$ = $1 | $3;
403f373ed5aSclaudio 		}
404f373ed5aSclaudio 		| option { $$ = $1; }
405f373ed5aSclaudio 		;
406f373ed5aSclaudio 
40791d3283aSclaudio option		: METRIC NUMBER {
408f373ed5aSclaudio 			if ($2 == 0 || $2 > MAX_METRIC) {
409f373ed5aSclaudio 				yyerror("invalid redistribute metric");
410f373ed5aSclaudio 				YYERROR;
411f373ed5aSclaudio 			}
412f373ed5aSclaudio 			$$ = $2;
413f373ed5aSclaudio 		}
41491d3283aSclaudio 		| TYPE NUMBER {
415f373ed5aSclaudio 			switch ($2) {
416f373ed5aSclaudio 			case 1:
417f373ed5aSclaudio 				$$ = 0;
418f373ed5aSclaudio 				break;
419f373ed5aSclaudio 			case 2:
420f373ed5aSclaudio 				$$ = LSA_ASEXT_E_FLAG;
421f373ed5aSclaudio 				break;
422f373ed5aSclaudio 			default:
42391d3283aSclaudio 				yyerror("only external type 1 and 2 allowed");
424f373ed5aSclaudio 				YYERROR;
425f373ed5aSclaudio 			}
426f373ed5aSclaudio 		}
427f373ed5aSclaudio 		;
428f373ed5aSclaudio 
429a3f6d01eSclaudio dependonopt	: /* empty */		{ $$ = NULL; }
430a3f6d01eSclaudio 		| dependon
431a3f6d01eSclaudio 
432a3f6d01eSclaudio dependon	: DEPEND ON STRING	{
433ac149fe2Sremi 			struct in_addr	 addr;
434ac149fe2Sremi 			struct kif	*kif;
435ac149fe2Sremi 
436ac149fe2Sremi 			if (strlen($3) >= IFNAMSIZ) {
437ac149fe2Sremi 				yyerror("interface name %s too long", $3);
438ac149fe2Sremi 				free($3);
439ac149fe2Sremi 				YYERROR;
440ac149fe2Sremi 			}
441ac149fe2Sremi 			bzero(&addr, sizeof(addr));
442ac149fe2Sremi 			if ((kif = kif_findname($3, addr, NULL)) == NULL) {
443ac149fe2Sremi 				yyerror("unknown interface %s", $3);
444ac149fe2Sremi 				free($3);
445ac149fe2Sremi 				YYERROR;
446ac149fe2Sremi 			}
447ac149fe2Sremi 			$$ = $3;
448ac149fe2Sremi 		}
449ac149fe2Sremi 		;
450ac149fe2Sremi 
45191d3283aSclaudio authmd		: AUTHMD NUMBER STRING {
45203431b74Snorby 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
453209c181bSstevesk 				yyerror("auth-md key-id out of range "
45403431b74Snorby 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
45503431b74Snorby 				free($3);
45603431b74Snorby 				YYERROR;
45703431b74Snorby 			}
458eee4aafbSnorby 			if (strlen($3) > MD5_DIGEST_LENGTH) {
459209c181bSstevesk 				yyerror("auth-md key length out of range "
460eee4aafbSnorby 				    "(max length %d)",
461eee4aafbSnorby 				    MD5_DIGEST_LENGTH);
462eee4aafbSnorby 				free($3);
463eee4aafbSnorby 				YYERROR;
464eee4aafbSnorby 			}
46576b51f83Sclaudio 			md_list_add(&defs->md_list, $2, $3);
46603431b74Snorby 			free($3);
46703431b74Snorby 		}
46803431b74Snorby 
46991d3283aSclaudio authmdkeyid	: AUTHMDKEYID NUMBER {
47003431b74Snorby 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
471209c181bSstevesk 				yyerror("auth-md-keyid out of range "
47203431b74Snorby 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
47303431b74Snorby 				YYERROR;
47403431b74Snorby 			}
47576b51f83Sclaudio 			defs->auth_keyid = $2;
47603431b74Snorby 		}
47703431b74Snorby 
478204df0f8Sclaudio authtype	: AUTHTYPE STRING {
479204df0f8Sclaudio 			enum auth_type	type;
480204df0f8Sclaudio 
481204df0f8Sclaudio 			if (!strcmp($2, "none"))
482204df0f8Sclaudio 				type = AUTH_NONE;
483204df0f8Sclaudio 			else if (!strcmp($2, "simple"))
484204df0f8Sclaudio 				type = AUTH_SIMPLE;
485204df0f8Sclaudio 			else if (!strcmp($2, "crypt"))
48603431b74Snorby 				type = AUTH_CRYPT;
487204df0f8Sclaudio 			else {
488204df0f8Sclaudio 				yyerror("unknown auth-type");
489204df0f8Sclaudio 				free($2);
490204df0f8Sclaudio 				YYERROR;
491204df0f8Sclaudio 			}
492204df0f8Sclaudio 			free($2);
49376b51f83Sclaudio 			defs->auth_type = type;
494204df0f8Sclaudio 		}
495204df0f8Sclaudio 		;
496204df0f8Sclaudio 
497204df0f8Sclaudio authkey		: AUTHKEY STRING {
498eee4aafbSnorby 			if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
499d79d6d90Sclaudio 				yyerror("auth-key too long (max length %d)",
500d79d6d90Sclaudio 				    MAX_SIMPLE_AUTH_LEN);
501eee4aafbSnorby 					free($2);
502eee4aafbSnorby 					YYERROR;
503eee4aafbSnorby 			}
50476b51f83Sclaudio 			strncpy(defs->auth_key, $2,
50576b51f83Sclaudio 			    sizeof(defs->auth_key));
5061436b306Sclaudio 			free($2);
507204df0f8Sclaudio 		}
508204df0f8Sclaudio 		;
509204df0f8Sclaudio 
51091d3283aSclaudio defaults	: METRIC NUMBER {
511627c6412Sclaudio 			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
512627c6412Sclaudio 				yyerror("metric out of range (%d-%d)",
513627c6412Sclaudio 				    MIN_METRIC, MAX_METRIC);
514627c6412Sclaudio 				YYERROR;
515627c6412Sclaudio 			}
516627c6412Sclaudio 			defs->metric = $2;
517627c6412Sclaudio 		}
51891d3283aSclaudio 		| ROUTERPRIORITY NUMBER {
519627c6412Sclaudio 			if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
520627c6412Sclaudio 				yyerror("router-priority out of range (%d-%d)",
521627c6412Sclaudio 				    MIN_PRIORITY, MAX_PRIORITY);
522627c6412Sclaudio 				YYERROR;
523627c6412Sclaudio 			}
524627c6412Sclaudio 			defs->priority = $2;
525627c6412Sclaudio 		}
5267afdfd2dSdlg 		| ROUTERDEADTIME deadtime {
527627c6412Sclaudio 			defs->dead_interval = $2;
528627c6412Sclaudio 		}
52991d3283aSclaudio 		| TRANSMITDELAY NUMBER {
530627c6412Sclaudio 			if ($2 < MIN_TRANSMIT_DELAY ||
531627c6412Sclaudio 			    $2 > MAX_TRANSMIT_DELAY) {
532627c6412Sclaudio 				yyerror("transmit-delay out of range (%d-%d)",
533627c6412Sclaudio 				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
534627c6412Sclaudio 				YYERROR;
535627c6412Sclaudio 			}
536627c6412Sclaudio 			defs->transmit_delay = $2;
537627c6412Sclaudio 		}
53891d3283aSclaudio 		| HELLOINTERVAL NUMBER {
539627c6412Sclaudio 			if ($2 < MIN_HELLO_INTERVAL ||
540627c6412Sclaudio 			    $2 > MAX_HELLO_INTERVAL) {
541627c6412Sclaudio 				yyerror("hello-interval out of range (%d-%d)",
542627c6412Sclaudio 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
543627c6412Sclaudio 				YYERROR;
544627c6412Sclaudio 			}
545627c6412Sclaudio 			defs->hello_interval = $2;
546627c6412Sclaudio 		}
5477afdfd2dSdlg 		| FASTHELLOINTERVAL MSEC NUMBER {
5487afdfd2dSdlg 			if ($3 < MIN_FAST_INTERVAL ||
5497afdfd2dSdlg 			    $3 > MAX_FAST_INTERVAL) {
5507afdfd2dSdlg 				yyerror("fast-hello-interval msec out of "
5517afdfd2dSdlg 				    "range (%d-%d)", MIN_FAST_INTERVAL,
5527afdfd2dSdlg 				    MAX_FAST_INTERVAL);
5537afdfd2dSdlg 				YYERROR;
5547afdfd2dSdlg 			}
5557afdfd2dSdlg 			defs->fast_hello_interval = $3;
5567afdfd2dSdlg 		}
55791d3283aSclaudio 		| RETRANSMITINTERVAL NUMBER {
558627c6412Sclaudio 			if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
559627c6412Sclaudio 				yyerror("retransmit-interval out of range "
560627c6412Sclaudio 				    "(%d-%d)", MIN_RXMT_INTERVAL,
561627c6412Sclaudio 				    MAX_RXMT_INTERVAL);
562627c6412Sclaudio 				YYERROR;
563627c6412Sclaudio 			}
564627c6412Sclaudio 			defs->rxmt_interval = $2;
565627c6412Sclaudio 		}
56609e8f780Sremi 		| TYPE P2P		{
56709e8f780Sremi 			defs->p2p = 1;
56809e8f780Sremi 		}
56976b51f83Sclaudio 		| authtype
57076b51f83Sclaudio 		| authkey
57176b51f83Sclaudio 		| authmdkeyid
57276b51f83Sclaudio 		| authmd
57376b51f83Sclaudio 		;
574627c6412Sclaudio 
5757afdfd2dSdlg deadtime	: NUMBER {
5767afdfd2dSdlg 			if ($1 < MIN_RTR_DEAD_TIME || $1 > MAX_RTR_DEAD_TIME) {
5777afdfd2dSdlg 				yyerror("router-dead-time out of range (%d-%d)",
5787afdfd2dSdlg 				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
5797afdfd2dSdlg 				YYERROR;
5807afdfd2dSdlg 			}
5817afdfd2dSdlg 			$$ = $1;
5827afdfd2dSdlg 		}
5837afdfd2dSdlg 		| MINIMAL {
5847afdfd2dSdlg 			$$ = FAST_RTR_DEAD_TIME;
5857afdfd2dSdlg 		}
5867afdfd2dSdlg 
587204df0f8Sclaudio optnl		: '\n' optnl
588204df0f8Sclaudio 		|
589204df0f8Sclaudio 		;
590204df0f8Sclaudio 
591204df0f8Sclaudio nl		: '\n' optnl		/* one newline or more */
592204df0f8Sclaudio 		;
593204df0f8Sclaudio 
594f373ed5aSclaudio comma		: ','
595f373ed5aSclaudio 		| /*empty*/
596f373ed5aSclaudio 		;
597f373ed5aSclaudio 
598cacfc040Sdlg area		: AREA areaid {
599cacfc040Sdlg 			area = conf_get_area($2);
600627c6412Sclaudio 
601627c6412Sclaudio 			memcpy(&areadefs, defs, sizeof(areadefs));
60276b51f83Sclaudio 			md_list_copy(&areadefs.md_list, &defs->md_list);
603627c6412Sclaudio 			defs = &areadefs;
604a3f6d01eSclaudio 		} '{' optnl areaopts_l optnl '}' {
605204df0f8Sclaudio 			area = NULL;
60676b51f83Sclaudio 			md_list_clr(&defs->md_list);
607627c6412Sclaudio 			defs = &globaldefs;
608204df0f8Sclaudio 		}
609204df0f8Sclaudio 		;
610204df0f8Sclaudio 
61191d3283aSclaudio demotecount	: NUMBER	{ $$ = $1; }
612a36153efSpyr 		| /*empty*/	{ $$ = 1; }
613a36153efSpyr 		;
614a36153efSpyr 
615cacfc040Sdlg areaid		: NUMBER {
616cacfc040Sdlg 			if ($1 < 0 || $1 > 0xffffffff) {
617cacfc040Sdlg 				yyerror("invalid area id");
618cacfc040Sdlg 				YYERROR;
619cacfc040Sdlg 			}
620cacfc040Sdlg 			$$.s_addr = htonl($1);
621cacfc040Sdlg 		}
622cacfc040Sdlg 		| STRING {
62382905b67Sflorian 			if (inet_pton(AF_INET, $1, &$$) != 1) {
624cacfc040Sdlg 				yyerror("error parsing area");
625cacfc040Sdlg 				free($1);
626cacfc040Sdlg 				YYERROR;
627cacfc040Sdlg 			}
628cacfc040Sdlg 			free($1);
629cacfc040Sdlg 		}
630cacfc040Sdlg 		;
631cacfc040Sdlg 
632a3f6d01eSclaudio areaopts_l	: areaopts_l nl areaoptsl
633a3f6d01eSclaudio 		| areaoptsl
634204df0f8Sclaudio 		;
635204df0f8Sclaudio 
6368785114bSclaudio areaoptsl	: interface
637a36153efSpyr 		| DEMOTE STRING	demotecount {
63891d3283aSclaudio 			if ($3 < 1 || $3 > 255) {
63991d3283aSclaudio 				yyerror("demote count out of range (1-255)");
640fba2d3d0Sclaudio 				free($2);
641fba2d3d0Sclaudio 				YYERROR;
642fba2d3d0Sclaudio 			}
643fba2d3d0Sclaudio 			area->demote_level = $3;
644fba2d3d0Sclaudio 			if (strlcpy(area->demote_group, $2,
645fba2d3d0Sclaudio 			    sizeof(area->demote_group)) >=
646fba2d3d0Sclaudio 			    sizeof(area->demote_group)) {
6479c81ce9fSdoug 				yyerror("demote group name \"%s\" too long",
6489c81ce9fSdoug 				    $2);
649fba2d3d0Sclaudio 				free($2);
650fba2d3d0Sclaudio 				YYERROR;
651fba2d3d0Sclaudio 			}
652fba2d3d0Sclaudio 			free($2);
653fba2d3d0Sclaudio 			if (carp_demote_init(area->demote_group,
654fba2d3d0Sclaudio 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
655fba2d3d0Sclaudio 				yyerror("error initializing group \"%s\"",
656fba2d3d0Sclaudio 				    area->demote_group);
657fba2d3d0Sclaudio 				YYERROR;
658fba2d3d0Sclaudio 			}
659fba2d3d0Sclaudio 		}
6608785114bSclaudio 		| defaults
66198b447a7Sclaudio 		| STUB 			{ area->stub = 1; }
6626fa28760Sclaudio 		| STUB redistribute {
6636fa28760Sclaudio 			area->stub = 1;
6646fa28760Sclaudio 			if ($2->type != REDIST_DEFAULT) {
6656fa28760Sclaudio 				yyerror("bad redistribute option");
6666fa28760Sclaudio 				YYERROR;
6676fa28760Sclaudio 			}
6686fa28760Sclaudio 			if (!SIMPLEQ_EMPTY(&area->redist_list)) {
6696fa28760Sclaudio 				yyerror("area redistribute option only "
6706fa28760Sclaudio 				    "allowed once");
6716fa28760Sclaudio 				YYERROR;
6726fa28760Sclaudio 			}
6736fa28760Sclaudio 			SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
6746fa28760Sclaudio 		}
675204df0f8Sclaudio 		;
676204df0f8Sclaudio 
677204df0f8Sclaudio interface	: INTERFACE STRING	{
678e9fa2173Sclaudio 			struct kif	*kif;
67966dd3991Sclaudio 			struct kif_addr	*ka = NULL;
68066dd3991Sclaudio 			char		*s;
68166dd3991Sclaudio 			struct in_addr	 addr;
682204df0f8Sclaudio 
68366dd3991Sclaudio 			s = strchr($2, ':');
68466dd3991Sclaudio 			if (s) {
68566dd3991Sclaudio 				*s++ = '\0';
68682905b67Sflorian 				if (inet_pton(AF_INET, s, &addr) != 1) {
68766dd3991Sclaudio 					yyerror(
68866dd3991Sclaudio 					    "error parsing interface address");
68966dd3991Sclaudio 					free($2);
69066dd3991Sclaudio 					YYERROR;
69166dd3991Sclaudio 				}
69266dd3991Sclaudio 			} else
69366dd3991Sclaudio 				addr.s_addr = 0;
69466dd3991Sclaudio 
69566dd3991Sclaudio 			if ((kif = kif_findname($2, addr, &ka)) == NULL) {
696204df0f8Sclaudio 				yyerror("unknown interface %s", $2);
697204df0f8Sclaudio 				free($2);
698204df0f8Sclaudio 				YYERROR;
699204df0f8Sclaudio 			}
70066dd3991Sclaudio 			if (ka == NULL) {
70166dd3991Sclaudio 				if (s)
70266dd3991Sclaudio 					yyerror("address %s not configured on "
70366dd3991Sclaudio 					    "interface %s", s, $2);
70466dd3991Sclaudio 				else
70566dd3991Sclaudio 					yyerror("unnumbered interface %s", $2);
706204df0f8Sclaudio 				free($2);
70766dd3991Sclaudio 				YYERROR;
70866dd3991Sclaudio 			}
70966dd3991Sclaudio 			free($2);
71066dd3991Sclaudio 			iface = conf_get_if(kif, ka);
711204df0f8Sclaudio 			if (iface == NULL)
712204df0f8Sclaudio 				YYERROR;
713204df0f8Sclaudio 			iface->area = area;
714ecd183dbSclaudio 			LIST_INSERT_HEAD(&area->iface_list, iface, entry);
715627c6412Sclaudio 
716627c6412Sclaudio 			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
71776b51f83Sclaudio 			md_list_copy(&ifacedefs.md_list, &defs->md_list);
718627c6412Sclaudio 			defs = &ifacedefs;
7193d7c1a39Sclaudio 		} interface_block {
720627c6412Sclaudio 			iface->dead_interval = defs->dead_interval;
7217afdfd2dSdlg 			iface->fast_hello_interval = defs->fast_hello_interval;
722627c6412Sclaudio 			iface->transmit_delay = defs->transmit_delay;
7237afdfd2dSdlg 			if (iface->dead_interval == FAST_RTR_DEAD_TIME)
7247afdfd2dSdlg 				iface->hello_interval = 0;
7257afdfd2dSdlg 			else
726627c6412Sclaudio 				iface->hello_interval = defs->hello_interval;
727627c6412Sclaudio 			iface->rxmt_interval = defs->rxmt_interval;
728627c6412Sclaudio 			iface->metric = defs->metric;
729627c6412Sclaudio 			iface->priority = defs->priority;
73076b51f83Sclaudio 			iface->auth_type = defs->auth_type;
73176b51f83Sclaudio 			iface->auth_keyid = defs->auth_keyid;
73209e8f780Sremi 			if (defs->p2p == 1)
73309e8f780Sremi 				iface->type = IF_TYPE_POINTOPOINT;
73476b51f83Sclaudio 			memcpy(iface->auth_key, defs->auth_key,
73576b51f83Sclaudio 			    sizeof(iface->auth_key));
73676b51f83Sclaudio 			md_list_copy(&iface->auth_md_list, &defs->md_list);
73776b51f83Sclaudio 			md_list_clr(&defs->md_list);
738204df0f8Sclaudio 			iface = NULL;
739627c6412Sclaudio 			/* interface is always part of an area */
740627c6412Sclaudio 			defs = &areadefs;
741204df0f8Sclaudio 		}
742204df0f8Sclaudio 		;
743204df0f8Sclaudio 
744a3f6d01eSclaudio interface_block	: '{' optnl interfaceopts_l optnl '}'
745d4cfe42aSclaudio 		| '{' optnl '}'
746a3f6d01eSclaudio 		| /* empty */
7473d7c1a39Sclaudio 		;
7483d7c1a39Sclaudio 
749a3f6d01eSclaudio interfaceopts_l	: interfaceopts_l nl interfaceoptsl
750a3f6d01eSclaudio 		| interfaceoptsl
751204df0f8Sclaudio 		;
752204df0f8Sclaudio 
7538785114bSclaudio interfaceoptsl	: PASSIVE		{ iface->passive = 1; }
754fba2d3d0Sclaudio 		| DEMOTE STRING		{
755fba2d3d0Sclaudio 			if (strlcpy(iface->demote_group, $2,
756fba2d3d0Sclaudio 			    sizeof(iface->demote_group)) >=
757fba2d3d0Sclaudio 			    sizeof(iface->demote_group)) {
7589c81ce9fSdoug 				yyerror("demote group name \"%s\" too long",
7599c81ce9fSdoug 				    $2);
760fba2d3d0Sclaudio 				free($2);
761fba2d3d0Sclaudio 				YYERROR;
762fba2d3d0Sclaudio 			}
763fba2d3d0Sclaudio 			free($2);
764fba2d3d0Sclaudio 			if (carp_demote_init(iface->demote_group,
765fba2d3d0Sclaudio 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
766fba2d3d0Sclaudio 				yyerror("error initializing group \"%s\"",
767fba2d3d0Sclaudio 				    iface->demote_group);
768fba2d3d0Sclaudio 				YYERROR;
769fba2d3d0Sclaudio 			}
770fba2d3d0Sclaudio 		}
771ac149fe2Sremi 		| dependon {
772ac149fe2Sremi 			struct in_addr	 addr;
773ac149fe2Sremi 			struct kif	*kif;
774ac149fe2Sremi 
775ac149fe2Sremi 			if ($1) {
776ac149fe2Sremi 				strlcpy(iface->dependon, $1,
777ac149fe2Sremi 				       	sizeof(iface->dependon));
778ac149fe2Sremi 				bzero(&addr, sizeof(addr));
779ac149fe2Sremi 				kif = kif_findname($1, addr, NULL);
780ac149fe2Sremi 				iface->depend_ok = ifstate_is_up(kif);
781ac149fe2Sremi 			} else {
782ac149fe2Sremi 				iface->dependon[0] = '\0';
783ac149fe2Sremi 				iface->depend_ok = 1;
784ac149fe2Sremi 			}
785ac149fe2Sremi 
786ac149fe2Sremi 			free($1);
787ac149fe2Sremi 		}
7888785114bSclaudio 		| defaults
789204df0f8Sclaudio 		;
790204df0f8Sclaudio 
791204df0f8Sclaudio %%
792204df0f8Sclaudio 
793204df0f8Sclaudio struct keywords {
794204df0f8Sclaudio 	const char	*k_name;
795204df0f8Sclaudio 	int		 k_val;
796204df0f8Sclaudio };
797204df0f8Sclaudio 
798204df0f8Sclaudio int
799204df0f8Sclaudio yyerror(const char *fmt, ...)
800204df0f8Sclaudio {
801204df0f8Sclaudio 	va_list		 ap;
802d1fe7d6dSbluhm 	char		*msg;
803204df0f8Sclaudio 
80420741916Sderaadt 	file->errors++;
805204df0f8Sclaudio 	va_start(ap, fmt);
806d1fe7d6dSbluhm 	if (vasprintf(&msg, fmt, ap) == -1)
807d1fe7d6dSbluhm 		fatalx("yyerror vasprintf");
808204df0f8Sclaudio 	va_end(ap);
809d1fe7d6dSbluhm 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
810d1fe7d6dSbluhm 	free(msg);
811204df0f8Sclaudio 	return (0);
812204df0f8Sclaudio }
813204df0f8Sclaudio 
814204df0f8Sclaudio int
815204df0f8Sclaudio kw_cmp(const void *k, const void *e)
816204df0f8Sclaudio {
817204df0f8Sclaudio 	return (strcmp(k, ((const struct keywords *)e)->k_name));
818204df0f8Sclaudio }
819204df0f8Sclaudio 
820204df0f8Sclaudio int
821204df0f8Sclaudio lookup(char *s)
822204df0f8Sclaudio {
823204df0f8Sclaudio 	/* this has to be sorted always */
824204df0f8Sclaudio 	static const struct keywords keywords[] = {
825204df0f8Sclaudio 		{"area",		AREA},
826204df0f8Sclaudio 		{"auth-key",		AUTHKEY},
82703431b74Snorby 		{"auth-md",		AUTHMD},
82803431b74Snorby 		{"auth-md-keyid",	AUTHMDKEYID},
829204df0f8Sclaudio 		{"auth-type",		AUTHTYPE},
830fba2d3d0Sclaudio 		{"demote",		DEMOTE},
831ac149fe2Sremi 		{"depend",		DEPEND},
832fcb4545bSreyk 		{"external-tag",	EXTTAG},
8337afdfd2dSdlg 		{"fast-hello-interval",	FASTHELLOINTERVAL},
8344c260f66Sremi 		{"fib-priority",	FIBPRIORITY},
8358ffc8f84Sgollo 		{"fib-update",		FIBUPDATE},
836204df0f8Sclaudio 		{"hello-interval",	HELLOINTERVAL},
8374fd4397dSdlg 		{"include",		INCLUDE},
838204df0f8Sclaudio 		{"interface",		INTERFACE},
839204df0f8Sclaudio 		{"metric",		METRIC},
8407afdfd2dSdlg 		{"minimal",		MINIMAL},
84137877ca4Sdlg 		{"msec",		MSEC},
842619421e7Sclaudio 		{"no",			NO},
843ac149fe2Sremi 		{"on",			ON},
844ef209401Sremi 		{"p2p",			P2P},
845204df0f8Sclaudio 		{"passive",		PASSIVE},
846e4caa3d9Sclaudio 		{"rdomain",		RDOMAIN},
847e2993955Sclaudio 		{"redistribute",	REDISTRIBUTE},
848204df0f8Sclaudio 		{"retransmit-interval",	RETRANSMITINTERVAL},
849bbb7cc9cSnorby 		{"rfc1583compat",	RFC1583COMPAT},
8501891964aSclaudio 		{"router",		ROUTER},
851dacb568dSclaudio 		{"router-dead-time",	ROUTERDEADTIME},
852204df0f8Sclaudio 		{"router-id",		ROUTERID},
853204df0f8Sclaudio 		{"router-priority",	ROUTERPRIORITY},
854bbb232d2Sclaudio 		{"rtlabel",		RTLABEL},
855f373ed5aSclaudio 		{"set",			SET},
8563ada9d8fSnorby 		{"spf-delay",		SPFDELAY},
8573ada9d8fSnorby 		{"spf-holdtime",	SPFHOLDTIME},
8581891964aSclaudio 		{"stub",		STUB},
859619421e7Sclaudio 		{"transmit-delay",	TRANSMITDELAY},
860f373ed5aSclaudio 		{"type",		TYPE},
861619421e7Sclaudio 		{"yes",			YES}
862204df0f8Sclaudio 	};
863204df0f8Sclaudio 	const struct keywords	*p;
864204df0f8Sclaudio 
865204df0f8Sclaudio 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
866204df0f8Sclaudio 	    sizeof(keywords[0]), kw_cmp);
867204df0f8Sclaudio 
86874c23245Sclaudio 	if (p)
869204df0f8Sclaudio 		return (p->k_val);
87074c23245Sclaudio 	else
871204df0f8Sclaudio 		return (STRING);
872204df0f8Sclaudio }
873204df0f8Sclaudio 
874a8823310Sdenis #define START_EXPAND	1
875a8823310Sdenis #define DONE_EXPAND	2
876204df0f8Sclaudio 
877a8823310Sdenis static int	expanding;
878a8823310Sdenis 
879a8823310Sdenis int
880a8823310Sdenis igetc(void)
881a8823310Sdenis {
882a8823310Sdenis 	int	c;
883a8823310Sdenis 
884a8823310Sdenis 	while (1) {
885a8823310Sdenis 		if (file->ungetpos > 0)
886a8823310Sdenis 			c = file->ungetbuf[--file->ungetpos];
887a8823310Sdenis 		else
888a8823310Sdenis 			c = getc(file->stream);
889a8823310Sdenis 
890a8823310Sdenis 		if (c == START_EXPAND)
891a8823310Sdenis 			expanding = 1;
892a8823310Sdenis 		else if (c == DONE_EXPAND)
893a8823310Sdenis 			expanding = 0;
894a8823310Sdenis 		else
895a8823310Sdenis 			break;
896a8823310Sdenis 	}
897a8823310Sdenis 	return (c);
898a8823310Sdenis }
899204df0f8Sclaudio 
900204df0f8Sclaudio int
90120741916Sderaadt lgetc(int quotec)
902204df0f8Sclaudio {
903204df0f8Sclaudio 	int		c, next;
904204df0f8Sclaudio 
90520741916Sderaadt 	if (quotec) {
906a8823310Sdenis 		if ((c = igetc()) == EOF) {
907c6004ab9Smpf 			yyerror("reached end of file while parsing "
908c6004ab9Smpf 			    "quoted string");
909c6004ab9Smpf 			if (file == topfile || popfile() == EOF)
91020741916Sderaadt 				return (EOF);
91120741916Sderaadt 			return (quotec);
91220741916Sderaadt 		}
913d5d66eaeSderaadt 		return (c);
914d5d66eaeSderaadt 	}
915d5d66eaeSderaadt 
916a8823310Sdenis 	while ((c = igetc()) == '\\') {
917a8823310Sdenis 		next = igetc();
918204df0f8Sclaudio 		if (next != '\n') {
919e3bfd77aSderaadt 			c = next;
920204df0f8Sclaudio 			break;
921204df0f8Sclaudio 		}
92220741916Sderaadt 		yylval.lineno = file->lineno;
92320741916Sderaadt 		file->lineno++;
924204df0f8Sclaudio 	}
925204df0f8Sclaudio 
926a8823310Sdenis 	if (c == EOF) {
927a8823310Sdenis 		/*
928a8823310Sdenis 		 * Fake EOL when hit EOF for the first time. This gets line
929a8823310Sdenis 		 * count right if last line in included file is syntactically
930a8823310Sdenis 		 * invalid and has no newline.
931a8823310Sdenis 		 */
932a8823310Sdenis 		if (file->eof_reached == 0) {
933a8823310Sdenis 			file->eof_reached = 1;
934a8823310Sdenis 			return ('\n');
935a8823310Sdenis 		}
93620741916Sderaadt 		while (c == EOF) {
937c6004ab9Smpf 			if (file == topfile || popfile() == EOF)
93820741916Sderaadt 				return (EOF);
939a8823310Sdenis 			c = igetc();
940a8823310Sdenis 		}
94120741916Sderaadt 	}
942204df0f8Sclaudio 	return (c);
943204df0f8Sclaudio }
944204df0f8Sclaudio 
945a8823310Sdenis void
946204df0f8Sclaudio lungetc(int c)
947204df0f8Sclaudio {
948204df0f8Sclaudio 	if (c == EOF)
949a8823310Sdenis 		return;
950a8823310Sdenis 
951a8823310Sdenis 	if (file->ungetpos >= file->ungetsize) {
952a8823310Sdenis 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
953a8823310Sdenis 		if (p == NULL)
954a062aa9dSkrw 			err(1, "%s", __func__);
955a8823310Sdenis 		file->ungetbuf = p;
956a8823310Sdenis 		file->ungetsize *= 2;
957204df0f8Sclaudio 	}
958a8823310Sdenis 	file->ungetbuf[file->ungetpos++] = c;
959204df0f8Sclaudio }
960204df0f8Sclaudio 
961204df0f8Sclaudio int
962204df0f8Sclaudio findeol(void)
963204df0f8Sclaudio {
964204df0f8Sclaudio 	int	c;
965204df0f8Sclaudio 
966204df0f8Sclaudio 	/* skip to either EOF or the first real EOL */
967204df0f8Sclaudio 	while (1) {
968d5d66eaeSderaadt 		c = lgetc(0);
969204df0f8Sclaudio 		if (c == '\n') {
97020741916Sderaadt 			file->lineno++;
971204df0f8Sclaudio 			break;
972204df0f8Sclaudio 		}
973204df0f8Sclaudio 		if (c == EOF)
974204df0f8Sclaudio 			break;
975204df0f8Sclaudio 	}
976204df0f8Sclaudio 	return (ERROR);
977204df0f8Sclaudio }
978204df0f8Sclaudio 
979204df0f8Sclaudio int
980204df0f8Sclaudio yylex(void)
981204df0f8Sclaudio {
98208f6ba19Snaddy 	char	 buf[8096];
98308f6ba19Snaddy 	char	*p, *val;
98420741916Sderaadt 	int	 quotec, next, c;
985204df0f8Sclaudio 	int	 token;
986204df0f8Sclaudio 
987204df0f8Sclaudio top:
988204df0f8Sclaudio 	p = buf;
9892053f12aSmpf 	while ((c = lgetc(0)) == ' ' || c == '\t')
990204df0f8Sclaudio 		; /* nothing */
991204df0f8Sclaudio 
99220741916Sderaadt 	yylval.lineno = file->lineno;
993204df0f8Sclaudio 	if (c == '#')
994d5d66eaeSderaadt 		while ((c = lgetc(0)) != '\n' && c != EOF)
995204df0f8Sclaudio 			; /* nothing */
996a8823310Sdenis 	if (c == '$' && !expanding) {
997204df0f8Sclaudio 		while (1) {
998d5d66eaeSderaadt 			if ((c = lgetc(0)) == EOF)
999204df0f8Sclaudio 				return (0);
1000204df0f8Sclaudio 
1001204df0f8Sclaudio 			if (p + 1 >= buf + sizeof(buf) - 1) {
1002204df0f8Sclaudio 				yyerror("string too long");
1003204df0f8Sclaudio 				return (findeol());
1004204df0f8Sclaudio 			}
1005204df0f8Sclaudio 			if (isalnum(c) || c == '_') {
1006015d7b4dSbenno 				*p++ = c;
1007204df0f8Sclaudio 				continue;
1008204df0f8Sclaudio 			}
1009204df0f8Sclaudio 			*p = '\0';
1010204df0f8Sclaudio 			lungetc(c);
1011204df0f8Sclaudio 			break;
1012204df0f8Sclaudio 		}
1013204df0f8Sclaudio 		val = symget(buf);
1014204df0f8Sclaudio 		if (val == NULL) {
1015204df0f8Sclaudio 			yyerror("macro '%s' not defined", buf);
1016204df0f8Sclaudio 			return (findeol());
1017204df0f8Sclaudio 		}
1018a8823310Sdenis 		p = val + strlen(val) - 1;
1019a8823310Sdenis 		lungetc(DONE_EXPAND);
1020a8823310Sdenis 		while (p >= val) {
102108f6ba19Snaddy 			lungetc((unsigned char)*p);
1022a8823310Sdenis 			p--;
1023a8823310Sdenis 		}
1024a8823310Sdenis 		lungetc(START_EXPAND);
1025204df0f8Sclaudio 		goto top;
1026204df0f8Sclaudio 	}
1027204df0f8Sclaudio 
1028204df0f8Sclaudio 	switch (c) {
1029204df0f8Sclaudio 	case '\'':
1030204df0f8Sclaudio 	case '"':
103120741916Sderaadt 		quotec = c;
1032204df0f8Sclaudio 		while (1) {
103320741916Sderaadt 			if ((c = lgetc(quotec)) == EOF)
1034204df0f8Sclaudio 				return (0);
1035204df0f8Sclaudio 			if (c == '\n') {
103620741916Sderaadt 				file->lineno++;
1037204df0f8Sclaudio 				continue;
1038d5d66eaeSderaadt 			} else if (c == '\\') {
103920741916Sderaadt 				if ((next = lgetc(quotec)) == EOF)
1040d5d66eaeSderaadt 					return (0);
1041a1533359Ssashan 				if (next == quotec || next == ' ' ||
1042a1533359Ssashan 				    next == '\t')
1043d5d66eaeSderaadt 					c = next;
1044daf24110Shenning 				else if (next == '\n') {
1045daf24110Shenning 					file->lineno++;
1046ea014f46Sderaadt 					continue;
1047daf24110Shenning 				} else
1048d5d66eaeSderaadt 					lungetc(next);
104920741916Sderaadt 			} else if (c == quotec) {
1050d5d66eaeSderaadt 				*p = '\0';
1051d5d66eaeSderaadt 				break;
105241eef22fSjsg 			} else if (c == '\0') {
105341eef22fSjsg 				yyerror("syntax error");
105441eef22fSjsg 				return (findeol());
1055204df0f8Sclaudio 			}
1056204df0f8Sclaudio 			if (p + 1 >= buf + sizeof(buf) - 1) {
1057204df0f8Sclaudio 				yyerror("string too long");
1058204df0f8Sclaudio 				return (findeol());
1059204df0f8Sclaudio 			}
1060015d7b4dSbenno 			*p++ = c;
1061204df0f8Sclaudio 		}
1062204df0f8Sclaudio 		yylval.v.string = strdup(buf);
1063204df0f8Sclaudio 		if (yylval.v.string == NULL)
1064a062aa9dSkrw 			err(1, "%s", __func__);
1065204df0f8Sclaudio 		return (STRING);
1066204df0f8Sclaudio 	}
1067204df0f8Sclaudio 
106891d3283aSclaudio #define allowed_to_end_number(x) \
10690cf2c9c3Smpf 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
107091d3283aSclaudio 
107191d3283aSclaudio 	if (c == '-' || isdigit(c)) {
107291d3283aSclaudio 		do {
107391d3283aSclaudio 			*p++ = c;
1074915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
107591d3283aSclaudio 				yyerror("string too long");
107691d3283aSclaudio 				return (findeol());
107791d3283aSclaudio 			}
1078d5d66eaeSderaadt 		} while ((c = lgetc(0)) != EOF && isdigit(c));
107991d3283aSclaudio 		lungetc(c);
108091d3283aSclaudio 		if (p == buf + 1 && buf[0] == '-')
108191d3283aSclaudio 			goto nodigits;
108291d3283aSclaudio 		if (c == EOF || allowed_to_end_number(c)) {
108391d3283aSclaudio 			const char *errstr = NULL;
108491d3283aSclaudio 
108591d3283aSclaudio 			*p = '\0';
1086d5d66eaeSderaadt 			yylval.v.number = strtonum(buf, LLONG_MIN,
1087d5d66eaeSderaadt 			    LLONG_MAX, &errstr);
108891d3283aSclaudio 			if (errstr) {
1089d5d66eaeSderaadt 				yyerror("\"%s\" invalid number: %s",
1090d5d66eaeSderaadt 				    buf, errstr);
109191d3283aSclaudio 				return (findeol());
109291d3283aSclaudio 			}
109391d3283aSclaudio 			return (NUMBER);
109491d3283aSclaudio 		} else {
109591d3283aSclaudio nodigits:
109691d3283aSclaudio 			while (p > buf + 1)
109708f6ba19Snaddy 				lungetc((unsigned char)*--p);
109808f6ba19Snaddy 			c = (unsigned char)*--p;
109991d3283aSclaudio 			if (c == '-')
110091d3283aSclaudio 				return (c);
110191d3283aSclaudio 		}
110291d3283aSclaudio 	}
110391d3283aSclaudio 
1104204df0f8Sclaudio #define allowed_in_string(x) \
1105204df0f8Sclaudio 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1106204df0f8Sclaudio 	x != '{' && x != '}' && \
1107204df0f8Sclaudio 	x != '!' && x != '=' && x != '#' && \
1108204df0f8Sclaudio 	x != ','))
1109204df0f8Sclaudio 
1110204df0f8Sclaudio 	if (isalnum(c) || c == ':' || c == '_') {
1111204df0f8Sclaudio 		do {
1112204df0f8Sclaudio 			*p++ = c;
1113915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
1114204df0f8Sclaudio 				yyerror("string too long");
1115204df0f8Sclaudio 				return (findeol());
1116204df0f8Sclaudio 			}
1117d5d66eaeSderaadt 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1118204df0f8Sclaudio 		lungetc(c);
1119204df0f8Sclaudio 		*p = '\0';
1120204df0f8Sclaudio 		if ((token = lookup(buf)) == STRING)
1121204df0f8Sclaudio 			if ((yylval.v.string = strdup(buf)) == NULL)
1122a062aa9dSkrw 				err(1, "%s", __func__);
1123204df0f8Sclaudio 		return (token);
1124204df0f8Sclaudio 	}
1125204df0f8Sclaudio 	if (c == '\n') {
112620741916Sderaadt 		yylval.lineno = file->lineno;
112720741916Sderaadt 		file->lineno++;
1128204df0f8Sclaudio 	}
1129204df0f8Sclaudio 	if (c == EOF)
1130204df0f8Sclaudio 		return (0);
1131204df0f8Sclaudio 	return (c);
1132204df0f8Sclaudio }
1133204df0f8Sclaudio 
113420741916Sderaadt int
113520741916Sderaadt check_file_secrecy(int fd, const char *fname)
113620741916Sderaadt {
113720741916Sderaadt 	struct stat	st;
113820741916Sderaadt 
113920741916Sderaadt 	if (fstat(fd, &st)) {
114020741916Sderaadt 		log_warn("cannot stat %s", fname);
114120741916Sderaadt 		return (-1);
114220741916Sderaadt 	}
114320741916Sderaadt 	if (st.st_uid != 0 && st.st_uid != getuid()) {
114420741916Sderaadt 		log_warnx("%s: owner not root or current user", fname);
114520741916Sderaadt 		return (-1);
114620741916Sderaadt 	}
11477140c133Shenning 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
11487140c133Shenning 		log_warnx("%s: group writable or world read/writable", fname);
114920741916Sderaadt 		return (-1);
115020741916Sderaadt 	}
115120741916Sderaadt 	return (0);
115220741916Sderaadt }
115320741916Sderaadt 
115420741916Sderaadt struct file *
115520741916Sderaadt pushfile(const char *name, int secret)
115620741916Sderaadt {
115720741916Sderaadt 	struct file	*nfile;
115820741916Sderaadt 
11597fc93de0Stobias 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
11606a3d55f9Skrw 		log_warn("%s", __func__);
116120741916Sderaadt 		return (NULL);
1162e23c639fSpyr 	}
11637fc93de0Stobias 	if ((nfile->name = strdup(name)) == NULL) {
11646a3d55f9Skrw 		log_warn("%s", __func__);
11657fc93de0Stobias 		free(nfile);
11667fc93de0Stobias 		return (NULL);
11677fc93de0Stobias 	}
116820741916Sderaadt 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
11696a3d55f9Skrw 		log_warn("%s: %s", __func__, nfile->name);
117020741916Sderaadt 		free(nfile->name);
117120741916Sderaadt 		free(nfile);
117220741916Sderaadt 		return (NULL);
117320741916Sderaadt 	} else if (secret &&
117420741916Sderaadt 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
117520741916Sderaadt 		fclose(nfile->stream);
117620741916Sderaadt 		free(nfile->name);
117720741916Sderaadt 		free(nfile);
117820741916Sderaadt 		return (NULL);
117920741916Sderaadt 	}
1180a8823310Sdenis 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1181a8823310Sdenis 	nfile->ungetsize = 16;
1182a8823310Sdenis 	nfile->ungetbuf = malloc(nfile->ungetsize);
1183a8823310Sdenis 	if (nfile->ungetbuf == NULL) {
11846a3d55f9Skrw 		log_warn("%s", __func__);
1185a8823310Sdenis 		fclose(nfile->stream);
1186a8823310Sdenis 		free(nfile->name);
1187a8823310Sdenis 		free(nfile);
1188a8823310Sdenis 		return (NULL);
1189a8823310Sdenis 	}
119020741916Sderaadt 	TAILQ_INSERT_TAIL(&files, nfile, entry);
119120741916Sderaadt 	return (nfile);
119220741916Sderaadt }
119320741916Sderaadt 
119420741916Sderaadt int
119520741916Sderaadt popfile(void)
119620741916Sderaadt {
119720741916Sderaadt 	struct file	*prev;
119820741916Sderaadt 
1199c6004ab9Smpf 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
120020741916Sderaadt 		prev->errors += file->errors;
1201c6004ab9Smpf 
120220741916Sderaadt 	TAILQ_REMOVE(&files, file, entry);
120320741916Sderaadt 	fclose(file->stream);
120420741916Sderaadt 	free(file->name);
1205a8823310Sdenis 	free(file->ungetbuf);
120620741916Sderaadt 	free(file);
120720741916Sderaadt 	file = prev;
1208c6004ab9Smpf 	return (file ? 0 : EOF);
120920741916Sderaadt }
121020741916Sderaadt 
1211204df0f8Sclaudio struct ospfd_conf *
1212204df0f8Sclaudio parse_config(char *filename, int opts)
1213204df0f8Sclaudio {
1214204df0f8Sclaudio 	struct sym	*sym, *next;
1215204df0f8Sclaudio 
1216bbb232d2Sclaudio 	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
1217bbb232d2Sclaudio 		fatal("parse_config");
121820741916Sderaadt 	conf->opts = opts;
121920741916Sderaadt 	if (conf->opts & OSPFD_OPT_STUB_ROUTER)
122020741916Sderaadt 		conf->flags |= OSPFD_FLAG_STUB_ROUTER;
1221204df0f8Sclaudio 
1222627c6412Sclaudio 	bzero(&globaldefs, sizeof(globaldefs));
1223627c6412Sclaudio 	defs = &globaldefs;
122476b51f83Sclaudio 	TAILQ_INIT(&defs->md_list);
1225627c6412Sclaudio 	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
12267afdfd2dSdlg 	defs->fast_hello_interval = DEFAULT_FAST_INTERVAL;
1227627c6412Sclaudio 	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
1228627c6412Sclaudio 	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
1229627c6412Sclaudio 	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
1230627c6412Sclaudio 	defs->metric = DEFAULT_METRIC;
1231627c6412Sclaudio 	defs->priority = DEFAULT_PRIORITY;
123209e8f780Sremi 	defs->p2p = 0;
1233204df0f8Sclaudio 
12343ada9d8fSnorby 	conf->spf_delay = DEFAULT_SPF_DELAY;
12353ada9d8fSnorby 	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
12363ada9d8fSnorby 	conf->spf_state = SPF_IDLE;
12374c260f66Sremi 	conf->fib_priority = RTP_OSPF;
1238204df0f8Sclaudio 
1239a8823310Sdenis 	if ((file = pushfile(filename,
1240a8823310Sdenis 	    !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1241204df0f8Sclaudio 		free(conf);
1242204df0f8Sclaudio 		return (NULL);
1243204df0f8Sclaudio 	}
1244c6004ab9Smpf 	topfile = file;
1245204df0f8Sclaudio 
1246204df0f8Sclaudio 	LIST_INIT(&conf->area_list);
1247bbb232d2Sclaudio 	LIST_INIT(&conf->cand_list);
1248bbb232d2Sclaudio 	SIMPLEQ_INIT(&conf->redist_list);
1249204df0f8Sclaudio 
1250204df0f8Sclaudio 	yyparse();
125120741916Sderaadt 	errors = file->errors;
125220741916Sderaadt 	popfile();
1253204df0f8Sclaudio 
1254204df0f8Sclaudio 	/* Free macros and check which have not been used. */
125546bca67bSkrw 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1256204df0f8Sclaudio 		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
1257204df0f8Sclaudio 			fprintf(stderr, "warning: macro '%s' not "
1258204df0f8Sclaudio 			    "used\n", sym->nam);
1259204df0f8Sclaudio 		if (!sym->persist) {
1260204df0f8Sclaudio 			free(sym->nam);
1261204df0f8Sclaudio 			free(sym->val);
126220741916Sderaadt 			TAILQ_REMOVE(&symhead, sym, entry);
1263204df0f8Sclaudio 			free(sym);
1264204df0f8Sclaudio 		}
1265204df0f8Sclaudio 	}
1266204df0f8Sclaudio 
126776b51f83Sclaudio 	/* free global config defaults */
126876b51f83Sclaudio 	md_list_clr(&globaldefs.md_list);
126976b51f83Sclaudio 
1270358269bbSclaudio 	/* check that all interfaces belong to the configured rdomain */
1271358269bbSclaudio 	errors += conf_check_rdomain(conf->rdomain);
1272358269bbSclaudio 
1273204df0f8Sclaudio 	if (errors) {
1274204df0f8Sclaudio 		clear_config(conf);
1275204df0f8Sclaudio 		return (NULL);
1276204df0f8Sclaudio 	}
1277204df0f8Sclaudio 
1278204df0f8Sclaudio 	return (conf);
1279204df0f8Sclaudio }
1280204df0f8Sclaudio 
1281204df0f8Sclaudio int
1282204df0f8Sclaudio symset(const char *nam, const char *val, int persist)
1283204df0f8Sclaudio {
1284204df0f8Sclaudio 	struct sym	*sym;
1285204df0f8Sclaudio 
128654c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
128754c95b7aSkrw 		if (strcmp(nam, sym->nam) == 0)
128854c95b7aSkrw 			break;
128954c95b7aSkrw 	}
1290204df0f8Sclaudio 
1291204df0f8Sclaudio 	if (sym != NULL) {
1292204df0f8Sclaudio 		if (sym->persist == 1)
1293204df0f8Sclaudio 			return (0);
1294204df0f8Sclaudio 		else {
1295204df0f8Sclaudio 			free(sym->nam);
1296204df0f8Sclaudio 			free(sym->val);
129720741916Sderaadt 			TAILQ_REMOVE(&symhead, sym, entry);
1298204df0f8Sclaudio 			free(sym);
1299204df0f8Sclaudio 		}
1300204df0f8Sclaudio 	}
1301204df0f8Sclaudio 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1302204df0f8Sclaudio 		return (-1);
1303204df0f8Sclaudio 
1304204df0f8Sclaudio 	sym->nam = strdup(nam);
1305204df0f8Sclaudio 	if (sym->nam == NULL) {
1306204df0f8Sclaudio 		free(sym);
1307204df0f8Sclaudio 		return (-1);
1308204df0f8Sclaudio 	}
1309204df0f8Sclaudio 	sym->val = strdup(val);
1310204df0f8Sclaudio 	if (sym->val == NULL) {
1311204df0f8Sclaudio 		free(sym->nam);
1312204df0f8Sclaudio 		free(sym);
1313204df0f8Sclaudio 		return (-1);
1314204df0f8Sclaudio 	}
1315204df0f8Sclaudio 	sym->used = 0;
1316204df0f8Sclaudio 	sym->persist = persist;
131720741916Sderaadt 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1318204df0f8Sclaudio 	return (0);
1319204df0f8Sclaudio }
1320204df0f8Sclaudio 
1321204df0f8Sclaudio int
1322204df0f8Sclaudio cmdline_symset(char *s)
1323204df0f8Sclaudio {
1324204df0f8Sclaudio 	char	*sym, *val;
1325204df0f8Sclaudio 	int	ret;
1326204df0f8Sclaudio 
1327204df0f8Sclaudio 	if ((val = strrchr(s, '=')) == NULL)
1328204df0f8Sclaudio 		return (-1);
1329ed1b9eb8Smiko 	sym = strndup(s, val - s);
1330ed1b9eb8Smiko 	if (sym == NULL)
1331ed1b9eb8Smiko 		errx(1, "%s: strndup", __func__);
1332204df0f8Sclaudio 	ret = symset(sym, val + 1, 1);
1333204df0f8Sclaudio 	free(sym);
1334204df0f8Sclaudio 
1335204df0f8Sclaudio 	return (ret);
1336204df0f8Sclaudio }
1337204df0f8Sclaudio 
1338204df0f8Sclaudio char *
1339204df0f8Sclaudio symget(const char *nam)
1340204df0f8Sclaudio {
1341204df0f8Sclaudio 	struct sym	*sym;
1342204df0f8Sclaudio 
134354c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
1344204df0f8Sclaudio 		if (strcmp(nam, sym->nam) == 0) {
1345204df0f8Sclaudio 			sym->used = 1;
1346204df0f8Sclaudio 			return (sym->val);
1347204df0f8Sclaudio 		}
134854c95b7aSkrw 	}
1349204df0f8Sclaudio 	return (NULL);
1350204df0f8Sclaudio }
1351204df0f8Sclaudio 
1352204df0f8Sclaudio struct area *
1353204df0f8Sclaudio conf_get_area(struct in_addr id)
1354204df0f8Sclaudio {
1355204df0f8Sclaudio 	struct area	*a;
1356204df0f8Sclaudio 
1357204df0f8Sclaudio 	a = area_find(conf, id);
1358204df0f8Sclaudio 	if (a)
1359204df0f8Sclaudio 		return (a);
1360204df0f8Sclaudio 	a = area_new();
1361204df0f8Sclaudio 	LIST_INSERT_HEAD(&conf->area_list, a, entry);
1362204df0f8Sclaudio 
1363204df0f8Sclaudio 	a->id.s_addr = id.s_addr;
1364204df0f8Sclaudio 
1365204df0f8Sclaudio 	return (a);
1366204df0f8Sclaudio }
1367204df0f8Sclaudio 
1368204df0f8Sclaudio struct iface *
136966dd3991Sclaudio conf_get_if(struct kif *kif, struct kif_addr *ka)
1370204df0f8Sclaudio {
1371204df0f8Sclaudio 	struct area	*a;
1372204df0f8Sclaudio 	struct iface	*i;
1373204df0f8Sclaudio 
1374204df0f8Sclaudio 	LIST_FOREACH(a, &conf->area_list, entry)
1375204df0f8Sclaudio 		LIST_FOREACH(i, &a->iface_list, entry)
137666dd3991Sclaudio 			if (i->ifindex == kif->ifindex &&
137766dd3991Sclaudio 			    i->addr.s_addr == ka->addr.s_addr) {
1378204df0f8Sclaudio 				yyerror("interface %s already configured",
1379e9fa2173Sclaudio 				    kif->ifname);
1380204df0f8Sclaudio 				return (NULL);
1381204df0f8Sclaudio 			}
1382204df0f8Sclaudio 
138366dd3991Sclaudio 	i = if_new(kif, ka);
1384db162a95Sclaudio 	i->auth_keyid = 1;
1385204df0f8Sclaudio 
1386204df0f8Sclaudio 	return (i);
1387204df0f8Sclaudio }
1388204df0f8Sclaudio 
1389358269bbSclaudio int
1390358269bbSclaudio conf_check_rdomain(unsigned int rdomain)
1391358269bbSclaudio {
1392358269bbSclaudio 	struct area		*a;
1393358269bbSclaudio 	struct iface		*i;
13948a9f8fc9Sremi 	struct in_addr		 addr;
13958a9f8fc9Sremi 	struct kif		*kif;
13968a9f8fc9Sremi 	struct redistribute	*r;
1397358269bbSclaudio 	int			 errs = 0;
1398358269bbSclaudio 
13998a9f8fc9Sremi 	SIMPLEQ_FOREACH(r, &conf->redist_list, entry)
14008a9f8fc9Sremi 		if (r->dependon[0] != '\0') {
14018a9f8fc9Sremi 			bzero(&addr, sizeof(addr));
14028a9f8fc9Sremi 			kif = kif_findname(r->dependon, addr, NULL);
14038a9f8fc9Sremi 			if (kif->rdomain != rdomain) {
14048a9f8fc9Sremi 				logit(LOG_CRIT,
14058a9f8fc9Sremi 				    "depend on %s: interface not in rdomain %u",
14068a9f8fc9Sremi 				    kif->ifname, rdomain);
14078a9f8fc9Sremi 				errs++;
14088a9f8fc9Sremi 			}
14098a9f8fc9Sremi 		}
14108a9f8fc9Sremi 
1411358269bbSclaudio 	LIST_FOREACH(a, &conf->area_list, entry)
14128a9f8fc9Sremi 		LIST_FOREACH(i, &a->iface_list, entry) {
1413358269bbSclaudio 			if (i->rdomain != rdomain) {
1414358269bbSclaudio 				logit(LOG_CRIT,
1415358269bbSclaudio 				    "interface %s not in rdomain %u",
1416358269bbSclaudio 				    i->name, rdomain);
1417358269bbSclaudio 				errs++;
1418358269bbSclaudio 			}
14198a9f8fc9Sremi 			if (i->dependon[0] != '\0') {
14208a9f8fc9Sremi 				bzero(&addr, sizeof(addr));
14218a9f8fc9Sremi 				kif = kif_findname(i->dependon, addr, NULL);
14228a9f8fc9Sremi 				if (kif->rdomain != rdomain) {
14238a9f8fc9Sremi 					logit(LOG_CRIT,
14248a9f8fc9Sremi 					    "depend on %s: interface not in "
14258a9f8fc9Sremi 					    "rdomain %u",
14268a9f8fc9Sremi 					    kif->ifname, rdomain);
14278a9f8fc9Sremi 					errs++;
14288a9f8fc9Sremi 				}
14298a9f8fc9Sremi 			}
14308a9f8fc9Sremi 		}
1431358269bbSclaudio 
1432358269bbSclaudio 	return (errs);
1433358269bbSclaudio }
1434358269bbSclaudio 
1435204df0f8Sclaudio void
1436ac149fe2Sremi conf_clear_redist_list(struct redist_list *rl)
1437ac149fe2Sremi {
1438ac149fe2Sremi 	struct redistribute *r;
1439ac149fe2Sremi 	while ((r = SIMPLEQ_FIRST(rl)) != NULL) {
1440ac149fe2Sremi 		SIMPLEQ_REMOVE_HEAD(rl, entry);
1441ac149fe2Sremi 		free(r);
1442ac149fe2Sremi 	}
1443ac149fe2Sremi }
1444ac149fe2Sremi 
1445ac149fe2Sremi void
1446204df0f8Sclaudio clear_config(struct ospfd_conf *xconf)
1447204df0f8Sclaudio {
14481436b306Sclaudio 	struct area	*a;
14491436b306Sclaudio 
14501436b306Sclaudio 	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
14511436b306Sclaudio 		LIST_REMOVE(a, entry);
14521436b306Sclaudio 		area_del(a);
14531436b306Sclaudio 	}
14541436b306Sclaudio 
1455ac149fe2Sremi 	conf_clear_redist_list(&xconf->redist_list);
1456ac149fe2Sremi 
14571436b306Sclaudio 	free(xconf);
1458204df0f8Sclaudio }
1459f12637e5Smsf 
1460f12637e5Smsf u_int32_t
1461f12637e5Smsf get_rtr_id(void)
1462f12637e5Smsf {
1463f12637e5Smsf 	struct ifaddrs		*ifap, *ifa;
1464f12637e5Smsf 	u_int32_t		 ip = 0, cur, localnet;
1465f12637e5Smsf 
1466f12637e5Smsf 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1467f12637e5Smsf 
1468f12637e5Smsf 	if (getifaddrs(&ifap) == -1)
1469f12637e5Smsf 		fatal("getifaddrs");
1470f12637e5Smsf 
1471f12637e5Smsf 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
147265e33efcSbluhm 		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
147365e33efcSbluhm 			continue;
1474c2000e10Sbenno 		if (ifa->ifa_addr == NULL ||
1475c2000e10Sbenno 		    ifa->ifa_addr->sa_family != AF_INET)
1476f12637e5Smsf 			continue;
1477f12637e5Smsf 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1478f12637e5Smsf 		if ((cur & localnet) == localnet)	/* skip 127/8 */
1479f12637e5Smsf 			continue;
1480c508cba4Sclaudio 		if (ntohl(cur) < ntohl(ip) || ip == 0)
1481f12637e5Smsf 			ip = cur;
1482f12637e5Smsf 	}
1483f12637e5Smsf 	freeifaddrs(ifap);
1484f12637e5Smsf 
1485f12637e5Smsf 	if (ip == 0)
1486f12637e5Smsf 		fatal("router-id is 0.0.0.0");
1487f12637e5Smsf 
1488f12637e5Smsf 	return (ip);
1489f12637e5Smsf }
1490471ee2ebSclaudio 
1491471ee2ebSclaudio int
1492471ee2ebSclaudio host(const char *s, struct in_addr *addr, struct in_addr *mask)
1493471ee2ebSclaudio {
1494471ee2ebSclaudio 	struct in_addr		 ina;
1495471ee2ebSclaudio 	int			 bits = 32;
1496471ee2ebSclaudio 
1497471ee2ebSclaudio 	bzero(&ina, sizeof(struct in_addr));
1498471ee2ebSclaudio 	if (strrchr(s, '/') != NULL) {
1499471ee2ebSclaudio 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1500471ee2ebSclaudio 			return (0);
1501471ee2ebSclaudio 	} else {
1502471ee2ebSclaudio 		if (inet_pton(AF_INET, s, &ina) != 1)
1503471ee2ebSclaudio 			return (0);
1504471ee2ebSclaudio 	}
1505471ee2ebSclaudio 
1506471ee2ebSclaudio 	addr->s_addr = ina.s_addr;
1507471ee2ebSclaudio 	mask->s_addr = prefixlen2mask(bits);
1508471ee2ebSclaudio 
1509471ee2ebSclaudio 	return (1);
1510471ee2ebSclaudio }
1511