#include <sys/cdefs.h>
#ifndef lint
#if 0
static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
#else
__IDSTRING(yyrcsid, "$NetBSD: skeleton.c,v 1.14 1997/10/20 03:41:16 lukem Exp $");
#endif
#endif
#include <stdlib.h>
#define YYBYACC 1
#define YYMAJOR 1
#define YYMINOR 9
#define YYLEX yylex()
#define YYEMPTY -1
#define yyclearin (yychar=(YYEMPTY))
#define yyerrok (yyerrflag=0)
#define YYRECOVERING (yyerrflag!=0)
#define YYPREFIX "yy"
#line 25 "parse.y"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <ifaddrs.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "ospf.h"
#include "ospfd.h"
#include "ospfe.h"
#include "log.h"

static struct ospfd_conf	*conf;
static FILE			*fin = NULL;
static int			 lineno = 1;
static int			 errors = 0;
static int			 pdebug = 1;
char				*infile;
char				*start_state;

struct area	*area = NULL;
struct iface	*iface = NULL;

int	 yyerror(const char *, ...);
int	 yyparse(void);
int	 kw_cmp(const void *, const void *);
int	 lookup(char *);
int	 lgetc(FILE *);
int	 lungetc(int);
int	 findeol(void);
int	 yylex(void);
void	 clear_config(struct ospfd_conf *xconf);
int	 check_file_secrecy(int fd, const char *fname);
u_int32_t	get_rtr_id(void);
int	 host(const char *, struct in_addr *, struct in_addr *);

struct config_defaults {
	char		auth_key[MAX_SIMPLE_AUTH_LEN];
	struct auth_md_head	 md_list;
	u_int32_t	dead_interval;
	u_int16_t	transmit_delay;
	u_int16_t	hello_interval;
	u_int16_t	rxmt_interval;
	u_int16_t	metric;
	enum auth_type	auth_type;
	u_int8_t	auth_keyid;
	u_int8_t	priority;
};

struct config_defaults	 globaldefs;
struct config_defaults	 areadefs;
struct config_defaults	 ifacedefs;
struct config_defaults	*defs;

TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
struct sym {
	TAILQ_ENTRY(sym)	 entries;
	int			 used;
	int			 persist;
	char			*nam;
	char			*val;
};

int			 symset(const char *, const char *, int);
char			*symget(const char *);
int			 atoul(char *, u_long *);
struct area		*conf_get_area(struct in_addr);
struct iface		*conf_get_if(struct kif *);

typedef struct {
	union {
		u_int32_t	 number;
		char		*string;
	} v;
	int lineno;
} YYSTYPE;

