xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/config.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "defs.h"
30*0Sstevel@tonic-gate #include "tables.h"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * Parse the config file which consists of entries of the form:
34*0Sstevel@tonic-gate  *	ifdefault	[<variable> <value>]*
35*0Sstevel@tonic-gate  *	prefixdefault	[<variable> <value>]*
36*0Sstevel@tonic-gate  *	if <ifname>	[<variable> <value>]*
37*0Sstevel@tonic-gate  *	prefix <prefix>/<length> <ifname>	[<variable> <value>]*
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * All "ifdefault" and "prefixdefault" entries must preceed any
40*0Sstevel@tonic-gate  * "if" and "prefix" entries.
41*0Sstevel@tonic-gate  *
42*0Sstevel@tonic-gate  * Values (such as expiry dates) which contain white space
43*0Sstevel@tonic-gate  * can be quoted with single or double quotes.
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /* maximum length of messages we send to syslog */
47*0Sstevel@tonic-gate #define	NDPD_LOGMSGSIZE	1024
48*0Sstevel@tonic-gate typedef	boolean_t	(*pfb_t)(char *, uint_t *);
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate struct configinfo {
51*0Sstevel@tonic-gate 	char	*ci_name;
52*0Sstevel@tonic-gate 	uint_t	ci_min;		/* 0: no min check */
53*0Sstevel@tonic-gate 	uint_t	ci_max;		/* ~0U: no max check */
54*0Sstevel@tonic-gate 	uint_t	ci_default;
55*0Sstevel@tonic-gate 	uint_t	ci_index;	/* Into result array */
56*0Sstevel@tonic-gate 	pfb_t	ci_parsefunc;	/* Parse function returns -1 on failure */
57*0Sstevel@tonic-gate };
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate enum config_type { CONFIG_IF, CONFIG_PREFIX};
60*0Sstevel@tonic-gate typedef enum config_type config_type_t;
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate static void set_protocol_defaults(void);
63*0Sstevel@tonic-gate static void print_defaults(void);
64*0Sstevel@tonic-gate static void parse_var_value(config_type_t, struct configinfo *, char *, char *,
65*0Sstevel@tonic-gate     struct confvar *);
66*0Sstevel@tonic-gate static void parse_default(config_type_t, struct configinfo *, char **, int,
67*0Sstevel@tonic-gate     struct confvar *);
68*0Sstevel@tonic-gate static void parse_if(struct configinfo *, char **, int);
69*0Sstevel@tonic-gate static void parse_prefix(struct configinfo *, char **, int);
70*0Sstevel@tonic-gate static boolean_t parse_onoff(char *, uint_t *);	/* boolean */
71*0Sstevel@tonic-gate static boolean_t parse_int(char *, uint_t *);	/* integer */
72*0Sstevel@tonic-gate static boolean_t parse_ms(char *, uint_t *);	/* milliseconds */
73*0Sstevel@tonic-gate static boolean_t parse_s(char *, uint_t *);	/* seconds */
74*0Sstevel@tonic-gate static boolean_t parse_date(char *, uint_t *);	/* date format */
75*0Sstevel@tonic-gate static void conferr(char *fmt, ...);
76*0Sstevel@tonic-gate static FILE *open_conffile(char *filename);
77*0Sstevel@tonic-gate static int parse_line(char *line, char *argvec[], int argcount);
78*0Sstevel@tonic-gate static int readline(FILE *fp, char *line, int length);
79*0Sstevel@tonic-gate static int parse_addrprefix(char *strin, struct in6_addr *in6);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate /*
82*0Sstevel@tonic-gate  * Per interface configuration variables.
83*0Sstevel@tonic-gate  * Min, max, and default values are from RFC 2461.
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate static struct configinfo iflist[] = {
86*0Sstevel@tonic-gate 	/* Name, Min, Max, Default, Index */
87*0Sstevel@tonic-gate 	{ "DupAddrDetectTransmits", 0, 100, 1, I_DupAddrDetectTransmits,
88*0Sstevel@tonic-gate 	parse_int },
89*0Sstevel@tonic-gate 	{ "AdvSendAdvertisements", 0, 1, 0, I_AdvSendAdvertisements,
90*0Sstevel@tonic-gate 	parse_onoff },
91*0Sstevel@tonic-gate 	{ "MaxRtrAdvInterval", 4, 1800, 600, I_MaxRtrAdvInterval, parse_s },
92*0Sstevel@tonic-gate 	{ "MinRtrAdvInterval", 3, 1350, 200, I_MinRtrAdvInterval, parse_s },
93*0Sstevel@tonic-gate 	/*
94*0Sstevel@tonic-gate 	 * No greater than .75 * MaxRtrAdvInterval.
95*0Sstevel@tonic-gate 	 * Default: 0.33 * MaxRtrAdvInterval
96*0Sstevel@tonic-gate 	 */
97*0Sstevel@tonic-gate 	{ "AdvManagedFlag", 0, 1, 0, I_AdvManagedFlag, parse_onoff },
98*0Sstevel@tonic-gate 	{ "AdvOtherConfigFlag", 0, 1, 0, I_AdvOtherConfigFlag, parse_onoff },
99*0Sstevel@tonic-gate 	{ "AdvLinkMTU", IPV6_MIN_MTU, 65535, 0, I_AdvLinkMTU, parse_int },
100*0Sstevel@tonic-gate 	{ "AdvReachableTime", 0, 3600000, 0, I_AdvReachableTime, parse_ms },
101*0Sstevel@tonic-gate 	{ "AdvRetransTimer", 0, ~0U, 0, I_AdvRetransTimer, parse_ms },
102*0Sstevel@tonic-gate 	{ "AdvCurHopLimit", 0, 255, 0, I_AdvCurHopLimit, parse_int },
103*0Sstevel@tonic-gate 	{ "AdvDefaultLifetime", 0, 9000, 1800, I_AdvDefaultLifetime, parse_s },
104*0Sstevel@tonic-gate 	/*
105*0Sstevel@tonic-gate 	 * MUST be either zero or between MaxRtrAdvInterval and 9000 seconds.
106*0Sstevel@tonic-gate 	 * Default: 3 * MaxRtrAdvInterval
107*0Sstevel@tonic-gate 	 */
108*0Sstevel@tonic-gate 	{ "StatelessAddrConf", 0, 1, 1, I_StatelessAddrConf, parse_onoff },
109*0Sstevel@tonic-gate 	/*
110*0Sstevel@tonic-gate 	 * Tmp* variables from RFC 3041, where defaults are defined.
111*0Sstevel@tonic-gate 	 */
112*0Sstevel@tonic-gate 	{ "TmpAddrsEnabled", 0, 1, 0, I_TmpAddrsEnabled, parse_onoff },
113*0Sstevel@tonic-gate 	{ "TmpValidLifetime", 0, ~0U, 604800, I_TmpValidLifetime, parse_s },
114*0Sstevel@tonic-gate 	{ "TmpPreferredLifetime", 0, ~0U, 86400, I_TmpPreferredLifetime,
115*0Sstevel@tonic-gate 	parse_s },
116*0Sstevel@tonic-gate 	{ "TmpRegenAdvance", 0, 60, 5, I_TmpRegenAdvance, parse_s },
117*0Sstevel@tonic-gate 	{ "TmpMaxDesyncFactor", 0, 600, 600, I_TmpMaxDesyncFactor, parse_s },
118*0Sstevel@tonic-gate 	{ NULL, 0, 0, 0, 0 }
119*0Sstevel@tonic-gate };
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*
122*0Sstevel@tonic-gate  * Per prefix: AdvPrefixList configuration variables.
123*0Sstevel@tonic-gate  * Min, max, and default values are from RFC 2461.
124*0Sstevel@tonic-gate  */
125*0Sstevel@tonic-gate static struct configinfo prefixlist[] = {
126*0Sstevel@tonic-gate 	/* Name, Min, Max, Default, Index */
127*0Sstevel@tonic-gate 	{ "AdvValidLifetime", 0, ~0U, 2592000, I_AdvValidLifetime,
128*0Sstevel@tonic-gate 	parse_s },
129*0Sstevel@tonic-gate 	{ "AdvOnLinkFlag", 0, 1, 1, I_AdvOnLinkFlag, parse_onoff },
130*0Sstevel@tonic-gate 	{ "AdvPreferredLifetime", 0, ~0U, 604800, I_AdvPreferredLifetime,
131*0Sstevel@tonic-gate 	parse_s},
132*0Sstevel@tonic-gate 	{ "AdvAutonomousFlag", 0, 1, 1, I_AdvAutonomousFlag, parse_onoff },
133*0Sstevel@tonic-gate 	{ "AdvValidExpiration", 0, ~0U, 0, I_AdvValidExpiration,
134*0Sstevel@tonic-gate 	parse_date },
135*0Sstevel@tonic-gate 	{ "AdvPreferredExpiration", 0, ~0U, 0, I_AdvPreferredExpiration,
136*0Sstevel@tonic-gate 	parse_date},
137*0Sstevel@tonic-gate 	{ NULL, 0, 0, 0, 0 },
138*0Sstevel@tonic-gate };
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * Data structures used to merge above protocol defaults
142*0Sstevel@tonic-gate  * with defaults specified in the configuration file.
143*0Sstevel@tonic-gate  * ifdefault is not static because new interfaces can be
144*0Sstevel@tonic-gate  * created outside of the configuration context.
145*0Sstevel@tonic-gate  */
146*0Sstevel@tonic-gate struct confvar ifdefaults[I_IFSIZE];
147*0Sstevel@tonic-gate static struct confvar prefixdefaults[I_PREFIXSIZE];
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate static char	conf_filename[MAXPATHLEN];
150*0Sstevel@tonic-gate static int	lineno;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate /*
153*0Sstevel@tonic-gate  * Checks for violations of section 5.5.3 (c) of RFC 2462.
154*0Sstevel@tonic-gate  */
155*0Sstevel@tonic-gate static void
156*0Sstevel@tonic-gate check_var_consistency(struct confvar *cv, void *save, int size)
157*0Sstevel@tonic-gate {
158*0Sstevel@tonic-gate 	boolean_t rollback = _B_FALSE;
159*0Sstevel@tonic-gate 	int prefl, prefe, valid;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	prefl = cv[I_AdvPreferredLifetime].cf_value;
162*0Sstevel@tonic-gate 	prefe = cv[I_AdvPreferredExpiration].cf_value;
163*0Sstevel@tonic-gate 	valid = cv[I_AdvValidLifetime].cf_value;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	if (prefl > valid) {
166*0Sstevel@tonic-gate 		conferr("AdvPreferredLifetime (%u) is greater than "
167*0Sstevel@tonic-gate 		    "valid lifetime (%u)\n", prefl, valid);
168*0Sstevel@tonic-gate 		rollback = _B_TRUE;
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	if (prefe > valid) {
172*0Sstevel@tonic-gate 		conferr("AdvPreferredExpiration (%u) is greater than "
173*0Sstevel@tonic-gate 		    "valid lifetime (%u)\n", prefe, valid);
174*0Sstevel@tonic-gate 		rollback = _B_TRUE;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	if (rollback) {
178*0Sstevel@tonic-gate 		(void) memcpy(cv, save, size);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate  * Check for invalid lifetime values for RFC3041 addresses
184*0Sstevel@tonic-gate  */
185*0Sstevel@tonic-gate static void
186*0Sstevel@tonic-gate check_if_var_consistency(struct confvar *cv, void *save, int size)
187*0Sstevel@tonic-gate {
188*0Sstevel@tonic-gate 	boolean_t rollback = _B_FALSE;
189*0Sstevel@tonic-gate 	int tpref, tvalid, tdesync, tregen;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	tpref = cv[I_TmpPreferredLifetime].cf_value;
192*0Sstevel@tonic-gate 	tvalid = cv[I_TmpValidLifetime].cf_value;
193*0Sstevel@tonic-gate 	tdesync = cv[I_TmpMaxDesyncFactor].cf_value;
194*0Sstevel@tonic-gate 	tregen = cv[I_TmpRegenAdvance].cf_value;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	/*
197*0Sstevel@tonic-gate 	 * Only need to do this if tmp addrs are enabled.
198*0Sstevel@tonic-gate 	 */
199*0Sstevel@tonic-gate 	if (cv[I_TmpAddrsEnabled].cf_value == 0)
200*0Sstevel@tonic-gate 		return;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if (tdesync > tpref) {
203*0Sstevel@tonic-gate 		conferr("TmpDesyncFactor (%u) is greater than "
204*0Sstevel@tonic-gate 		    "TmpPreferredLifetime (%u)\n", tdesync, tpref);
205*0Sstevel@tonic-gate 		rollback = _B_TRUE;
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	if (tpref > tvalid) {
209*0Sstevel@tonic-gate 		conferr("TmpPreferredLifetime (%u) is greater than "
210*0Sstevel@tonic-gate 		    "TmpValidLifetime (%u)\n", tpref, tvalid);
211*0Sstevel@tonic-gate 		rollback = _B_TRUE;
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	if (tregen > tvalid) {
215*0Sstevel@tonic-gate 		conferr("TmpRegenAdvance (%u) is greater than "
216*0Sstevel@tonic-gate 		    "TmpValidLifetime (%u)\n", tregen, tvalid);
217*0Sstevel@tonic-gate 		rollback = _B_TRUE;
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if (rollback) {
221*0Sstevel@tonic-gate 		(void) memcpy(cv, save, size);
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate int
226*0Sstevel@tonic-gate parse_config(char *config_file, boolean_t file_required)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	FILE *fp;
229*0Sstevel@tonic-gate 	char line[MAXLINELEN];
230*0Sstevel@tonic-gate 	char pline[MAXLINELEN];
231*0Sstevel@tonic-gate 	int argcount;
232*0Sstevel@tonic-gate 	char *argvec[MAXARGSPERLINE];
233*0Sstevel@tonic-gate 	int defaultdone = 0;	/* Set when first non-default command found */
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	if (debug & D_CONFIG)
236*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_config()\n");
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	set_protocol_defaults();
239*0Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
240*0Sstevel@tonic-gate 		print_defaults();
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	fp = open_conffile(config_file);
243*0Sstevel@tonic-gate 	if (fp == NULL) {
244*0Sstevel@tonic-gate 		if (errno == ENOENT && !file_required)
245*0Sstevel@tonic-gate 			return (0);
246*0Sstevel@tonic-gate 		logperror(config_file);
247*0Sstevel@tonic-gate 		return (-1);
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 	while (readline(fp, line, sizeof (line)) != 0) {
250*0Sstevel@tonic-gate 		(void) strncpy(pline, line, sizeof (pline));
251*0Sstevel@tonic-gate 		pline[sizeof (pline) - 1] = '\0';	/* NULL terminate */
252*0Sstevel@tonic-gate 		argcount = parse_line(pline, argvec,
253*0Sstevel@tonic-gate 		    sizeof (argvec) / sizeof (argvec[0]));
254*0Sstevel@tonic-gate 		if (debug & D_PARSE) {
255*0Sstevel@tonic-gate 			int i;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "scanned %d args\n", argcount);
258*0Sstevel@tonic-gate 			for (i = 0; i < argcount; i++)
259*0Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "arg[%d]: %s\n",
260*0Sstevel@tonic-gate 				    i, argvec[i]);
261*0Sstevel@tonic-gate 		}
262*0Sstevel@tonic-gate 		if (argcount == 0) {
263*0Sstevel@tonic-gate 			/* Empty line - or comment only line */
264*0Sstevel@tonic-gate 			continue;
265*0Sstevel@tonic-gate 		}
266*0Sstevel@tonic-gate 		if (strcmp(argvec[0], "ifdefault") == 0) {
267*0Sstevel@tonic-gate 			char save[sizeof (ifdefaults)];
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 			if (defaultdone) {
270*0Sstevel@tonic-gate 				conferr("ifdefault after non-default "
271*0Sstevel@tonic-gate 				    "command\n");
272*0Sstevel@tonic-gate 				continue;
273*0Sstevel@tonic-gate 			}
274*0Sstevel@tonic-gate 			/*
275*0Sstevel@tonic-gate 			 * Save existing values in case what we read is
276*0Sstevel@tonic-gate 			 * invalid and we need to restore previous settings.
277*0Sstevel@tonic-gate 			 */
278*0Sstevel@tonic-gate 			(void) memcpy(save, ifdefaults, sizeof (ifdefaults));
279*0Sstevel@tonic-gate 			parse_default(CONFIG_IF, iflist, argvec+1, argcount-1,
280*0Sstevel@tonic-gate 			    ifdefaults);
281*0Sstevel@tonic-gate 			check_if_var_consistency(ifdefaults, save,
282*0Sstevel@tonic-gate 			    sizeof (save));
283*0Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "prefixdefault") == 0) {
284*0Sstevel@tonic-gate 			char save[sizeof (prefixdefaults)];
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 			if (defaultdone) {
287*0Sstevel@tonic-gate 				conferr("prefixdefault after non-default "
288*0Sstevel@tonic-gate 				    "command\n");
289*0Sstevel@tonic-gate 				continue;
290*0Sstevel@tonic-gate 			}
291*0Sstevel@tonic-gate 			/*
292*0Sstevel@tonic-gate 			 * Save existing values in case what we read is
293*0Sstevel@tonic-gate 			 * invalid and we need to restore previous settings.
294*0Sstevel@tonic-gate 			 */
295*0Sstevel@tonic-gate 			(void) memcpy(save, prefixdefaults,
296*0Sstevel@tonic-gate 			    sizeof (prefixdefaults));
297*0Sstevel@tonic-gate 			parse_default(CONFIG_PREFIX, prefixlist, argvec+1,
298*0Sstevel@tonic-gate 			    argcount-1, prefixdefaults);
299*0Sstevel@tonic-gate 			check_var_consistency(prefixdefaults, save,
300*0Sstevel@tonic-gate 			    sizeof (save));
301*0Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "if") == 0) {
302*0Sstevel@tonic-gate 			defaultdone = 1;
303*0Sstevel@tonic-gate 			parse_if(iflist, argvec+1, argcount-1);
304*0Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "prefix") == 0) {
305*0Sstevel@tonic-gate 			defaultdone = 1;
306*0Sstevel@tonic-gate 			parse_prefix(prefixlist, argvec+1, argcount-1);
307*0Sstevel@tonic-gate 		} else {
308*0Sstevel@tonic-gate 			conferr("Unknown command: %s\n", argvec[0]);
309*0Sstevel@tonic-gate 		}
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 	(void) fclose(fp);
312*0Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
313*0Sstevel@tonic-gate 		print_defaults();
314*0Sstevel@tonic-gate 	return (0);
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate /*
318*0Sstevel@tonic-gate  * Extract the defaults from the configinfo tables to initialize
319*0Sstevel@tonic-gate  * the ifdefaults and prefixdefaults arrays.
320*0Sstevel@tonic-gate  * The arrays are needed to track which defaults have been changed
321*0Sstevel@tonic-gate  * by the config file.
322*0Sstevel@tonic-gate  */
323*0Sstevel@tonic-gate static void
324*0Sstevel@tonic-gate set_protocol_defaults(void)
325*0Sstevel@tonic-gate {
326*0Sstevel@tonic-gate 	struct configinfo *cip;
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
329*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "extract_protocol_defaults\n");
330*0Sstevel@tonic-gate 	for (cip = iflist; cip->ci_name != NULL; cip++) {
331*0Sstevel@tonic-gate 		ifdefaults[cip->ci_index].cf_value = cip->ci_default;
332*0Sstevel@tonic-gate 		ifdefaults[cip->ci_index].cf_notdefault = _B_FALSE;
333*0Sstevel@tonic-gate 	}
334*0Sstevel@tonic-gate 	for (cip = prefixlist; cip->ci_name != NULL; cip++) {
335*0Sstevel@tonic-gate 		prefixdefaults[cip->ci_index].cf_value = cip->ci_default;
336*0Sstevel@tonic-gate 		prefixdefaults[cip->ci_index].cf_notdefault = _B_FALSE;
337*0Sstevel@tonic-gate 	}
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate void
341*0Sstevel@tonic-gate print_iflist(struct confvar *confvar)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	struct configinfo *cip;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	for (cip = iflist; cip->ci_name != NULL; cip++) {
346*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\t%s min %u max %u def %u value %u set %d\n",
347*0Sstevel@tonic-gate 		    cip->ci_name, cip->ci_min, cip->ci_max, cip->ci_default,
348*0Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_value,
349*0Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_notdefault);
350*0Sstevel@tonic-gate 	}
351*0Sstevel@tonic-gate }
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate void
354*0Sstevel@tonic-gate print_prefixlist(struct confvar *confvar)
355*0Sstevel@tonic-gate {
356*0Sstevel@tonic-gate 	struct configinfo *cip;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	for (cip = prefixlist; cip->ci_name != NULL; cip++) {
359*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\t%s min %u max %u def %u value %u set %d\n",
360*0Sstevel@tonic-gate 		    cip->ci_name, cip->ci_min, cip->ci_max, cip->ci_default,
361*0Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_value,
362*0Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_notdefault);
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate static void
368*0Sstevel@tonic-gate print_defaults(void)
369*0Sstevel@tonic-gate {
370*0Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Default interface variables:\n");
371*0Sstevel@tonic-gate 	print_iflist(ifdefaults);
372*0Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Default prefix variables:\n");
373*0Sstevel@tonic-gate 	print_prefixlist(prefixdefaults);
374*0Sstevel@tonic-gate }
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate /*
377*0Sstevel@tonic-gate  * Read from fp. Handle \ at the end of the line by joining lines together.
378*0Sstevel@tonic-gate  * Return 0 on EOF.
379*0Sstevel@tonic-gate  */
380*0Sstevel@tonic-gate static int
381*0Sstevel@tonic-gate readline(FILE *fp, char *line, int length)
382*0Sstevel@tonic-gate {
383*0Sstevel@tonic-gate 	int got = 0;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate retry:
386*0Sstevel@tonic-gate 	errno = 0;
387*0Sstevel@tonic-gate 	if (fgets(line, length, fp) == NULL) {
388*0Sstevel@tonic-gate 		if (errno == EINTR)
389*0Sstevel@tonic-gate 			goto retry;
390*0Sstevel@tonic-gate 		if (got != 0)
391*0Sstevel@tonic-gate 			return (1);
392*0Sstevel@tonic-gate 		else
393*0Sstevel@tonic-gate 			return (0);
394*0Sstevel@tonic-gate 	}
395*0Sstevel@tonic-gate 	lineno++;
396*0Sstevel@tonic-gate 	got = strlen(line);
397*0Sstevel@tonic-gate 	/* Look for trailing \. Note that fgets includes the linefeed. */
398*0Sstevel@tonic-gate 	if (got >= 2 && line[got-2] == '\\') {
399*0Sstevel@tonic-gate 		/* Skip \ and LF */
400*0Sstevel@tonic-gate 		line += got - 2;
401*0Sstevel@tonic-gate 		length -= got - 2;
402*0Sstevel@tonic-gate 		goto retry;
403*0Sstevel@tonic-gate 	}
404*0Sstevel@tonic-gate 	/* Remove the trailing linefeed */
405*0Sstevel@tonic-gate 	if (got > 0)
406*0Sstevel@tonic-gate 		line[got-1] = '\0';
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	return (1);
409*0Sstevel@tonic-gate }
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate /*
412*0Sstevel@tonic-gate  * Parse a line splitting it off at whitspace characters.
413*0Sstevel@tonic-gate  * Modifies the content of the string by inserting NULLs.
414*0Sstevel@tonic-gate  * If more arguments than fits in argvec/argcount then ignore the last.
415*0Sstevel@tonic-gate  * Returns argcount.
416*0Sstevel@tonic-gate  * Handles single quotes and double quotes.
417*0Sstevel@tonic-gate  */
418*0Sstevel@tonic-gate static int
419*0Sstevel@tonic-gate parse_line(char *line, char *argvec[], int argcount)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	int i = 0;
422*0Sstevel@tonic-gate 	char *cp;
423*0Sstevel@tonic-gate 	boolean_t insingle_quote = _B_FALSE;
424*0Sstevel@tonic-gate 	boolean_t indouble_quote = _B_FALSE;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	/* Truncate at the beginning of a comment */
427*0Sstevel@tonic-gate 	cp = strchr(line, '#');
428*0Sstevel@tonic-gate 	if (cp != NULL)
429*0Sstevel@tonic-gate 		*cp = '\0';
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	for (;;) {
432*0Sstevel@tonic-gate 		/* Skip any whitespace */
433*0Sstevel@tonic-gate 		while (isspace(*line) && *line != '\0')
434*0Sstevel@tonic-gate 			line++;
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 		if (*line == '\'') {
437*0Sstevel@tonic-gate 			line++;
438*0Sstevel@tonic-gate 			if (*line == '\0')
439*0Sstevel@tonic-gate 				return (i);
440*0Sstevel@tonic-gate 			insingle_quote = _B_TRUE;
441*0Sstevel@tonic-gate 		} else if (*line == '"') {
442*0Sstevel@tonic-gate 			line++;
443*0Sstevel@tonic-gate 			if (*line == '\0')
444*0Sstevel@tonic-gate 				return (i);
445*0Sstevel@tonic-gate 			indouble_quote = _B_TRUE;
446*0Sstevel@tonic-gate 		}
447*0Sstevel@tonic-gate 		argvec[i] = line;
448*0Sstevel@tonic-gate 		if (*line == '\0')
449*0Sstevel@tonic-gate 			return (i);
450*0Sstevel@tonic-gate 		i++;
451*0Sstevel@tonic-gate 		/* Skip until next whitespace or end of quoted text */
452*0Sstevel@tonic-gate 		if (insingle_quote) {
453*0Sstevel@tonic-gate 			while (*line != '\'' && *line != '\0')
454*0Sstevel@tonic-gate 				line++;
455*0Sstevel@tonic-gate 			if (*line == '\'') {
456*0Sstevel@tonic-gate 				*line = ' ';
457*0Sstevel@tonic-gate 			} else {
458*0Sstevel@tonic-gate 				/* Handle missing quote at end */
459*0Sstevel@tonic-gate 				i--;
460*0Sstevel@tonic-gate 				conferr("Missing end quote - ignoring <%s>\n",
461*0Sstevel@tonic-gate 				    argvec[i]);
462*0Sstevel@tonic-gate 				return (i);
463*0Sstevel@tonic-gate 			}
464*0Sstevel@tonic-gate 			insingle_quote = _B_FALSE;
465*0Sstevel@tonic-gate 		} else if (indouble_quote) {
466*0Sstevel@tonic-gate 			while (*line != '"' && *line != '\0')
467*0Sstevel@tonic-gate 				line++;
468*0Sstevel@tonic-gate 			if (*line == '"') {
469*0Sstevel@tonic-gate 				*line = ' ';
470*0Sstevel@tonic-gate 			} else {
471*0Sstevel@tonic-gate 				/* Handle missing quote at end */
472*0Sstevel@tonic-gate 				i--;
473*0Sstevel@tonic-gate 				conferr("Missing end quote - ignoring <%s>\n",
474*0Sstevel@tonic-gate 				    argvec[i]);
475*0Sstevel@tonic-gate 				return (i);
476*0Sstevel@tonic-gate 			}
477*0Sstevel@tonic-gate 			indouble_quote = _B_FALSE;
478*0Sstevel@tonic-gate 		} else {
479*0Sstevel@tonic-gate 			while (!isspace(*line) && *line != '\0')
480*0Sstevel@tonic-gate 				line++;
481*0Sstevel@tonic-gate 		}
482*0Sstevel@tonic-gate 		if (*line != '\0') {
483*0Sstevel@tonic-gate 			/* Break off argument */
484*0Sstevel@tonic-gate 			*line++ = '\0';
485*0Sstevel@tonic-gate 		}
486*0Sstevel@tonic-gate 		if (i > argcount)
487*0Sstevel@tonic-gate 			return (argcount);
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 	/* NOTREACHED */
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate static void
493*0Sstevel@tonic-gate parse_var_value(config_type_t type, struct configinfo *list, char *varstr,
494*0Sstevel@tonic-gate     char *valstr, struct confvar *confvar)
495*0Sstevel@tonic-gate {
496*0Sstevel@tonic-gate 	struct configinfo *cip;
497*0Sstevel@tonic-gate 	uint_t val;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	if (debug & D_CONFIG) {
500*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_var_value(%d, %s, %s)\n",
501*0Sstevel@tonic-gate 		    (int)type, varstr, valstr);
502*0Sstevel@tonic-gate 	}
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	for (cip = list; cip->ci_name != NULL; cip++) {
505*0Sstevel@tonic-gate 		if (strcasecmp(cip->ci_name, varstr) == 0)
506*0Sstevel@tonic-gate 			break;
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 	if (cip->ci_name == NULL) {
509*0Sstevel@tonic-gate 		conferr("Unknown variable: <%s>\n", varstr);
510*0Sstevel@tonic-gate 		return;
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 	if (!(*cip->ci_parsefunc)(valstr, &val)) {
513*0Sstevel@tonic-gate 		conferr("Bad value: <%s>\n", valstr);
514*0Sstevel@tonic-gate 		return;
515*0Sstevel@tonic-gate 	}
516*0Sstevel@tonic-gate 	if (cip->ci_min != 0 && val < cip->ci_min) {
517*0Sstevel@tonic-gate 		conferr("Value %s is below minimum %u for %s\n",
518*0Sstevel@tonic-gate 		    valstr, cip->ci_min, varstr);
519*0Sstevel@tonic-gate 		return;
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 	if (cip->ci_max != ~0U && val > cip->ci_max) {
522*0Sstevel@tonic-gate 		conferr("Value %s is above maximum %u for %s\n",
523*0Sstevel@tonic-gate 		    valstr, cip->ci_max, varstr);
524*0Sstevel@tonic-gate 		return;
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate 	/* Check against dynamic/relative limits */
527*0Sstevel@tonic-gate 	if (type == CONFIG_IF) {
528*0Sstevel@tonic-gate 		if (cip->ci_index == I_MinRtrAdvInterval &&
529*0Sstevel@tonic-gate 		    confvar[I_MaxRtrAdvInterval].cf_notdefault &&
530*0Sstevel@tonic-gate 		    val > confvar[I_MaxRtrAdvInterval].cf_value * 0.75) {
531*0Sstevel@tonic-gate 			conferr("MinRtrAdvInterval exceeds .75 * "
532*0Sstevel@tonic-gate 			    "MaxRtrAdvInterval (%u)\n",
533*0Sstevel@tonic-gate 			    confvar[I_MaxRtrAdvInterval].cf_value);
534*0Sstevel@tonic-gate 			return;
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
537*0Sstevel@tonic-gate 		    confvar[I_MinRtrAdvInterval].cf_notdefault &&
538*0Sstevel@tonic-gate 		    confvar[I_MinRtrAdvInterval].cf_value > val * 0.75) {
539*0Sstevel@tonic-gate 			conferr("MinRtrAdvInterval (%u) exceeds .75 * "
540*0Sstevel@tonic-gate 			    "MaxRtrAdvInterval\n",
541*0Sstevel@tonic-gate 			    confvar[I_MinRtrAdvInterval].cf_value);
542*0Sstevel@tonic-gate 			return;
543*0Sstevel@tonic-gate 		}
544*0Sstevel@tonic-gate 		if (cip->ci_index == I_AdvDefaultLifetime &&
545*0Sstevel@tonic-gate 		    confvar[I_MaxRtrAdvInterval].cf_notdefault &&
546*0Sstevel@tonic-gate 		    val != 0 &&
547*0Sstevel@tonic-gate 		    val < confvar[I_MaxRtrAdvInterval].cf_value) {
548*0Sstevel@tonic-gate 			conferr("AdvDefaultLifetime is not between "
549*0Sstevel@tonic-gate 			    "MaxRtrAdrInterval (%u) and 9000 seconds\n",
550*0Sstevel@tonic-gate 			    confvar[I_MaxRtrAdvInterval].cf_value);
551*0Sstevel@tonic-gate 			return;
552*0Sstevel@tonic-gate 		}
553*0Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
554*0Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_notdefault &&
555*0Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_value < val) {
556*0Sstevel@tonic-gate 			conferr("AdvDefaultLifetime (%u) is not between "
557*0Sstevel@tonic-gate 			    "MaxRtrAdrInterval and 9000 seconds\n",
558*0Sstevel@tonic-gate 			    confvar[I_AdvDefaultLifetime].cf_value);
559*0Sstevel@tonic-gate 			return;
560*0Sstevel@tonic-gate 		}
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 	confvar[cip->ci_index].cf_value = val;
563*0Sstevel@tonic-gate 	confvar[cip->ci_index].cf_notdefault = _B_TRUE;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/* Derive dynamic/relative variables based on this one */
566*0Sstevel@tonic-gate 	if (type == CONFIG_IF) {
567*0Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
568*0Sstevel@tonic-gate 		    !confvar[I_MinRtrAdvInterval].cf_notdefault)
569*0Sstevel@tonic-gate 			confvar[I_MinRtrAdvInterval].cf_value = val / 3;
570*0Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
571*0Sstevel@tonic-gate 		    !confvar[I_AdvDefaultLifetime].cf_notdefault)
572*0Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_value = 3 * val;
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate }
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate /*
577*0Sstevel@tonic-gate  * Split up the line into <variable> <value> pairs
578*0Sstevel@tonic-gate  */
579*0Sstevel@tonic-gate static void
580*0Sstevel@tonic-gate parse_default(config_type_t type, struct configinfo *list,
581*0Sstevel@tonic-gate     char *argvec[], int argcount, struct confvar *defaults)
582*0Sstevel@tonic-gate {
583*0Sstevel@tonic-gate 	if (debug & D_CONFIG)
584*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_default: argc %d\n", argcount);
585*0Sstevel@tonic-gate 	while (argcount >= 2) {
586*0Sstevel@tonic-gate 		parse_var_value(type, list, argvec[0], argvec[1], defaults);
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 		argcount -= 2;
589*0Sstevel@tonic-gate 		argvec += 2;
590*0Sstevel@tonic-gate 	}
591*0Sstevel@tonic-gate 	if (argcount != 0)
592*0Sstevel@tonic-gate 		conferr("Trailing text <%s> ignored\n", argvec[0]);
593*0Sstevel@tonic-gate }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate /*
596*0Sstevel@tonic-gate  * Returns true if ok; otherwise false.
597*0Sstevel@tonic-gate  */
598*0Sstevel@tonic-gate static void
599*0Sstevel@tonic-gate parse_if(struct configinfo *list, char *argvec[], int argcount)
600*0Sstevel@tonic-gate {
601*0Sstevel@tonic-gate 	char *ifname;
602*0Sstevel@tonic-gate 	struct phyint *pi;
603*0Sstevel@tonic-gate 	char save[sizeof (pi->pi_config)];
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	if (debug & D_CONFIG)
606*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_if: argc %d\n", argcount);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	if (argcount < 1) {
609*0Sstevel@tonic-gate 		conferr("Missing interface name\n");
610*0Sstevel@tonic-gate 		return;
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 	ifname = argvec[0];
613*0Sstevel@tonic-gate 	argvec++;
614*0Sstevel@tonic-gate 	argcount--;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
617*0Sstevel@tonic-gate 	if (pi == NULL) {
618*0Sstevel@tonic-gate 		/*
619*0Sstevel@tonic-gate 		 * Create the physical interface structure.
620*0Sstevel@tonic-gate 		 * Note, phyint_create() sets the interface
621*0Sstevel@tonic-gate 		 * defaults in pi_config.
622*0Sstevel@tonic-gate 		 */
623*0Sstevel@tonic-gate 		pi = phyint_create(ifname);
624*0Sstevel@tonic-gate 		if (pi == NULL) {
625*0Sstevel@tonic-gate 			conferr("Unable to use interface %s\n", ifname);
626*0Sstevel@tonic-gate 			return;
627*0Sstevel@tonic-gate 		}
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	(void) memcpy(save, pi->pi_config, sizeof (save));
631*0Sstevel@tonic-gate 	while (argcount >= 2) {
632*0Sstevel@tonic-gate 		parse_var_value(CONFIG_IF, list, argvec[0], argvec[1],
633*0Sstevel@tonic-gate 		    pi->pi_config);
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		argcount -= 2;
636*0Sstevel@tonic-gate 		argvec += 2;
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 	if (argcount != 0)
639*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "Trailing text <%s> ignored\n", argvec[0]);
640*0Sstevel@tonic-gate 	check_if_var_consistency(pi->pi_config, save, sizeof (save));
641*0Sstevel@tonic-gate }
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate static void
644*0Sstevel@tonic-gate parse_prefix(struct configinfo *list, char *argvec[], int argcount)
645*0Sstevel@tonic-gate {
646*0Sstevel@tonic-gate 	char *ifname, *prefix;
647*0Sstevel@tonic-gate 	struct phyint *pi;
648*0Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
649*0Sstevel@tonic-gate 	struct in6_addr in6;
650*0Sstevel@tonic-gate 	int prefixlen;
651*0Sstevel@tonic-gate 	char save[sizeof (adv_pr->adv_pr_config)];
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	if (debug & D_CONFIG)
654*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_prefix: argc %d\n", argcount);
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	if (argcount < 2) {
657*0Sstevel@tonic-gate 		conferr("Missing prefix and/or interface name\n");
658*0Sstevel@tonic-gate 		return;
659*0Sstevel@tonic-gate 	}
660*0Sstevel@tonic-gate 	prefix = argvec[0];
661*0Sstevel@tonic-gate 	ifname = argvec[1];
662*0Sstevel@tonic-gate 	argvec += 2;
663*0Sstevel@tonic-gate 	argcount -= 2;
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	prefixlen = parse_addrprefix(prefix, &in6);
666*0Sstevel@tonic-gate 	if (prefixlen == -1) {
667*0Sstevel@tonic-gate 		conferr("Bad prefix %s\n", prefix);
668*0Sstevel@tonic-gate 		return;
669*0Sstevel@tonic-gate 	}
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
672*0Sstevel@tonic-gate 	if (pi == NULL) {
673*0Sstevel@tonic-gate 		/*
674*0Sstevel@tonic-gate 		 * Create the physical interface structure.
675*0Sstevel@tonic-gate 		 * Note, phyint_create() sets the interface
676*0Sstevel@tonic-gate 		 * defaults in pi_config.
677*0Sstevel@tonic-gate 		 */
678*0Sstevel@tonic-gate 		pi = phyint_create(ifname);
679*0Sstevel@tonic-gate 		if (pi == NULL) {
680*0Sstevel@tonic-gate 			conferr("Unable to use interface %s\n", ifname);
681*0Sstevel@tonic-gate 			return;
682*0Sstevel@tonic-gate 		}
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 	adv_pr = adv_prefix_lookup(pi, in6, prefixlen);
685*0Sstevel@tonic-gate 	if (adv_pr == NULL) {
686*0Sstevel@tonic-gate 		int i;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 		adv_pr = adv_prefix_create(pi, in6, prefixlen);
689*0Sstevel@tonic-gate 		if (adv_pr == NULL) {
690*0Sstevel@tonic-gate 			conferr("Unable to create prefix %s\n", prefix);
691*0Sstevel@tonic-gate 			return;
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 		/*
694*0Sstevel@tonic-gate 		 * Copy the defaults from the default array.
695*0Sstevel@tonic-gate 		 */
696*0Sstevel@tonic-gate 		for (i = 0; i < I_PREFIXSIZE; i++) {
697*0Sstevel@tonic-gate 			adv_pr->adv_pr_config[i].cf_value =
698*0Sstevel@tonic-gate 			    prefixdefaults[i].cf_value;
699*0Sstevel@tonic-gate 			adv_pr->adv_pr_config[i].cf_notdefault =
700*0Sstevel@tonic-gate 			    prefixdefaults[i].cf_notdefault;
701*0Sstevel@tonic-gate 		}
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	(void) memcpy(save, adv_pr->adv_pr_config, sizeof (save));
705*0Sstevel@tonic-gate 	while (argcount >= 2) {
706*0Sstevel@tonic-gate 		parse_var_value(CONFIG_PREFIX, list, argvec[0], argvec[1],
707*0Sstevel@tonic-gate 		    adv_pr->adv_pr_config);
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		argcount -= 2;
710*0Sstevel@tonic-gate 		argvec += 2;
711*0Sstevel@tonic-gate 	}
712*0Sstevel@tonic-gate 	check_var_consistency(adv_pr->adv_pr_config, save, sizeof (save));
713*0Sstevel@tonic-gate 	if (argcount != 0)
714*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "Trailing text <%s> ignored\n", argvec[0]);
715*0Sstevel@tonic-gate }
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate /*
718*0Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
719*0Sstevel@tonic-gate  */
720*0Sstevel@tonic-gate static boolean_t
721*0Sstevel@tonic-gate parse_onoff(char *str, uint_t *resp)
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	if (strcasecmp(str, "on") == 0) {
724*0Sstevel@tonic-gate 		*resp = 1;
725*0Sstevel@tonic-gate 		return (_B_TRUE);
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 	if (strcasecmp(str, "off") == 0) {
728*0Sstevel@tonic-gate 		*resp = 0;
729*0Sstevel@tonic-gate 		return (_B_TRUE);
730*0Sstevel@tonic-gate 	}
731*0Sstevel@tonic-gate 	if (strcasecmp(str, "true") == 0) {
732*0Sstevel@tonic-gate 		*resp = 1;
733*0Sstevel@tonic-gate 		return (_B_TRUE);
734*0Sstevel@tonic-gate 	}
735*0Sstevel@tonic-gate 	if (strcasecmp(str, "false") == 0) {
736*0Sstevel@tonic-gate 		*resp = 0;
737*0Sstevel@tonic-gate 		return (_B_TRUE);
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 	if (parse_int(str, resp)) {
740*0Sstevel@tonic-gate 		if (*resp == 0 || *resp == 1)
741*0Sstevel@tonic-gate 			return (_B_TRUE);
742*0Sstevel@tonic-gate 	}
743*0Sstevel@tonic-gate 	return (_B_FALSE);
744*0Sstevel@tonic-gate }
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate /*
747*0Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
748*0Sstevel@tonic-gate  */
749*0Sstevel@tonic-gate static boolean_t
750*0Sstevel@tonic-gate parse_int(char *str, uint_t *resp)
751*0Sstevel@tonic-gate {
752*0Sstevel@tonic-gate 	char *end;
753*0Sstevel@tonic-gate 	int res;
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	res = strtoul(str, &end, 0);
756*0Sstevel@tonic-gate 	if (end == str)
757*0Sstevel@tonic-gate 		return (_B_FALSE);
758*0Sstevel@tonic-gate 	*resp = res;
759*0Sstevel@tonic-gate 	return (_B_TRUE);
760*0Sstevel@tonic-gate }
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate /*
763*0Sstevel@tonic-gate  * Parse something with a unit of millseconds.
764*0Sstevel@tonic-gate  * Regognizes the suffixes "ms", "s", "m", "h", and "d".
765*0Sstevel@tonic-gate  *
766*0Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
767*0Sstevel@tonic-gate  */
768*0Sstevel@tonic-gate static boolean_t
769*0Sstevel@tonic-gate parse_ms(char *str, uint_t *resp)
770*0Sstevel@tonic-gate {
771*0Sstevel@tonic-gate 	/* Look at the last and next to last character */
772*0Sstevel@tonic-gate 	char *cp, *last, *nlast;
773*0Sstevel@tonic-gate 	char str2[BUFSIZ];	/* For local modification */
774*0Sstevel@tonic-gate 	int multiplier = 1;
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	(void) strncpy(str2, str, sizeof (str2));
777*0Sstevel@tonic-gate 	str2[sizeof (str2) - 1] = '\0';
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 	last = str2;
780*0Sstevel@tonic-gate 	nlast = NULL;
781*0Sstevel@tonic-gate 	for (cp = str2; *cp != '\0'; cp++) {
782*0Sstevel@tonic-gate 		nlast = last;
783*0Sstevel@tonic-gate 		last = cp;
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 	if (debug & D_PARSE) {
786*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_ms: last <%c> nlast <%c>\n",
787*0Sstevel@tonic-gate 		    (last != NULL ? *last : ' '),
788*0Sstevel@tonic-gate 		    (nlast != NULL ? *nlast : ' '));
789*0Sstevel@tonic-gate 	}
790*0Sstevel@tonic-gate 	switch (*last) {
791*0Sstevel@tonic-gate 	case 'd':
792*0Sstevel@tonic-gate 		multiplier *= 24;
793*0Sstevel@tonic-gate 		/* FALLTHRU */
794*0Sstevel@tonic-gate 	case 'h':
795*0Sstevel@tonic-gate 		multiplier *= 60;
796*0Sstevel@tonic-gate 		/* FALLTHRU */
797*0Sstevel@tonic-gate 	case 'm':
798*0Sstevel@tonic-gate 		multiplier *= 60;
799*0Sstevel@tonic-gate 		*last = '\0';
800*0Sstevel@tonic-gate 		multiplier *= 1000;	/* Convert to milliseconds */
801*0Sstevel@tonic-gate 		break;
802*0Sstevel@tonic-gate 	case 's':
803*0Sstevel@tonic-gate 		/* Could be "ms" or "s" */
804*0Sstevel@tonic-gate 		if (nlast != NULL && *nlast == 'm') {
805*0Sstevel@tonic-gate 			/* "ms" */
806*0Sstevel@tonic-gate 			*nlast = '\0';
807*0Sstevel@tonic-gate 		} else {
808*0Sstevel@tonic-gate 			*last = '\0';
809*0Sstevel@tonic-gate 			multiplier *= 1000;	/* Convert to milliseconds */
810*0Sstevel@tonic-gate 		}
811*0Sstevel@tonic-gate 		break;
812*0Sstevel@tonic-gate 	}
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	if (!parse_int(str2, resp))
815*0Sstevel@tonic-gate 		return (_B_FALSE);
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	*resp *= multiplier;
818*0Sstevel@tonic-gate 	return (_B_TRUE);
819*0Sstevel@tonic-gate }
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate /*
822*0Sstevel@tonic-gate  * Parse something with a unit of seconds.
823*0Sstevel@tonic-gate  * Regognizes the suffixes "s", "m", "h", and "d".
824*0Sstevel@tonic-gate  *
825*0Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
826*0Sstevel@tonic-gate  */
827*0Sstevel@tonic-gate static boolean_t
828*0Sstevel@tonic-gate parse_s(char *str, uint_t *resp)
829*0Sstevel@tonic-gate {
830*0Sstevel@tonic-gate 	/* Look at the last character */
831*0Sstevel@tonic-gate 	char *cp, *last;
832*0Sstevel@tonic-gate 	char str2[BUFSIZ];	/* For local modification */
833*0Sstevel@tonic-gate 	int multiplier = 1;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	(void) strncpy(str2, str, sizeof (str2));
836*0Sstevel@tonic-gate 	str2[sizeof (str2) - 1] = '\0';
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	last = str2;
839*0Sstevel@tonic-gate 	for (cp = str2; *cp != '\0'; cp++) {
840*0Sstevel@tonic-gate 		last = cp;
841*0Sstevel@tonic-gate 	}
842*0Sstevel@tonic-gate 	if (debug & D_PARSE) {
843*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_s: last <%c>\n",
844*0Sstevel@tonic-gate 		    (last != NULL ? *last : ' '));
845*0Sstevel@tonic-gate 	}
846*0Sstevel@tonic-gate 	switch (*last) {
847*0Sstevel@tonic-gate 	case 'd':
848*0Sstevel@tonic-gate 		multiplier *= 24;
849*0Sstevel@tonic-gate 		/* FALLTHRU */
850*0Sstevel@tonic-gate 	case 'h':
851*0Sstevel@tonic-gate 		multiplier *= 60;
852*0Sstevel@tonic-gate 		/* FALLTHRU */
853*0Sstevel@tonic-gate 	case 'm':
854*0Sstevel@tonic-gate 		multiplier *= 60;
855*0Sstevel@tonic-gate 		/* FALLTHRU */
856*0Sstevel@tonic-gate 	case 's':
857*0Sstevel@tonic-gate 		*last = '\0';
858*0Sstevel@tonic-gate 		break;
859*0Sstevel@tonic-gate 	}
860*0Sstevel@tonic-gate 	if (!parse_int(str2, resp))
861*0Sstevel@tonic-gate 		return (_B_FALSE);
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 	*resp *= multiplier;
864*0Sstevel@tonic-gate 	return (_B_TRUE);
865*0Sstevel@tonic-gate }
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate /*
868*0Sstevel@tonic-gate  * Return prefixlen (0 to 128) if ok; -1 if failed.
869*0Sstevel@tonic-gate  */
870*0Sstevel@tonic-gate static int
871*0Sstevel@tonic-gate parse_addrprefix(char *strin, struct in6_addr *in6)
872*0Sstevel@tonic-gate {
873*0Sstevel@tonic-gate 	char str[BUFSIZ];	/* Local copy for modification */
874*0Sstevel@tonic-gate 	int prefixlen;
875*0Sstevel@tonic-gate 	char *cp;
876*0Sstevel@tonic-gate 	char *end;
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	(void) strncpy(str, strin, sizeof (str));
879*0Sstevel@tonic-gate 	str[sizeof (str) - 1] = '\0';
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	cp = strchr(str, '/');
882*0Sstevel@tonic-gate 	if (cp == NULL)
883*0Sstevel@tonic-gate 		return (-1);
884*0Sstevel@tonic-gate 	*cp = '\0';
885*0Sstevel@tonic-gate 	cp++;
886*0Sstevel@tonic-gate 
887*0Sstevel@tonic-gate 	prefixlen = strtol(cp, &end, 10);
888*0Sstevel@tonic-gate 	if (cp == end)
889*0Sstevel@tonic-gate 		return (-1);
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	if (prefixlen < 0 || prefixlen > IPV6_ABITS)
892*0Sstevel@tonic-gate 		return (-1);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	if (inet_pton(AF_INET6, str, in6) != 1)
895*0Sstevel@tonic-gate 		return (-1);
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	return (prefixlen);
898*0Sstevel@tonic-gate }
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate /*
901*0Sstevel@tonic-gate  * Parse an absolute date using a datemsk config file.
902*0Sstevel@tonic-gate  * Return the difference (measured in seconds) between that date/time and
903*0Sstevel@tonic-gate  * the current date/time.
904*0Sstevel@tonic-gate  * If the date has passed return zero.
905*0Sstevel@tonic-gate  *
906*0Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
907*0Sstevel@tonic-gate  * XXX Due to getdate limitations can not exceed year 2038.
908*0Sstevel@tonic-gate  */
909*0Sstevel@tonic-gate static boolean_t
910*0Sstevel@tonic-gate parse_date(char *str, uint_t *resp)
911*0Sstevel@tonic-gate {
912*0Sstevel@tonic-gate 	struct tm *tm;
913*0Sstevel@tonic-gate 	struct timeval tvs;
914*0Sstevel@tonic-gate 	time_t time, ntime;
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	if (getenv("DATEMSK") == NULL) {
917*0Sstevel@tonic-gate 		(void) putenv("DATEMSK=/etc/inet/datemsk.ndpd");
918*0Sstevel@tonic-gate 	}
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	if (gettimeofday(&tvs, NULL) < 0) {
921*0Sstevel@tonic-gate 		logperror("gettimeofday");
922*0Sstevel@tonic-gate 		return (_B_FALSE);
923*0Sstevel@tonic-gate 	}
924*0Sstevel@tonic-gate 	time = tvs.tv_sec;
925*0Sstevel@tonic-gate 	tm = getdate(str);
926*0Sstevel@tonic-gate 	if (tm == NULL) {
927*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "Bad date <%s> (error %d)\n",
928*0Sstevel@tonic-gate 		    str, getdate_err);
929*0Sstevel@tonic-gate 		return (_B_FALSE);
930*0Sstevel@tonic-gate 	}
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	ntime = mktime(tm);
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	if (debug & D_PARSE) {
935*0Sstevel@tonic-gate 		char buf[BUFSIZ];
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 		(void) strftime(buf, sizeof (buf), "%Y-%m-%d %R %Z", tm);
938*0Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_date: <%s>, delta %ld seconds\n",
939*0Sstevel@tonic-gate 		    buf, ntime - time);
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 	if (ntime < time) {
942*0Sstevel@tonic-gate 		conferr("Date in the past <%s>\n", str);
943*0Sstevel@tonic-gate 		*resp = 0;
944*0Sstevel@tonic-gate 		return (_B_TRUE);
945*0Sstevel@tonic-gate 	}
946*0Sstevel@tonic-gate 	*resp = (ntime - time);
947*0Sstevel@tonic-gate 	return (_B_TRUE);
948*0Sstevel@tonic-gate }
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate /* PRINTFLIKE1 */
951*0Sstevel@tonic-gate static void
952*0Sstevel@tonic-gate conferr(char *fmt, ...)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate 	char msg[NDPD_LOGMSGSIZE];
955*0Sstevel@tonic-gate 	size_t slen;
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	va_list ap;
958*0Sstevel@tonic-gate 	va_start(ap, fmt);
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	(void) snprintf(msg, NDPD_LOGMSGSIZE, "%s line %d: ",
961*0Sstevel@tonic-gate 	    conf_filename, lineno);
962*0Sstevel@tonic-gate 	slen = strlen(msg);
963*0Sstevel@tonic-gate 	(void) vsnprintf(msg + slen, NDPD_LOGMSGSIZE - slen, fmt, ap);
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	logmsg(LOG_ERR, "%s", msg);
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 	va_end(ap);
968*0Sstevel@tonic-gate }
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate static FILE *
971*0Sstevel@tonic-gate open_conffile(char *filename)
972*0Sstevel@tonic-gate {
973*0Sstevel@tonic-gate 	if (strlcpy(conf_filename, filename, MAXPATHLEN) >= MAXPATHLEN) {
974*0Sstevel@tonic-gate 		logmsg(LOG_ERR, "config file pathname is too long\n");
975*0Sstevel@tonic-gate 		return (NULL);
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	lineno = 0;
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	return (fopen(filename, "r"));
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate }
983