#line 104 "parse.c"
#define AREA 257
#define INTERFACE 258
#define ROUTERID 259
#define FIBUPDATE 260
#define REDISTRIBUTE 261
#define RTLABEL 262
#define RFC1583COMPAT 263
#define SPFDELAY 264
#define SPFHOLDTIME 265
#define AUTHKEY 266
#define AUTHTYPE 267
#define AUTHMD 268
#define AUTHMDKEYID 269
#define METRIC 270
#define PASSIVE 271
#define HELLOINTERVAL 272
#define TRANSMITDELAY 273
#define RETRANSMITINTERVAL 274
#define ROUTERDEADTIME 275
#define ROUTERPRIORITY 276
#define YES 277
#define NO 278
#define ERROR 279
#define STRING 280
#define YYERRCODE 256
short yylhs[] = {                                        -1,
    0,    0,    0,    0,    0,    0,    1,    4,    4,    2,
    2,    3,    3,    6,    5,    5,    5,    5,    5,    5,
    5,    5,    9,   10,   11,   12,    8,    8,    8,    8,
    8,    8,    8,    8,    8,    8,   13,   13,   14,   15,
    7,   16,   16,   17,   17,   20,   18,   19,   19,   19,
   21,   21,   22,   22,
};
short yylen[] = {                                         2,
    0,    2,    3,    3,    3,    3,    1,    2,    1,    1,
    1,    0,    1,    3,    2,    2,    3,    4,    2,    2,
    2,    1,    3,    2,    2,    2,    2,    2,    2,    2,
    2,    2,    1,    1,    1,    1,    2,    0,    2,    0,
    7,    2,    1,    2,    2,    0,    4,    4,    3,    0,
    2,    1,    2,    2,
};
short yydefred[] = {                                      1,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,   13,    0,
    2,    0,    0,    0,    0,   22,   36,   35,   33,   34,
    6,   40,   15,   10,   11,   16,   19,    7,   20,   21,
   26,   25,    0,   24,   27,   31,   30,   32,   29,   28,
    0,    0,    3,    4,    5,    0,   23,    9,    0,    0,
   17,    0,    8,   18,    0,    0,   37,    0,    0,    0,
   43,    0,   46,    0,   45,   41,   42,   44,    0,   39,
    0,   47,    0,    0,   49,    0,    0,   52,   53,   54,
   48,   51,
};
short yydgoto[] = {                                       1,
   39,   36,   22,   59,   23,   24,   25,   69,   27,   28,
   29,   30,   66,   75,   56,   70,   71,   72,   82,   79,
   87,   88,
};
short yysindex[] = {                                      0,
  -10,   -5, -271, -270, -274, -274, -269, -269, -268, -267,
 -269, -269, -269, -269, -269, -269, -269, -269,    0,  -55,
    0, -247,   17,   18,   20,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0, -248,    0,    0,    0,    0,    0,    0,    0,
 -246, -254,    0,    0,    0,  -90,    0,    0, -245, -244,
    0,   40,    0,    0,   40, -251,    0, -228,   41, -105,
    0,   41,    0,   40,    0,    0,    0,    0,  -69,    0,
   40,    0,  -94,   41,    0,   41,  -83,    0,    0,    0,
    0,    0,
};
short yyrindex[] = {                                      0,
 -206,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,   46,    0,
    0, -229,    0,    0, -124,    0,    0,    0,    0,    0,
    0,    0,    0, -124,    0,    0,    0,    0,   48,    0,
  -72,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,
};
short yygindex[] = {                                      0,
   54,   53,    0,    0,    0,    0,    0,    1,    0,    0,
    0,    0,  -17,  -23,    0,    0,    3,    0,    0,    0,
    0,  -27,
};
#define YYTABLESIZE 270
short yytable[] = {                                      21,
   38,   26,   34,   35,   31,   51,   68,   60,   32,   33,
   38,   41,   42,   52,    9,   10,   11,   12,   13,   76,
   14,   15,   16,   17,   18,   61,   53,   54,   38,   55,
   85,   57,   62,   58,   63,   64,   38,   38,   38,   38,
   38,   91,   38,   38,   38,   38,   38,   67,   78,   65,
   74,   73,   38,   81,   12,   14,   80,   50,   37,   92,
   89,   40,   90,   83,   43,   44,   45,   46,   47,   48,
   49,   50,   77,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,   86,    0,    0,    0,   86,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,   38,    0,    0,    0,    0,    0,    0,
    0,   38,   38,   38,   38,   38,   38,   38,   38,   38,
   38,   38,   68,    0,    0,    0,    0,    0,    0,    0,
    9,   10,   11,   12,   13,    0,   14,   15,   16,   17,
   18,    9,   10,   11,   12,   13,   84,   14,   15,   16,
   17,   18,    9,   10,   11,   12,   13,   84,   14,   15,
   16,   17,   18,   38,   38,   38,   38,   38,   38,   38,
   38,   38,   38,   38,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    2,    3,    0,    4,    5,
    0,    0,    6,    7,    8,    9,   10,   11,   12,   13,
    0,   14,   15,   16,   17,   18,    0,   19,    0,   20,
};
short yycheck[] = {                                      10,
  125,    1,  277,  278,   10,   61,  258,  262,  280,  280,
  280,  280,  280,  261,  266,  267,  268,  269,  270,  125,
  272,  273,  274,  275,  276,  280,   10,   10,  258,   10,
  125,  280,  123,  280,  280,  280,  266,  267,  268,  269,
  270,  125,  272,  273,  274,  275,  276,   65,   72,   10,
   10,  280,  125,  123,  261,   10,   74,   10,    6,   87,
   84,    8,   86,   81,   11,   12,   13,   14,   15,   16,
   17,   18,   70,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   83,   -1,   -1,   -1,   87,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,  258,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,  266,  267,  268,  269,  270,  271,  272,  273,  274,
  275,  276,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
  266,  267,  268,  269,  270,   -1,  272,  273,  274,  275,
  276,  266,  267,  268,  269,  270,  271,  272,  273,  274,
  275,  276,  266,  267,  268,  269,  270,  271,  272,  273,
  274,  275,  276,  266,  267,  268,  269,  270,  271,  272,
  273,  274,  275,  276,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,  256,  257,   -1,  259,  260,
   -1,   -1,  263,  264,  265,  266,  267,  268,  269,  270,
   -1,  272,  273,  274,  275,  276,   -1,  278,   -1,  280,
};
#define YYFINAL 1
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 280
#if YYDEBUG
char *yyname[] = {
"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'='",0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"AREA",
"INTERFACE","ROUTERID","FIBUPDATE","REDISTRIBUTE","RTLABEL","RFC1583COMPAT",
"SPFDELAY","SPFHOLDTIME","AUTHKEY","AUTHTYPE","AUTHMD","AUTHMDKEYID","METRIC",
"PASSIVE","HELLOINTERVAL","TRANSMITDELAY","RETRANSMITINTERVAL","ROUTERDEADTIME",
"ROUTERPRIORITY","YES","NO","ERROR","STRING",
};
char *yyrule[] = {
"$accept : grammar",
"grammar :",
"grammar : grammar '\\n'",
"grammar : grammar conf_main '\\n'",
"grammar : grammar varset '\\n'",
"grammar : grammar area '\\n'",
"grammar : grammar error '\\n'",
"number : STRING",
"string : string STRING",
"string : STRING",
"yesno : YES",
"yesno : NO",
"no :",
"no : NO",
"varset : STRING '=' string",
"conf_main : ROUTERID STRING",
"conf_main : FIBUPDATE yesno",
"conf_main : no REDISTRIBUTE STRING",
"conf_main : no REDISTRIBUTE RTLABEL STRING",
"conf_main : RFC1583COMPAT yesno",
"conf_main : SPFDELAY number",
"conf_main : SPFHOLDTIME number",
"conf_main : defaults",
"authmd : AUTHMD number STRING",
"authmdkeyid : AUTHMDKEYID number",
"authtype : AUTHTYPE STRING",
"authkey : AUTHKEY STRING",
"defaults : METRIC number",
"defaults : ROUTERPRIORITY number",
"defaults : ROUTERDEADTIME number",
"defaults : TRANSMITDELAY number",
"defaults : HELLOINTERVAL number",
"defaults : RETRANSMITINTERVAL number",
"defaults : authtype",
"defaults : authkey",
"defaults : authmdkeyid",
"defaults : authmd",
"optnl : '\\n' optnl",
"optnl :",
"nl : '\\n' optnl",
"$$1 :",
"area : AREA STRING $$1 '{' optnl areaopts_l '}'",
"areaopts_l : areaopts_l areaoptsl",
"areaopts_l : areaoptsl",
"areaoptsl : interface nl",
"areaoptsl : defaults nl",
"$$2 :",
"interface : INTERFACE STRING $$2 interface_block",
"interface_block : '{' optnl interfaceopts_l '}'",
"interface_block : '{' optnl '}'",
"interface_block :",
"interfaceopts_l : interfaceopts_l interfaceoptsl",
"interfaceopts_l : interfaceoptsl",
"interfaceoptsl : PASSIVE nl",
"interfaceoptsl : defaults nl",
};
#endif
#ifdef YYSTACKSIZE
#undef YYMAXDEPTH
#define YYMAXDEPTH YYSTACKSIZE
#else
#ifdef YYMAXDEPTH
#define YYSTACKSIZE YYMAXDEPTH
#else
#define YYSTACKSIZE 10000
#define YYMAXDEPTH 10000
#endif
#endif
#define YYINITSTACKSIZE 200
int yydebug;
int yynerrs;
int yyerrflag;
int yychar;
short *yyssp;
YYSTYPE *yyvsp;
YYSTYPE yyval;
YYSTYPE yylval;
short *yyss;
short *yysslim;
YYSTYPE *yyvs;
int yystacksize;
#line 467 "parse.y"

struct keywords {
	const char	*k_name;
	int		 k_val;
};

int
yyerror(const char *fmt, ...)
{
	va_list	ap;

	errors = 1;
	va_start(ap, fmt);
	fprintf(stderr, "%s:%d: ", infile, yylval.lineno);
	vfprintf(stderr, fmt, ap);
	fprintf(stderr, "\n");
	va_end(ap);
	return (0);
}

int
kw_cmp(const void *k, const void *e)
{

	return (strcmp(k, ((const struct keywords *)e)->k_name));
}

int
lookup(char *s)
{
	/* this has to be sorted always */
	static const struct keywords keywords[] = {
		{"area",		AREA},
		{"auth-key",		AUTHKEY},
		{"auth-md",		AUTHMD},
		{"auth-md-keyid",	AUTHMDKEYID},
		{"auth-type",		AUTHTYPE},
		{"fib-update",		FIBUPDATE},
		{"hello-interval",	HELLOINTERVAL},
		{"interface",		INTERFACE},
		{"metric",		METRIC},
		{"no",			NO},
		{"passive",		PASSIVE},
		{"redistribute",	REDISTRIBUTE},
		{"retransmit-interval",	RETRANSMITINTERVAL},
		{"rfc1583compat",	RFC1583COMPAT},
		{"router-dead-time",	ROUTERDEADTIME},
		{"router-id",		ROUTERID},
		{"router-priority",	ROUTERPRIORITY},
		{"rtlabel",		RTLABEL},
		{"spf-delay",		SPFDELAY},
		{"spf-holdtime",	SPFHOLDTIME},
		{"transmit-delay",	TRANSMITDELAY},
		{"yes",			YES}
	};
	const struct keywords	*p;

	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
	    sizeof(keywords[0]), kw_cmp);

	if (p) {
		if (pdebug > 1)
			fprintf(stderr, "%s: %d\n", s, p->k_val);
		return (p->k_val);
	} else {
		if (pdebug > 1)
			fprintf(stderr, "string: %s\n", s);
		return (STRING);
	}
}

#define MAXPUSHBACK	128

char	*parsebuf;
int	 parseindex;
char	 pushback_buffer[MAXPUSHBACK];
int	 pushback_index = 0;

int
lgetc(FILE *f)
{
	int	c, next;

	if (parsebuf) {
		/* Read character from the parsebuffer instead of input. */
		if (parseindex >= 0) {
			c = parsebuf[parseindex++];
			if (c != '\0')
				return (c);
			parsebuf = NULL;
		} else
			parseindex++;
	}

	if (pushback_index)
		return (pushback_buffer[--pushback_index]);

	while ((c = getc(f)) == '\\') {
		next = getc(f);
		if (next != '\n') {
			c = next;
			break;
		}
		yylval.lineno = lineno;
		lineno++;
	}
	if (c == '\t' || c == ' ') {
		/* Compress blanks to a single space. */
		do {
			c = getc(f);
		} while (c == '\t' || c == ' ');
		ungetc(c, f);
		c = ' ';
	}

	return (c);
}

int
lungetc(int c)
{
	if (c == EOF)
		return (EOF);
	if (parsebuf) {
		parseindex--;
		if (parseindex >= 0)
			return (c);
	}
	if (pushback_index < MAXPUSHBACK-1)
		return (pushback_buffer[pushback_index++] = c);
	else
		return (EOF);
}

int
findeol(void)
{
	int	c;

	parsebuf = NULL;
	pushback_index = 0;

	/* skip to either EOF or the first real EOL */
	while (1) {
		c = lgetc(fin);
		if (c == '\n') {
			lineno++;
			break;
		}
		if (c == EOF)
			break;
	}
	return (ERROR);
}

int
yylex(void)
{
	char	 buf[8096];
	char	*p, *val;
	int	 endc, c;
	int	 token;

top:
	p = buf;
	while ((c = lgetc(fin)) == ' ')
		; /* nothing */

	yylval.lineno = lineno;
	if (c == '#')
		while ((c = lgetc(fin)) != '\n' && c != EOF)
			; /* nothing */
	if (c == '$' && parsebuf == NULL) {
		while (1) {
			if ((c = lgetc(fin)) == EOF)
				return (0);

			if (p + 1 >= buf + sizeof(buf) - 1) {
				yyerror("string too long");
				return (findeol());
			}
			if (isalnum(c) || c == '_') {
				*p++ = (char)c;
				continue;
			}
			*p = '\0';
			lungetc(c);
			break;
		}
		val = symget(buf);
		if (val == NULL) {
			yyerror("macro '%s' not defined", buf);
			return (findeol());
		}
		parsebuf = val;
		parseindex = 0;
		goto top;
	}

	switch (c) {
	case '\'':
	case '"':
		endc = c;
		while (1) {
			if ((c = lgetc(fin)) == EOF)
				return (0);
			if (c == endc) {
				*p = '\0';
				break;
			}
			if (c == '\n') {
				lineno++;
				continue;
			}
			if (p + 1 >= buf + sizeof(buf) - 1) {
				yyerror("string too long");
				return (findeol());
			}
			*p++ = (char)c;
		}
		yylval.v.string = strdup(buf);
		if (yylval.v.string == NULL)
			errx(1, "yylex: strdup");
		return (STRING);
	}

#define allowed_in_string(x) \
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
	x != '{' && x != '}' && \
	x != '!' && x != '=' && x != '#' && \
	x != ','))

	if (isalnum(c) || c == ':' || c == '_') {
		do {
			*p++ = c;
			if ((unsigned)(p-buf) >= sizeof(buf)) {
				yyerror("string too long");
				return (findeol());
			}
		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
		lungetc(c);
		*p = '\0';
		if ((token = lookup(buf)) == STRING)
			if ((yylval.v.string = strdup(buf)) == NULL)
				err(1, "yylex: strdup");
		return (token);
	}
	if (c == '\n') {
		yylval.lineno = lineno;
		lineno++;
	}
	if (c == EOF)
		return (0);
	return (c);
}

struct ospfd_conf *
parse_config(char *filename, int opts)
{
	struct sym	*sym, *next;

	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
		fatal("parse_config");

	bzero(&globaldefs, sizeof(globaldefs));
	defs = &globaldefs;
	TAILQ_INIT(&defs->md_list);
	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
	defs->metric = DEFAULT_METRIC;
	defs->priority = DEFAULT_PRIORITY;

	conf->options = OSPF_OPTION_E;
	conf->spf_delay = DEFAULT_SPF_DELAY;
	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
	conf->spf_state = SPF_IDLE;

	if ((fin = fopen(filename, "r")) == NULL) {
		warn("%s", filename);
		free(conf);
		return (NULL);
	}
	infile = filename;

	conf->opts = opts;
	LIST_INIT(&conf->area_list);
	LIST_INIT(&conf->cand_list);
	STAILQ_INIT(&conf->redist_list);

	if (!(conf->opts & OSPFD_OPT_NOACTION))
		if (check_file_secrecy(fileno(fin), filename)) {
			fclose(fin);
			free(conf);
			return (NULL);
		}

	yyparse();

	fclose(fin);

	/* Free macros and check which have not been used. */
	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
		next = TAILQ_NEXT(sym, entries);
		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
			fprintf(stderr, "warning: macro '%s' not "
			    "used\n", sym->nam);
		if (!sym->persist) {
			free(sym->nam);
			free(sym->val);
			TAILQ_REMOVE(&symhead, sym, entries);
			free(sym);
		}
	}

	/* free global config defaults */
	md_list_clr(&globaldefs.md_list);

	if (errors) {
		clear_config(conf);
		return (NULL);
	}

	if (conf->rtr_id.s_addr == 0)
		conf->rtr_id.s_addr = get_rtr_id();

	return (conf);
}

int
symset(const char *nam, const char *val, int persist)
{
	struct sym	*sym;

	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
	    sym = TAILQ_NEXT(sym, entries))
		;	/* nothing */

	if (sym != NULL) {
		if (sym->persist == 1)
			return (0);
		else {
			free(sym->nam);
			free(sym->val);
			TAILQ_REMOVE(&symhead, sym, entries);
			free(sym);
		}
	}
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
		return (-1);

	sym->nam = strdup(nam);
	if (sym->nam == NULL) {
		free(sym);
		return (-1);
	}
	sym->val = strdup(val);
	if (sym->val == NULL) {
		free(sym->nam);
		free(sym);
		return (-1);
	}
	sym->used = 0;
	sym->persist = persist;
	TAILQ_INSERT_TAIL(&symhead, sym, entries);
	return (0);
}

int
cmdline_symset(char *s)
{
	char	*sym, *val;
	int	ret;
	size_t	len;

	if ((val = strrchr(s, '=')) == NULL)
		return (-1);

	len = strlen(s) - strlen(val) + 1;
	if ((sym = malloc(len)) == NULL)
		errx(1, "cmdline_symset: malloc");

	strlcpy(sym, s, len);

	ret = symset(sym, val + 1, 1);
	free(sym);

	return (ret);
}

char *
symget(const char *nam)
{
	struct sym	*sym;

	TAILQ_FOREACH(sym, &symhead, entries)
		if (strcmp(nam, sym->nam) == 0) {
			sym->used = 1;
			return (sym->val);
		}
	return (NULL);
}

int
atoul(char *s, u_long *ulvalp)
{
	u_long	 ulval;
	char	*ep;

	errno = 0;
	ulval = strtoul(s, &ep, 0);
	if (s[0] == '\0' || *ep != '\0')
		return (-1);
	if (errno == ERANGE && ulval == ULONG_MAX)
		return (-1);
	*ulvalp = ulval;
	return (0);
}

struct area *
conf_get_area(struct in_addr id)
{
	struct area	*a;

	a = area_find(conf, id);
	if (a)
		return (a);
	a = area_new();
	LIST_INSERT_HEAD(&conf->area_list, a, entry);

	a->id.s_addr = id.s_addr;

	return (a);
}

struct iface *
conf_get_if(struct kif *kif)
{
	struct area	*a;
	struct iface	*i;

	LIST_FOREACH(a, &conf->area_list, entry)
		LIST_FOREACH(i, &a->iface_list, entry)
			if (i->ifindex == kif->ifindex) {
				yyerror("interface %s already configured",
				    kif->ifname);
				return (NULL);
			}

	i = if_new(kif);
	i->auth_keyid = 1;

	return (i);
}

void
clear_config(struct ospfd_conf *xconf)
{
	struct area	*a;

	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
		LIST_REMOVE(a, entry);
		area_del(a);
	}

	free(xconf);
}

u_int32_t
get_rtr_id(void)
{
	struct ifaddrs		*ifap, *ifa;
	u_int32_t		 ip = 0, cur, localnet;

	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);

	if (getifaddrs(&ifap) == -1)
		fatal("getifaddrs");

	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr->sa_family != AF_INET)
			continue;
		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
		if ((cur & localnet) == localnet)	/* skip 127/8 */
			continue;
		if (cur > ip || ip == 0)
			ip = cur;
	}
	freeifaddrs(ifap);

	if (ip == 0)
		fatal("router-id is 0.0.0.0");

	return (ip);
}

int
host(const char *s, struct in_addr *addr, struct in_addr *mask)
{
	struct in_addr		 ina;
	int			 bits = 32;

	bzero(&ina, sizeof(struct in_addr));
	if (strrchr(s, '/') != NULL) {
		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
			return (0);
	} else {
		if (inet_pton(AF_INET, s, &ina) != 1)
			return (0);
	}

	addr->s_addr = ina.s_addr;
	mask->s_addr = prefixlen2mask(bits);

	return (1);
}

#line 871 "parse.c"
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
int yyparse __P((void));
static int yygrowstack __P((void));
static int yygrowstack()
{
    int newsize, i;
    short *newss;
    YYSTYPE *newvs;

    if ((newsize = yystacksize) == 0)
        newsize = YYINITSTACKSIZE;
    else if (newsize >= YYMAXDEPTH)
        return -1;
    else if ((newsize *= 2) > YYMAXDEPTH)
        newsize = YYMAXDEPTH;
    i = yyssp - yyss;
    if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL)
        return -1;
    yyss = newss;
    yyssp = newss + i;
    if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL)
        return -1;
    yyvs = newvs;
    yyvsp = newvs + i;
    yystacksize = newsize;
    yysslim = yyss + newsize - 1;
    return 0;
}

#define YYABORT goto yyabort
#define YYREJECT goto yyabort
#define YYACCEPT goto yyaccept
#define YYERROR goto yyerrlab
int
yyparse()
{
    int yym, yyn, yystate;
#if YYDEBUG
    char *yys;

    if ((yys = getenv("YYDEBUG")) != NULL)
    {
        yyn = *yys;
        if (yyn >= '0' && yyn <= '9')
            yydebug = yyn - '0';
    }
#endif

    yynerrs = 0;
    yyerrflag = 0;
    yychar = (-1);

    if (yyss == NULL && yygrowstack()) goto yyoverflow;
    yyssp = yyss;
    yyvsp = yyvs;
    *yyssp = yystate = 0;

yyloop:
    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
    if (yychar < 0)
    {
        if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, reading %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
    }
    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: state %d, shifting to state %d\n",
                    YYPREFIX, yystate, yytable[yyn]);
#endif
        if (yyssp >= yysslim && yygrowstack())
        {
            goto yyoverflow;
        }
        *++yyssp = yystate = yytable[yyn];
        *++yyvsp = yylval;
        yychar = (-1);
        if (yyerrflag > 0)  --yyerrflag;
        goto yyloop;
    }
    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
        yyn = yytable[yyn];
        goto yyreduce;
    }
    if (yyerrflag) goto yyinrecovery;
    goto yynewerror;
yynewerror:
    yyerror("syntax error");
    goto yyerrlab;
yyerrlab:
    ++yynerrs;
yyinrecovery:
    if (yyerrflag < 3)
    {
        yyerrflag = 3;
        for (;;)
        {
            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: state %d, error recovery shifting\
 to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
#endif
                if (yyssp >= yysslim && yygrowstack())
                {
                    goto yyoverflow;
                }
                *++yyssp = yystate = yytable[yyn];
                *++yyvsp = yylval;
                goto yyloop;
            }
            else
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: error recovery discarding state %d\n",
                            YYPREFIX, *yyssp);
#endif
                if (yyssp <= yyss) goto yyabort;
                --yyssp;
                --yyvsp;
            }
        }
    }
    else
    {
        if (yychar == 0) goto yyabort;
#if YYDEBUG
        if (yydebug)
        {
            yys = 0;
            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
            if (!yys) yys = "illegal-symbol";
            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
        yychar = (-1);
        goto yyloop;
    }
yyreduce:
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
                YYPREFIX, yystate, yyn, yyrule[yyn]);
#endif
    yym = yylen[yyn];
    yyval = yyvsp[1-yym];
    switch (yyn)
    {
case 6:
#line 129 "parse.y"
{ errors++; }
break;
case 7:
#line 132 "parse.y"
{
			u_long	ulval;

			if (atoul(yyvsp[0].v.string, &ulval) == -1) {
				yyerror("%s is not a number", yyvsp[0].v.string);
				free(yyvsp[0].v.string);
				YYERROR;
			} else
				yyval.v.number = ulval;
			free(yyvsp[0].v.string);
		}
break;
case 8:
#line 145 "parse.y"
{
			if (asprintf(&yyval.v.string, "%s %s", yyvsp[-1].v.string, yyvsp[0].v.string) == -1) {
				free(yyvsp[-1].v.string);
				free(yyvsp[0].v.string);
				yyerror("string: asprintf");
				YYERROR;
			}
			free(yyvsp[-1].v.string);
			free(yyvsp[0].v.string);
		}
break;
case 10:
#line 158 "parse.y"
{ yyval.v.number = 1; }
break;
case 11:
#line 159 "parse.y"
{ yyval.v.number = 0; }
break;
case 12:
#line 162 "parse.y"
{ yyval.v.number = 0; }
break;
case 13:
#line 163 "parse.y"
{ yyval.v.number = 1; }
break;
case 14:
#line 165 "parse.y"
{
			if (conf->opts & OSPFD_OPT_VERBOSE)
				printf("%s = \"%s\"\n", yyvsp[-2].v.string, yyvsp[0].v.string);
			if (symset(yyvsp[-2].v.string, yyvsp[0].v.string, 0) == -1)
				fatal("cannot store variable");
			free(yyvsp[-2].v.string);
			free(yyvsp[0].v.string);
		}
break;
case 15:
#line 175 "parse.y"
{
			if (!inet_aton(yyvsp[0].v.string, &conf->rtr_id)) {
				yyerror("error parsing router-id");
				free(yyvsp[0].v.string);
				YYERROR;
			}
			free(yyvsp[0].v.string);
		}
break;
case 16:
#line 183 "parse.y"
{
			if (yyvsp[0].v.number == 0)
				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
			else
				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
		}
break;
case 17:
#line 189 "parse.y"
{
			struct redistribute	*r;

			if (!strcmp(yyvsp[0].v.string, "default")) {
				conf->redistribute |= REDISTRIBUTE_DEFAULT;
				if (yyvsp[-2].v.number) {
					yyerror("cannot use 'no' with "
					    "redistribute default");
					free(yyvsp[0].v.string);
					YYERROR;
				}
			} else {
				if ((r = calloc(1, sizeof(*r))) == NULL)
					fatal(NULL);
				if (!strcmp(yyvsp[0].v.string, "static"))
					r->type = REDIST_STATIC;
				else if (!strcmp(yyvsp[0].v.string, "connected"))
					r->type = REDIST_CONNECTED;
				else if (host(yyvsp[0].v.string, &r->addr, &r->mask))
					r->type = REDIST_ADDR;
				else {
					yyerror("unknown redistribute type");
					free(yyvsp[0].v.string);
					free(r);
					YYERROR;
				}

				if (yyvsp[-2].v.number)
					r->type |= REDIST_NO;

				STAILQ_INSERT_TAIL(&conf->redist_list, r,
				    entry);
			}
			conf->redistribute |= REDISTRIBUTE_ON;
			free(yyvsp[0].v.string);

		}
break;
case 18:
#line 226 "parse.y"
{
			struct redistribute	*r;

			if ((r = calloc(1, sizeof(*r))) == NULL)
				fatal(NULL);
			r->type = REDIST_LABEL;
			r->label = rtlabel_name2id(yyvsp[0].v.string);
			if (yyvsp[-3].v.number)
				r->type |= REDIST_NO;
			free(yyvsp[0].v.string);

			STAILQ_INSERT_TAIL(&conf->redist_list, r, entry);
			conf->redistribute |= REDISTRIBUTE_ON;
		}
break;
case 19:
#line 240 "parse.y"
{
			conf->rfc1583compat = yyvsp[0].v.number;
		}
break;
case 20:
#line 243 "parse.y"
{
			if (yyvsp[0].v.number < MIN_SPF_DELAY || yyvsp[0].v.number > MAX_SPF_DELAY) {
				yyerror("spf-delay out of range "
				    "(%d-%d)", MIN_SPF_DELAY,
				    MAX_SPF_DELAY);
				YYERROR;
			}
			conf->spf_delay = yyvsp[0].v.number;
		}
break;
case 21:
#line 252 "parse.y"
{
			if (yyvsp[0].v.number < MIN_SPF_HOLDTIME || yyvsp[0].v.number > MAX_SPF_HOLDTIME) {
				yyerror("spf-holdtime out of range "
				    "(%d-%d)", MIN_SPF_HOLDTIME,
				    MAX_SPF_HOLDTIME);
				YYERROR;
			}
			conf->spf_hold_time = yyvsp[0].v.number;
		}
break;
case 23:
#line 264 "parse.y"
{
			if (yyvsp[-1].v.number < MIN_MD_ID || yyvsp[-1].v.number > MAX_MD_ID) {
				yyerror("auth-md key-id out of range "
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
				free(yyvsp[0].v.string);
				YYERROR;
			}
			if (strlen(yyvsp[0].v.string) > MD5_DIGEST_LENGTH) {
				yyerror("auth-md key length out of range "
				    "(max length %d)",
				    MD5_DIGEST_LENGTH);
				free(yyvsp[0].v.string);
				YYERROR;
			}
			md_list_add(&defs->md_list, yyvsp[-1].v.number, yyvsp[0].v.string);
			free(yyvsp[0].v.string);
		}
break;
case 24:
#line 282 "parse.y"
{
			if (yyvsp[0].v.number < MIN_MD_ID || yyvsp[0].v.number > MAX_MD_ID) {
				yyerror("auth-md-keyid out of range "
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
				YYERROR;
			}
			defs->auth_keyid = yyvsp[0].v.number;
		}
break;
case 25:
#line 291 "parse.y"
{
			enum auth_type	type;

			if (!strcmp(yyvsp[0].v.string, "none"))
				type = AUTH_NONE;
			else if (!strcmp(yyvsp[0].v.string, "simple"))
				type = AUTH_SIMPLE;
			else if (!strcmp(yyvsp[0].v.string, "crypt"))
				type = AUTH_CRYPT;
			else {
				yyerror("unknown auth-type");
				free(yyvsp[0].v.string);
				YYERROR;
			}
			free(yyvsp[0].v.string);
			defs->auth_type = type;
		}
break;
case 26:
#line 310 "parse.y"
{
			if (strlen(yyvsp[0].v.string) > MAX_SIMPLE_AUTH_LEN) {
				yyerror("auth-key too long (max length %d)",
				    MAX_SIMPLE_AUTH_LEN);
					free(yyvsp[0].v.string);
					YYERROR;
			}
			strncpy(defs->auth_key, yyvsp[0].v.string,
			    sizeof(defs->auth_key));
			free(yyvsp[0].v.string);
		}
break;
case 27:
#line 323 "parse.y"
{
			if (yyvsp[0].v.number < MIN_METRIC || yyvsp[0].v.number > MAX_METRIC) {
				yyerror("metric out of range (%d-%d)",
				    MIN_METRIC, MAX_METRIC);
				YYERROR;
			}
			defs->metric = yyvsp[0].v.number;
		}
break;
case 28:
#line 331 "parse.y"
{
			if (yyvsp[0].v.number < MIN_PRIORITY || yyvsp[0].v.number > MAX_PRIORITY) {
				yyerror("router-priority out of range (%d-%d)",
				    MIN_PRIORITY, MAX_PRIORITY);
				YYERROR;
			}
			defs->priority = yyvsp[0].v.number;
		}
break;
case 29:
#line 339 "parse.y"
{
			if (yyvsp[0].v.number < MIN_RTR_DEAD_TIME || yyvsp[0].v.number > MAX_RTR_DEAD_TIME) {
				yyerror("router-dead-time out of range (%d-%d)",
				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
				YYERROR;
			}
			defs->dead_interval = yyvsp[0].v.number;
		}
break;
case 30:
#line 347 "parse.y"
{
			if (yyvsp[0].v.number < MIN_TRANSMIT_DELAY ||
			    yyvsp[0].v.number > MAX_TRANSMIT_DELAY) {
				yyerror("transmit-delay out of range (%d-%d)",
				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
				YYERROR;
			}
			defs->transmit_delay = yyvsp[0].v.number;
		}
break;
case 31:
#line 356 "parse.y"
{
			if (yyvsp[0].v.number < MIN_HELLO_INTERVAL ||
			    yyvsp[0].v.number > MAX_HELLO_INTERVAL) {
				yyerror("hello-interval out of range (%d-%d)",
				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
				YYERROR;
			}
			defs->hello_interval = yyvsp[0].v.number;
		}
break;
case 32:
#line 365 "parse.y"
{
			if (yyvsp[0].v.number < MIN_RXMT_INTERVAL || yyvsp[0].v.number > MAX_RXMT_INTERVAL) {
				yyerror("retransmit-interval out of range "
				    "(%d-%d)", MIN_RXMT_INTERVAL,
				    MAX_RXMT_INTERVAL);
				YYERROR;
			}
			defs->rxmt_interval = yyvsp[0].v.number;
		}
break;
case 40:
#line 387 "parse.y"
{
			struct in_addr	id;
			if (inet_aton(yyvsp[0].v.string, &id) == 0) {
				yyerror("error parsing area");
				free(yyvsp[0].v.string);
				YYERROR;
			}
			free(yyvsp[0].v.string);
			area = conf_get_area(id);

			memcpy(&areadefs, defs, sizeof(areadefs));
			md_list_copy(&areadefs.md_list, &defs->md_list);
			defs = &areadefs;
		}
break;
case 41:
#line 400 "parse.y"
{
			area = NULL;
			md_list_clr(&defs->md_list);
			defs = &globaldefs;
		}
break;
case 46:
#line 415 "parse.y"
{
			struct kif *kif;

			if ((kif = kif_findname(yyvsp[0].v.string)) == NULL) {
				yyerror("unknown interface %s", yyvsp[0].v.string);
				free(yyvsp[0].v.string);
				YYERROR;
			}
			free(yyvsp[0].v.string);
			iface = conf_get_if(kif);
			if (iface == NULL)
				YYERROR;
			iface->area = area;
			LIST_INSERT_HEAD(&area->iface_list,
			    iface, entry);

			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
			md_list_copy(&ifacedefs.md_list, &defs->md_list);
			defs = &ifacedefs;
		}
break;
case 47:
#line 434 "parse.y"
{
			iface->dead_interval = defs->dead_interval;
			iface->transmit_delay = defs->transmit_delay;
			iface->hello_interval = defs->hello_interval;
			iface->rxmt_interval = defs->rxmt_interval;
			iface->metric = defs->metric;
			iface->priority = defs->priority;
			iface->auth_type = defs->auth_type;
			iface->auth_keyid = defs->auth_keyid;
			memcpy(iface->auth_key, defs->auth_key,
			    sizeof(iface->auth_key));
			md_list_copy(&iface->auth_md_list, &defs->md_list);
			md_list_clr(&defs->md_list);
			iface = NULL;
			/* interface is always part of an area */
			defs = &areadefs;
		}
break;
case 53:
#line 462 "parse.y"
{ iface->passive = 1; }
break;
#line 1408 "parse.c"
    }
    yyssp -= yym;
    yystate = *yyssp;
    yyvsp -= yym;
    yym = yylhs[yyn];
    if (yystate == 0 && yym == 0)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: after reduction, shifting from state 0 to\
 state %d\n", YYPREFIX, YYFINAL);
#endif
        yystate = YYFINAL;
        *++yyssp = YYFINAL;
        *++yyvsp = yyval;
        if (yychar < 0)
        {
            if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
            if (yydebug)
            {
                yys = 0;
                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
                if (!yys) yys = "illegal-symbol";
                printf("%sdebug: state %d, reading %d (%s)\n",
                        YYPREFIX, YYFINAL, yychar, yys);
            }
#endif
        }
        if (yychar == 0) goto yyaccept;
        goto yyloop;
    }
    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
        yystate = yytable[yyn];
    else
        yystate = yydgoto[yym];
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: after reduction, shifting from state %d \
to state %d\n", YYPREFIX, *yyssp, yystate);
#endif
    if (yyssp >= yysslim && yygrowstack())
    {
        goto yyoverflow;
    }
    *++yyssp = yystate;
    *++yyvsp = yyval;
    goto yyloop;
yyoverflow:
    yyerror("yacc stack overflow");
yyabort:
    return (1);
yyaccept:
    return (0);
}


syntax highlighted by Code2HTML, v. 0.9.1