xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/config.c (revision 3431:9f2d277dcffa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3431Scarlsonj  * Common Development and Distribution License (the "License").
6*3431Scarlsonj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3431Scarlsonj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "defs.h"
290Sstevel@tonic-gate #include "tables.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Parse the config file which consists of entries of the form:
330Sstevel@tonic-gate  *	ifdefault	[<variable> <value>]*
340Sstevel@tonic-gate  *	prefixdefault	[<variable> <value>]*
350Sstevel@tonic-gate  *	if <ifname>	[<variable> <value>]*
360Sstevel@tonic-gate  *	prefix <prefix>/<length> <ifname>	[<variable> <value>]*
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * All "ifdefault" and "prefixdefault" entries must preceed any
390Sstevel@tonic-gate  * "if" and "prefix" entries.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * Values (such as expiry dates) which contain white space
420Sstevel@tonic-gate  * can be quoted with single or double quotes.
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /* maximum length of messages we send to syslog */
460Sstevel@tonic-gate #define	NDPD_LOGMSGSIZE	1024
470Sstevel@tonic-gate typedef	boolean_t	(*pfb_t)(char *, uint_t *);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate struct configinfo {
500Sstevel@tonic-gate 	char	*ci_name;
510Sstevel@tonic-gate 	uint_t	ci_min;		/* 0: no min check */
520Sstevel@tonic-gate 	uint_t	ci_max;		/* ~0U: no max check */
530Sstevel@tonic-gate 	uint_t	ci_default;
540Sstevel@tonic-gate 	uint_t	ci_index;	/* Into result array */
550Sstevel@tonic-gate 	pfb_t	ci_parsefunc;	/* Parse function returns -1 on failure */
560Sstevel@tonic-gate };
570Sstevel@tonic-gate 
580Sstevel@tonic-gate enum config_type { CONFIG_IF, CONFIG_PREFIX};
590Sstevel@tonic-gate typedef enum config_type config_type_t;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static void set_protocol_defaults(void);
620Sstevel@tonic-gate static void print_defaults(void);
630Sstevel@tonic-gate static void parse_var_value(config_type_t, struct configinfo *, char *, char *,
640Sstevel@tonic-gate     struct confvar *);
650Sstevel@tonic-gate static void parse_default(config_type_t, struct configinfo *, char **, int,
660Sstevel@tonic-gate     struct confvar *);
670Sstevel@tonic-gate static void parse_if(struct configinfo *, char **, int);
680Sstevel@tonic-gate static void parse_prefix(struct configinfo *, char **, int);
690Sstevel@tonic-gate static boolean_t parse_onoff(char *, uint_t *);	/* boolean */
700Sstevel@tonic-gate static boolean_t parse_int(char *, uint_t *);	/* integer */
710Sstevel@tonic-gate static boolean_t parse_ms(char *, uint_t *);	/* milliseconds */
720Sstevel@tonic-gate static boolean_t parse_s(char *, uint_t *);	/* seconds */
730Sstevel@tonic-gate static boolean_t parse_date(char *, uint_t *);	/* date format */
740Sstevel@tonic-gate static void conferr(char *fmt, ...);
750Sstevel@tonic-gate static FILE *open_conffile(char *filename);
760Sstevel@tonic-gate static int parse_line(char *line, char *argvec[], int argcount);
770Sstevel@tonic-gate static int readline(FILE *fp, char *line, int length);
780Sstevel@tonic-gate static int parse_addrprefix(char *strin, struct in6_addr *in6);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * Per interface configuration variables.
820Sstevel@tonic-gate  * Min, max, and default values are from RFC 2461.
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate static struct configinfo iflist[] = {
850Sstevel@tonic-gate 	/* Name, Min, Max, Default, Index */
860Sstevel@tonic-gate 	{ "DupAddrDetectTransmits", 0, 100, 1, I_DupAddrDetectTransmits,
870Sstevel@tonic-gate 	parse_int },
880Sstevel@tonic-gate 	{ "AdvSendAdvertisements", 0, 1, 0, I_AdvSendAdvertisements,
890Sstevel@tonic-gate 	parse_onoff },
900Sstevel@tonic-gate 	{ "MaxRtrAdvInterval", 4, 1800, 600, I_MaxRtrAdvInterval, parse_s },
910Sstevel@tonic-gate 	{ "MinRtrAdvInterval", 3, 1350, 200, I_MinRtrAdvInterval, parse_s },
920Sstevel@tonic-gate 	/*
930Sstevel@tonic-gate 	 * No greater than .75 * MaxRtrAdvInterval.
940Sstevel@tonic-gate 	 * Default: 0.33 * MaxRtrAdvInterval
950Sstevel@tonic-gate 	 */
960Sstevel@tonic-gate 	{ "AdvManagedFlag", 0, 1, 0, I_AdvManagedFlag, parse_onoff },
970Sstevel@tonic-gate 	{ "AdvOtherConfigFlag", 0, 1, 0, I_AdvOtherConfigFlag, parse_onoff },
980Sstevel@tonic-gate 	{ "AdvLinkMTU", IPV6_MIN_MTU, 65535, 0, I_AdvLinkMTU, parse_int },
990Sstevel@tonic-gate 	{ "AdvReachableTime", 0, 3600000, 0, I_AdvReachableTime, parse_ms },
1000Sstevel@tonic-gate 	{ "AdvRetransTimer", 0, ~0U, 0, I_AdvRetransTimer, parse_ms },
1010Sstevel@tonic-gate 	{ "AdvCurHopLimit", 0, 255, 0, I_AdvCurHopLimit, parse_int },
1020Sstevel@tonic-gate 	{ "AdvDefaultLifetime", 0, 9000, 1800, I_AdvDefaultLifetime, parse_s },
1030Sstevel@tonic-gate 	/*
1040Sstevel@tonic-gate 	 * MUST be either zero or between MaxRtrAdvInterval and 9000 seconds.
1050Sstevel@tonic-gate 	 * Default: 3 * MaxRtrAdvInterval
1060Sstevel@tonic-gate 	 */
1070Sstevel@tonic-gate 	{ "StatelessAddrConf", 0, 1, 1, I_StatelessAddrConf, parse_onoff },
108*3431Scarlsonj 	{ "StatefulAddrConf", 0, 1, 1, I_StatefulAddrConf, parse_onoff },
1090Sstevel@tonic-gate 	/*
1100Sstevel@tonic-gate 	 * Tmp* variables from RFC 3041, where defaults are defined.
1110Sstevel@tonic-gate 	 */
1120Sstevel@tonic-gate 	{ "TmpAddrsEnabled", 0, 1, 0, I_TmpAddrsEnabled, parse_onoff },
1130Sstevel@tonic-gate 	{ "TmpValidLifetime", 0, ~0U, 604800, I_TmpValidLifetime, parse_s },
1140Sstevel@tonic-gate 	{ "TmpPreferredLifetime", 0, ~0U, 86400, I_TmpPreferredLifetime,
1150Sstevel@tonic-gate 	parse_s },
1160Sstevel@tonic-gate 	{ "TmpRegenAdvance", 0, 60, 5, I_TmpRegenAdvance, parse_s },
1170Sstevel@tonic-gate 	{ "TmpMaxDesyncFactor", 0, 600, 600, I_TmpMaxDesyncFactor, parse_s },
1180Sstevel@tonic-gate 	{ NULL, 0, 0, 0, 0 }
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Per prefix: AdvPrefixList configuration variables.
1230Sstevel@tonic-gate  * Min, max, and default values are from RFC 2461.
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate static struct configinfo prefixlist[] = {
1260Sstevel@tonic-gate 	/* Name, Min, Max, Default, Index */
1270Sstevel@tonic-gate 	{ "AdvValidLifetime", 0, ~0U, 2592000, I_AdvValidLifetime,
1280Sstevel@tonic-gate 	parse_s },
1290Sstevel@tonic-gate 	{ "AdvOnLinkFlag", 0, 1, 1, I_AdvOnLinkFlag, parse_onoff },
1300Sstevel@tonic-gate 	{ "AdvPreferredLifetime", 0, ~0U, 604800, I_AdvPreferredLifetime,
1310Sstevel@tonic-gate 	parse_s},
1320Sstevel@tonic-gate 	{ "AdvAutonomousFlag", 0, 1, 1, I_AdvAutonomousFlag, parse_onoff },
1330Sstevel@tonic-gate 	{ "AdvValidExpiration", 0, ~0U, 0, I_AdvValidExpiration,
1340Sstevel@tonic-gate 	parse_date },
1350Sstevel@tonic-gate 	{ "AdvPreferredExpiration", 0, ~0U, 0, I_AdvPreferredExpiration,
1360Sstevel@tonic-gate 	parse_date},
1370Sstevel@tonic-gate 	{ NULL, 0, 0, 0, 0 },
1380Sstevel@tonic-gate };
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * Data structures used to merge above protocol defaults
1420Sstevel@tonic-gate  * with defaults specified in the configuration file.
1430Sstevel@tonic-gate  * ifdefault is not static because new interfaces can be
1440Sstevel@tonic-gate  * created outside of the configuration context.
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate struct confvar ifdefaults[I_IFSIZE];
1470Sstevel@tonic-gate static struct confvar prefixdefaults[I_PREFIXSIZE];
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static char	conf_filename[MAXPATHLEN];
1500Sstevel@tonic-gate static int	lineno;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Checks for violations of section 5.5.3 (c) of RFC 2462.
1540Sstevel@tonic-gate  */
1550Sstevel@tonic-gate static void
check_var_consistency(struct confvar * cv,void * save,int size)1560Sstevel@tonic-gate check_var_consistency(struct confvar *cv, void *save, int size)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	boolean_t rollback = _B_FALSE;
1590Sstevel@tonic-gate 	int prefl, prefe, valid;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	prefl = cv[I_AdvPreferredLifetime].cf_value;
1620Sstevel@tonic-gate 	prefe = cv[I_AdvPreferredExpiration].cf_value;
1630Sstevel@tonic-gate 	valid = cv[I_AdvValidLifetime].cf_value;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (prefl > valid) {
1660Sstevel@tonic-gate 		conferr("AdvPreferredLifetime (%u) is greater than "
1670Sstevel@tonic-gate 		    "valid lifetime (%u)\n", prefl, valid);
1680Sstevel@tonic-gate 		rollback = _B_TRUE;
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if (prefe > valid) {
1720Sstevel@tonic-gate 		conferr("AdvPreferredExpiration (%u) is greater than "
1730Sstevel@tonic-gate 		    "valid lifetime (%u)\n", prefe, valid);
1740Sstevel@tonic-gate 		rollback = _B_TRUE;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if (rollback) {
1780Sstevel@tonic-gate 		(void) memcpy(cv, save, size);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  * Check for invalid lifetime values for RFC3041 addresses
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate static void
check_if_var_consistency(struct confvar * cv,void * save,int size)1860Sstevel@tonic-gate check_if_var_consistency(struct confvar *cv, void *save, int size)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	boolean_t rollback = _B_FALSE;
1890Sstevel@tonic-gate 	int tpref, tvalid, tdesync, tregen;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	tpref = cv[I_TmpPreferredLifetime].cf_value;
1920Sstevel@tonic-gate 	tvalid = cv[I_TmpValidLifetime].cf_value;
1930Sstevel@tonic-gate 	tdesync = cv[I_TmpMaxDesyncFactor].cf_value;
1940Sstevel@tonic-gate 	tregen = cv[I_TmpRegenAdvance].cf_value;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * Only need to do this if tmp addrs are enabled.
1980Sstevel@tonic-gate 	 */
1990Sstevel@tonic-gate 	if (cv[I_TmpAddrsEnabled].cf_value == 0)
2000Sstevel@tonic-gate 		return;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if (tdesync > tpref) {
2030Sstevel@tonic-gate 		conferr("TmpDesyncFactor (%u) is greater than "
2040Sstevel@tonic-gate 		    "TmpPreferredLifetime (%u)\n", tdesync, tpref);
2050Sstevel@tonic-gate 		rollback = _B_TRUE;
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (tpref > tvalid) {
2090Sstevel@tonic-gate 		conferr("TmpPreferredLifetime (%u) is greater than "
2100Sstevel@tonic-gate 		    "TmpValidLifetime (%u)\n", tpref, tvalid);
2110Sstevel@tonic-gate 		rollback = _B_TRUE;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (tregen > tvalid) {
2150Sstevel@tonic-gate 		conferr("TmpRegenAdvance (%u) is greater than "
2160Sstevel@tonic-gate 		    "TmpValidLifetime (%u)\n", tregen, tvalid);
2170Sstevel@tonic-gate 		rollback = _B_TRUE;
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if (rollback) {
2210Sstevel@tonic-gate 		(void) memcpy(cv, save, size);
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate int
parse_config(char * config_file,boolean_t file_required)2260Sstevel@tonic-gate parse_config(char *config_file, boolean_t file_required)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	FILE *fp;
2290Sstevel@tonic-gate 	char line[MAXLINELEN];
2300Sstevel@tonic-gate 	char pline[MAXLINELEN];
2310Sstevel@tonic-gate 	int argcount;
2320Sstevel@tonic-gate 	char *argvec[MAXARGSPERLINE];
2330Sstevel@tonic-gate 	int defaultdone = 0;	/* Set when first non-default command found */
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	if (debug & D_CONFIG)
2360Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_config()\n");
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	set_protocol_defaults();
2390Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
2400Sstevel@tonic-gate 		print_defaults();
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	fp = open_conffile(config_file);
2430Sstevel@tonic-gate 	if (fp == NULL) {
2440Sstevel@tonic-gate 		if (errno == ENOENT && !file_required)
2450Sstevel@tonic-gate 			return (0);
2460Sstevel@tonic-gate 		logperror(config_file);
2470Sstevel@tonic-gate 		return (-1);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 	while (readline(fp, line, sizeof (line)) != 0) {
2500Sstevel@tonic-gate 		(void) strncpy(pline, line, sizeof (pline));
2510Sstevel@tonic-gate 		pline[sizeof (pline) - 1] = '\0';	/* NULL terminate */
2520Sstevel@tonic-gate 		argcount = parse_line(pline, argvec,
2530Sstevel@tonic-gate 		    sizeof (argvec) / sizeof (argvec[0]));
2540Sstevel@tonic-gate 		if (debug & D_PARSE) {
2550Sstevel@tonic-gate 			int i;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "scanned %d args\n", argcount);
2580Sstevel@tonic-gate 			for (i = 0; i < argcount; i++)
2590Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "arg[%d]: %s\n",
2600Sstevel@tonic-gate 				    i, argvec[i]);
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 		if (argcount == 0) {
2630Sstevel@tonic-gate 			/* Empty line - or comment only line */
2640Sstevel@tonic-gate 			continue;
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 		if (strcmp(argvec[0], "ifdefault") == 0) {
2670Sstevel@tonic-gate 			char save[sizeof (ifdefaults)];
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 			if (defaultdone) {
2700Sstevel@tonic-gate 				conferr("ifdefault after non-default "
2710Sstevel@tonic-gate 				    "command\n");
2720Sstevel@tonic-gate 				continue;
2730Sstevel@tonic-gate 			}
2740Sstevel@tonic-gate 			/*
2750Sstevel@tonic-gate 			 * Save existing values in case what we read is
2760Sstevel@tonic-gate 			 * invalid and we need to restore previous settings.
2770Sstevel@tonic-gate 			 */
2780Sstevel@tonic-gate 			(void) memcpy(save, ifdefaults, sizeof (ifdefaults));
2790Sstevel@tonic-gate 			parse_default(CONFIG_IF, iflist, argvec+1, argcount-1,
2800Sstevel@tonic-gate 			    ifdefaults);
2810Sstevel@tonic-gate 			check_if_var_consistency(ifdefaults, save,
2820Sstevel@tonic-gate 			    sizeof (save));
2830Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "prefixdefault") == 0) {
2840Sstevel@tonic-gate 			char save[sizeof (prefixdefaults)];
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 			if (defaultdone) {
2870Sstevel@tonic-gate 				conferr("prefixdefault after non-default "
2880Sstevel@tonic-gate 				    "command\n");
2890Sstevel@tonic-gate 				continue;
2900Sstevel@tonic-gate 			}
2910Sstevel@tonic-gate 			/*
2920Sstevel@tonic-gate 			 * Save existing values in case what we read is
2930Sstevel@tonic-gate 			 * invalid and we need to restore previous settings.
2940Sstevel@tonic-gate 			 */
2950Sstevel@tonic-gate 			(void) memcpy(save, prefixdefaults,
2960Sstevel@tonic-gate 			    sizeof (prefixdefaults));
2970Sstevel@tonic-gate 			parse_default(CONFIG_PREFIX, prefixlist, argvec+1,
2980Sstevel@tonic-gate 			    argcount-1, prefixdefaults);
2990Sstevel@tonic-gate 			check_var_consistency(prefixdefaults, save,
3000Sstevel@tonic-gate 			    sizeof (save));
3010Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "if") == 0) {
3020Sstevel@tonic-gate 			defaultdone = 1;
3030Sstevel@tonic-gate 			parse_if(iflist, argvec+1, argcount-1);
3040Sstevel@tonic-gate 		} else if (strcmp(argvec[0], "prefix") == 0) {
3050Sstevel@tonic-gate 			defaultdone = 1;
3060Sstevel@tonic-gate 			parse_prefix(prefixlist, argvec+1, argcount-1);
3070Sstevel@tonic-gate 		} else {
3080Sstevel@tonic-gate 			conferr("Unknown command: %s\n", argvec[0]);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 	(void) fclose(fp);
3120Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
3130Sstevel@tonic-gate 		print_defaults();
3140Sstevel@tonic-gate 	return (0);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate  * Extract the defaults from the configinfo tables to initialize
3190Sstevel@tonic-gate  * the ifdefaults and prefixdefaults arrays.
3200Sstevel@tonic-gate  * The arrays are needed to track which defaults have been changed
3210Sstevel@tonic-gate  * by the config file.
3220Sstevel@tonic-gate  */
3230Sstevel@tonic-gate static void
set_protocol_defaults(void)3240Sstevel@tonic-gate set_protocol_defaults(void)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	struct configinfo *cip;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (debug & D_DEFAULTS)
3290Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "extract_protocol_defaults\n");
3300Sstevel@tonic-gate 	for (cip = iflist; cip->ci_name != NULL; cip++) {
3310Sstevel@tonic-gate 		ifdefaults[cip->ci_index].cf_value = cip->ci_default;
3320Sstevel@tonic-gate 		ifdefaults[cip->ci_index].cf_notdefault = _B_FALSE;
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 	for (cip = prefixlist; cip->ci_name != NULL; cip++) {
3350Sstevel@tonic-gate 		prefixdefaults[cip->ci_index].cf_value = cip->ci_default;
3360Sstevel@tonic-gate 		prefixdefaults[cip->ci_index].cf_notdefault = _B_FALSE;
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate void
print_iflist(struct confvar * confvar)3410Sstevel@tonic-gate print_iflist(struct confvar *confvar)
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	struct configinfo *cip;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	for (cip = iflist; cip->ci_name != NULL; cip++) {
3460Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\t%s min %u max %u def %u value %u set %d\n",
3470Sstevel@tonic-gate 		    cip->ci_name, cip->ci_min, cip->ci_max, cip->ci_default,
3480Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_value,
3490Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_notdefault);
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate void
print_prefixlist(struct confvar * confvar)3540Sstevel@tonic-gate print_prefixlist(struct confvar *confvar)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	struct configinfo *cip;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	for (cip = prefixlist; cip->ci_name != NULL; cip++) {
3590Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\t%s min %u max %u def %u value %u set %d\n",
3600Sstevel@tonic-gate 		    cip->ci_name, cip->ci_min, cip->ci_max, cip->ci_default,
3610Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_value,
3620Sstevel@tonic-gate 		    confvar[cip->ci_index].cf_notdefault);
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate static void
print_defaults(void)3680Sstevel@tonic-gate print_defaults(void)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Default interface variables:\n");
3710Sstevel@tonic-gate 	print_iflist(ifdefaults);
3720Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Default prefix variables:\n");
3730Sstevel@tonic-gate 	print_prefixlist(prefixdefaults);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate /*
3770Sstevel@tonic-gate  * Read from fp. Handle \ at the end of the line by joining lines together.
3780Sstevel@tonic-gate  * Return 0 on EOF.
3790Sstevel@tonic-gate  */
3800Sstevel@tonic-gate static int
readline(FILE * fp,char * line,int length)3810Sstevel@tonic-gate readline(FILE *fp, char *line, int length)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	int got = 0;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate retry:
3860Sstevel@tonic-gate 	errno = 0;
3870Sstevel@tonic-gate 	if (fgets(line, length, fp) == NULL) {
3880Sstevel@tonic-gate 		if (errno == EINTR)
3890Sstevel@tonic-gate 			goto retry;
3900Sstevel@tonic-gate 		if (got != 0)
3910Sstevel@tonic-gate 			return (1);
3920Sstevel@tonic-gate 		else
3930Sstevel@tonic-gate 			return (0);
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 	lineno++;
3960Sstevel@tonic-gate 	got = strlen(line);
3970Sstevel@tonic-gate 	/* Look for trailing \. Note that fgets includes the linefeed. */
3980Sstevel@tonic-gate 	if (got >= 2 && line[got-2] == '\\') {
3990Sstevel@tonic-gate 		/* Skip \ and LF */
4000Sstevel@tonic-gate 		line += got - 2;
4010Sstevel@tonic-gate 		length -= got - 2;
4020Sstevel@tonic-gate 		goto retry;
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate 	/* Remove the trailing linefeed */
4050Sstevel@tonic-gate 	if (got > 0)
4060Sstevel@tonic-gate 		line[got-1] = '\0';
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	return (1);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * Parse a line splitting it off at whitspace characters.
4130Sstevel@tonic-gate  * Modifies the content of the string by inserting NULLs.
4140Sstevel@tonic-gate  * If more arguments than fits in argvec/argcount then ignore the last.
4150Sstevel@tonic-gate  * Returns argcount.
4160Sstevel@tonic-gate  * Handles single quotes and double quotes.
4170Sstevel@tonic-gate  */
4180Sstevel@tonic-gate static int
parse_line(char * line,char * argvec[],int argcount)4190Sstevel@tonic-gate parse_line(char *line, char *argvec[], int argcount)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate 	int i = 0;
4220Sstevel@tonic-gate 	char *cp;
4230Sstevel@tonic-gate 	boolean_t insingle_quote = _B_FALSE;
4240Sstevel@tonic-gate 	boolean_t indouble_quote = _B_FALSE;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	/* Truncate at the beginning of a comment */
4270Sstevel@tonic-gate 	cp = strchr(line, '#');
4280Sstevel@tonic-gate 	if (cp != NULL)
4290Sstevel@tonic-gate 		*cp = '\0';
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	for (;;) {
4320Sstevel@tonic-gate 		/* Skip any whitespace */
4330Sstevel@tonic-gate 		while (isspace(*line) && *line != '\0')
4340Sstevel@tonic-gate 			line++;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		if (*line == '\'') {
4370Sstevel@tonic-gate 			line++;
4380Sstevel@tonic-gate 			if (*line == '\0')
4390Sstevel@tonic-gate 				return (i);
4400Sstevel@tonic-gate 			insingle_quote = _B_TRUE;
4410Sstevel@tonic-gate 		} else if (*line == '"') {
4420Sstevel@tonic-gate 			line++;
4430Sstevel@tonic-gate 			if (*line == '\0')
4440Sstevel@tonic-gate 				return (i);
4450Sstevel@tonic-gate 			indouble_quote = _B_TRUE;
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 		argvec[i] = line;
4480Sstevel@tonic-gate 		if (*line == '\0')
4490Sstevel@tonic-gate 			return (i);
4500Sstevel@tonic-gate 		i++;
4510Sstevel@tonic-gate 		/* Skip until next whitespace or end of quoted text */
4520Sstevel@tonic-gate 		if (insingle_quote) {
4530Sstevel@tonic-gate 			while (*line != '\'' && *line != '\0')
4540Sstevel@tonic-gate 				line++;
4550Sstevel@tonic-gate 			if (*line == '\'') {
4560Sstevel@tonic-gate 				*line = ' ';
4570Sstevel@tonic-gate 			} else {
4580Sstevel@tonic-gate 				/* Handle missing quote at end */
4590Sstevel@tonic-gate 				i--;
4600Sstevel@tonic-gate 				conferr("Missing end quote - ignoring <%s>\n",
4610Sstevel@tonic-gate 				    argvec[i]);
4620Sstevel@tonic-gate 				return (i);
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 			insingle_quote = _B_FALSE;
4650Sstevel@tonic-gate 		} else if (indouble_quote) {
4660Sstevel@tonic-gate 			while (*line != '"' && *line != '\0')
4670Sstevel@tonic-gate 				line++;
4680Sstevel@tonic-gate 			if (*line == '"') {
4690Sstevel@tonic-gate 				*line = ' ';
4700Sstevel@tonic-gate 			} else {
4710Sstevel@tonic-gate 				/* Handle missing quote at end */
4720Sstevel@tonic-gate 				i--;
4730Sstevel@tonic-gate 				conferr("Missing end quote - ignoring <%s>\n",
4740Sstevel@tonic-gate 				    argvec[i]);
4750Sstevel@tonic-gate 				return (i);
4760Sstevel@tonic-gate 			}
4770Sstevel@tonic-gate 			indouble_quote = _B_FALSE;
4780Sstevel@tonic-gate 		} else {
4790Sstevel@tonic-gate 			while (!isspace(*line) && *line != '\0')
4800Sstevel@tonic-gate 				line++;
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 		if (*line != '\0') {
4830Sstevel@tonic-gate 			/* Break off argument */
4840Sstevel@tonic-gate 			*line++ = '\0';
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 		if (i > argcount)
4870Sstevel@tonic-gate 			return (argcount);
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 	/* NOTREACHED */
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static void
parse_var_value(config_type_t type,struct configinfo * list,char * varstr,char * valstr,struct confvar * confvar)4930Sstevel@tonic-gate parse_var_value(config_type_t type, struct configinfo *list, char *varstr,
4940Sstevel@tonic-gate     char *valstr, struct confvar *confvar)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	struct configinfo *cip;
4970Sstevel@tonic-gate 	uint_t val;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	if (debug & D_CONFIG) {
5000Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_var_value(%d, %s, %s)\n",
5010Sstevel@tonic-gate 		    (int)type, varstr, valstr);
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	for (cip = list; cip->ci_name != NULL; cip++) {
5050Sstevel@tonic-gate 		if (strcasecmp(cip->ci_name, varstr) == 0)
5060Sstevel@tonic-gate 			break;
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 	if (cip->ci_name == NULL) {
5090Sstevel@tonic-gate 		conferr("Unknown variable: <%s>\n", varstr);
5100Sstevel@tonic-gate 		return;
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 	if (!(*cip->ci_parsefunc)(valstr, &val)) {
5130Sstevel@tonic-gate 		conferr("Bad value: <%s>\n", valstr);
5140Sstevel@tonic-gate 		return;
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 	if (cip->ci_min != 0 && val < cip->ci_min) {
5170Sstevel@tonic-gate 		conferr("Value %s is below minimum %u for %s\n",
5180Sstevel@tonic-gate 		    valstr, cip->ci_min, varstr);
5190Sstevel@tonic-gate 		return;
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 	if (cip->ci_max != ~0U && val > cip->ci_max) {
5220Sstevel@tonic-gate 		conferr("Value %s is above maximum %u for %s\n",
5230Sstevel@tonic-gate 		    valstr, cip->ci_max, varstr);
5240Sstevel@tonic-gate 		return;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 	/* Check against dynamic/relative limits */
5270Sstevel@tonic-gate 	if (type == CONFIG_IF) {
5280Sstevel@tonic-gate 		if (cip->ci_index == I_MinRtrAdvInterval &&
5290Sstevel@tonic-gate 		    confvar[I_MaxRtrAdvInterval].cf_notdefault &&
5300Sstevel@tonic-gate 		    val > confvar[I_MaxRtrAdvInterval].cf_value * 0.75) {
5310Sstevel@tonic-gate 			conferr("MinRtrAdvInterval exceeds .75 * "
5320Sstevel@tonic-gate 			    "MaxRtrAdvInterval (%u)\n",
5330Sstevel@tonic-gate 			    confvar[I_MaxRtrAdvInterval].cf_value);
5340Sstevel@tonic-gate 			return;
5350Sstevel@tonic-gate 		}
5360Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
5370Sstevel@tonic-gate 		    confvar[I_MinRtrAdvInterval].cf_notdefault &&
5380Sstevel@tonic-gate 		    confvar[I_MinRtrAdvInterval].cf_value > val * 0.75) {
5390Sstevel@tonic-gate 			conferr("MinRtrAdvInterval (%u) exceeds .75 * "
5400Sstevel@tonic-gate 			    "MaxRtrAdvInterval\n",
5410Sstevel@tonic-gate 			    confvar[I_MinRtrAdvInterval].cf_value);
5420Sstevel@tonic-gate 			return;
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 		if (cip->ci_index == I_AdvDefaultLifetime &&
5450Sstevel@tonic-gate 		    confvar[I_MaxRtrAdvInterval].cf_notdefault &&
5460Sstevel@tonic-gate 		    val != 0 &&
5470Sstevel@tonic-gate 		    val < confvar[I_MaxRtrAdvInterval].cf_value) {
5480Sstevel@tonic-gate 			conferr("AdvDefaultLifetime is not between "
5490Sstevel@tonic-gate 			    "MaxRtrAdrInterval (%u) and 9000 seconds\n",
5500Sstevel@tonic-gate 			    confvar[I_MaxRtrAdvInterval].cf_value);
5510Sstevel@tonic-gate 			return;
5520Sstevel@tonic-gate 		}
5530Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
5540Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_notdefault &&
5550Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_value < val) {
5560Sstevel@tonic-gate 			conferr("AdvDefaultLifetime (%u) is not between "
5570Sstevel@tonic-gate 			    "MaxRtrAdrInterval and 9000 seconds\n",
5580Sstevel@tonic-gate 			    confvar[I_AdvDefaultLifetime].cf_value);
5590Sstevel@tonic-gate 			return;
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	confvar[cip->ci_index].cf_value = val;
5630Sstevel@tonic-gate 	confvar[cip->ci_index].cf_notdefault = _B_TRUE;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/* Derive dynamic/relative variables based on this one */
5660Sstevel@tonic-gate 	if (type == CONFIG_IF) {
5670Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
5680Sstevel@tonic-gate 		    !confvar[I_MinRtrAdvInterval].cf_notdefault)
5690Sstevel@tonic-gate 			confvar[I_MinRtrAdvInterval].cf_value = val / 3;
5700Sstevel@tonic-gate 		if (cip->ci_index == I_MaxRtrAdvInterval &&
5710Sstevel@tonic-gate 		    !confvar[I_AdvDefaultLifetime].cf_notdefault)
5720Sstevel@tonic-gate 		    confvar[I_AdvDefaultLifetime].cf_value = 3 * val;
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate  * Split up the line into <variable> <value> pairs
5780Sstevel@tonic-gate  */
5790Sstevel@tonic-gate static void
parse_default(config_type_t type,struct configinfo * list,char * argvec[],int argcount,struct confvar * defaults)5800Sstevel@tonic-gate parse_default(config_type_t type, struct configinfo *list,
5810Sstevel@tonic-gate     char *argvec[], int argcount, struct confvar *defaults)
5820Sstevel@tonic-gate {
5830Sstevel@tonic-gate 	if (debug & D_CONFIG)
5840Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_default: argc %d\n", argcount);
5850Sstevel@tonic-gate 	while (argcount >= 2) {
5860Sstevel@tonic-gate 		parse_var_value(type, list, argvec[0], argvec[1], defaults);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		argcount -= 2;
5890Sstevel@tonic-gate 		argvec += 2;
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 	if (argcount != 0)
5920Sstevel@tonic-gate 		conferr("Trailing text <%s> ignored\n", argvec[0]);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * Returns true if ok; otherwise false.
5970Sstevel@tonic-gate  */
5980Sstevel@tonic-gate static void
parse_if(struct configinfo * list,char * argvec[],int argcount)5990Sstevel@tonic-gate parse_if(struct configinfo *list, char *argvec[], int argcount)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	char *ifname;
6020Sstevel@tonic-gate 	struct phyint *pi;
6030Sstevel@tonic-gate 	char save[sizeof (pi->pi_config)];
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	if (debug & D_CONFIG)
6060Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_if: argc %d\n", argcount);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (argcount < 1) {
6090Sstevel@tonic-gate 		conferr("Missing interface name\n");
6100Sstevel@tonic-gate 		return;
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 	ifname = argvec[0];
6130Sstevel@tonic-gate 	argvec++;
6140Sstevel@tonic-gate 	argcount--;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
6170Sstevel@tonic-gate 	if (pi == NULL) {
6180Sstevel@tonic-gate 		/*
6190Sstevel@tonic-gate 		 * Create the physical interface structure.
6200Sstevel@tonic-gate 		 * Note, phyint_create() sets the interface
6210Sstevel@tonic-gate 		 * defaults in pi_config.
6220Sstevel@tonic-gate 		 */
6230Sstevel@tonic-gate 		pi = phyint_create(ifname);
6240Sstevel@tonic-gate 		if (pi == NULL) {
6250Sstevel@tonic-gate 			conferr("Unable to use interface %s\n", ifname);
6260Sstevel@tonic-gate 			return;
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	(void) memcpy(save, pi->pi_config, sizeof (save));
6310Sstevel@tonic-gate 	while (argcount >= 2) {
6320Sstevel@tonic-gate 		parse_var_value(CONFIG_IF, list, argvec[0], argvec[1],
6330Sstevel@tonic-gate 		    pi->pi_config);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		argcount -= 2;
6360Sstevel@tonic-gate 		argvec += 2;
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 	if (argcount != 0)
6390Sstevel@tonic-gate 		logmsg(LOG_ERR, "Trailing text <%s> ignored\n", argvec[0]);
6400Sstevel@tonic-gate 	check_if_var_consistency(pi->pi_config, save, sizeof (save));
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate static void
parse_prefix(struct configinfo * list,char * argvec[],int argcount)6440Sstevel@tonic-gate parse_prefix(struct configinfo *list, char *argvec[], int argcount)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	char *ifname, *prefix;
6470Sstevel@tonic-gate 	struct phyint *pi;
6480Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
6490Sstevel@tonic-gate 	struct in6_addr in6;
6500Sstevel@tonic-gate 	int prefixlen;
6510Sstevel@tonic-gate 	char save[sizeof (adv_pr->adv_pr_config)];
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (debug & D_CONFIG)
6540Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_prefix: argc %d\n", argcount);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (argcount < 2) {
6570Sstevel@tonic-gate 		conferr("Missing prefix and/or interface name\n");
6580Sstevel@tonic-gate 		return;
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 	prefix = argvec[0];
6610Sstevel@tonic-gate 	ifname = argvec[1];
6620Sstevel@tonic-gate 	argvec += 2;
6630Sstevel@tonic-gate 	argcount -= 2;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	prefixlen = parse_addrprefix(prefix, &in6);
6660Sstevel@tonic-gate 	if (prefixlen == -1) {
6670Sstevel@tonic-gate 		conferr("Bad prefix %s\n", prefix);
6680Sstevel@tonic-gate 		return;
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
6720Sstevel@tonic-gate 	if (pi == NULL) {
6730Sstevel@tonic-gate 		/*
6740Sstevel@tonic-gate 		 * Create the physical interface structure.
6750Sstevel@tonic-gate 		 * Note, phyint_create() sets the interface
6760Sstevel@tonic-gate 		 * defaults in pi_config.
6770Sstevel@tonic-gate 		 */
6780Sstevel@tonic-gate 		pi = phyint_create(ifname);
6790Sstevel@tonic-gate 		if (pi == NULL) {
6800Sstevel@tonic-gate 			conferr("Unable to use interface %s\n", ifname);
6810Sstevel@tonic-gate 			return;
6820Sstevel@tonic-gate 		}
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 	adv_pr = adv_prefix_lookup(pi, in6, prefixlen);
6850Sstevel@tonic-gate 	if (adv_pr == NULL) {
6860Sstevel@tonic-gate 		int i;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 		adv_pr = adv_prefix_create(pi, in6, prefixlen);
6890Sstevel@tonic-gate 		if (adv_pr == NULL) {
6900Sstevel@tonic-gate 			conferr("Unable to create prefix %s\n", prefix);
6910Sstevel@tonic-gate 			return;
6920Sstevel@tonic-gate 		}
6930Sstevel@tonic-gate 		/*
6940Sstevel@tonic-gate 		 * Copy the defaults from the default array.
6950Sstevel@tonic-gate 		 */
6960Sstevel@tonic-gate 		for (i = 0; i < I_PREFIXSIZE; i++) {
6970Sstevel@tonic-gate 			adv_pr->adv_pr_config[i].cf_value =
6980Sstevel@tonic-gate 			    prefixdefaults[i].cf_value;
6990Sstevel@tonic-gate 			adv_pr->adv_pr_config[i].cf_notdefault =
7000Sstevel@tonic-gate 			    prefixdefaults[i].cf_notdefault;
7010Sstevel@tonic-gate 		}
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	(void) memcpy(save, adv_pr->adv_pr_config, sizeof (save));
7050Sstevel@tonic-gate 	while (argcount >= 2) {
7060Sstevel@tonic-gate 		parse_var_value(CONFIG_PREFIX, list, argvec[0], argvec[1],
7070Sstevel@tonic-gate 		    adv_pr->adv_pr_config);
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 		argcount -= 2;
7100Sstevel@tonic-gate 		argvec += 2;
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 	check_var_consistency(adv_pr->adv_pr_config, save, sizeof (save));
7130Sstevel@tonic-gate 	if (argcount != 0)
7140Sstevel@tonic-gate 		logmsg(LOG_ERR, "Trailing text <%s> ignored\n", argvec[0]);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate /*
7180Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
7190Sstevel@tonic-gate  */
7200Sstevel@tonic-gate static boolean_t
parse_onoff(char * str,uint_t * resp)7210Sstevel@tonic-gate parse_onoff(char *str, uint_t *resp)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	if (strcasecmp(str, "on") == 0) {
7240Sstevel@tonic-gate 		*resp = 1;
7250Sstevel@tonic-gate 		return (_B_TRUE);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 	if (strcasecmp(str, "off") == 0) {
7280Sstevel@tonic-gate 		*resp = 0;
7290Sstevel@tonic-gate 		return (_B_TRUE);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 	if (strcasecmp(str, "true") == 0) {
7320Sstevel@tonic-gate 		*resp = 1;
7330Sstevel@tonic-gate 		return (_B_TRUE);
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 	if (strcasecmp(str, "false") == 0) {
7360Sstevel@tonic-gate 		*resp = 0;
7370Sstevel@tonic-gate 		return (_B_TRUE);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 	if (parse_int(str, resp)) {
7400Sstevel@tonic-gate 		if (*resp == 0 || *resp == 1)
7410Sstevel@tonic-gate 			return (_B_TRUE);
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 	return (_B_FALSE);
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate /*
7470Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
7480Sstevel@tonic-gate  */
7490Sstevel@tonic-gate static boolean_t
parse_int(char * str,uint_t * resp)7500Sstevel@tonic-gate parse_int(char *str, uint_t *resp)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	char *end;
7530Sstevel@tonic-gate 	int res;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	res = strtoul(str, &end, 0);
7560Sstevel@tonic-gate 	if (end == str)
7570Sstevel@tonic-gate 		return (_B_FALSE);
7580Sstevel@tonic-gate 	*resp = res;
7590Sstevel@tonic-gate 	return (_B_TRUE);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate  * Parse something with a unit of millseconds.
7640Sstevel@tonic-gate  * Regognizes the suffixes "ms", "s", "m", "h", and "d".
7650Sstevel@tonic-gate  *
7660Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
7670Sstevel@tonic-gate  */
7680Sstevel@tonic-gate static boolean_t
parse_ms(char * str,uint_t * resp)7690Sstevel@tonic-gate parse_ms(char *str, uint_t *resp)
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	/* Look at the last and next to last character */
7720Sstevel@tonic-gate 	char *cp, *last, *nlast;
7730Sstevel@tonic-gate 	char str2[BUFSIZ];	/* For local modification */
7740Sstevel@tonic-gate 	int multiplier = 1;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	(void) strncpy(str2, str, sizeof (str2));
7770Sstevel@tonic-gate 	str2[sizeof (str2) - 1] = '\0';
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	last = str2;
7800Sstevel@tonic-gate 	nlast = NULL;
7810Sstevel@tonic-gate 	for (cp = str2; *cp != '\0'; cp++) {
7820Sstevel@tonic-gate 		nlast = last;
7830Sstevel@tonic-gate 		last = cp;
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 	if (debug & D_PARSE) {
7860Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_ms: last <%c> nlast <%c>\n",
7870Sstevel@tonic-gate 		    (last != NULL ? *last : ' '),
7880Sstevel@tonic-gate 		    (nlast != NULL ? *nlast : ' '));
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 	switch (*last) {
7910Sstevel@tonic-gate 	case 'd':
7920Sstevel@tonic-gate 		multiplier *= 24;
7930Sstevel@tonic-gate 		/* FALLTHRU */
7940Sstevel@tonic-gate 	case 'h':
7950Sstevel@tonic-gate 		multiplier *= 60;
7960Sstevel@tonic-gate 		/* FALLTHRU */
7970Sstevel@tonic-gate 	case 'm':
7980Sstevel@tonic-gate 		multiplier *= 60;
7990Sstevel@tonic-gate 		*last = '\0';
8000Sstevel@tonic-gate 		multiplier *= 1000;	/* Convert to milliseconds */
8010Sstevel@tonic-gate 		break;
8020Sstevel@tonic-gate 	case 's':
8030Sstevel@tonic-gate 		/* Could be "ms" or "s" */
8040Sstevel@tonic-gate 		if (nlast != NULL && *nlast == 'm') {
8050Sstevel@tonic-gate 			/* "ms" */
8060Sstevel@tonic-gate 			*nlast = '\0';
8070Sstevel@tonic-gate 		} else {
8080Sstevel@tonic-gate 			*last = '\0';
8090Sstevel@tonic-gate 			multiplier *= 1000;	/* Convert to milliseconds */
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (!parse_int(str2, resp))
8150Sstevel@tonic-gate 		return (_B_FALSE);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	*resp *= multiplier;
8180Sstevel@tonic-gate 	return (_B_TRUE);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate  * Parse something with a unit of seconds.
8230Sstevel@tonic-gate  * Regognizes the suffixes "s", "m", "h", and "d".
8240Sstevel@tonic-gate  *
8250Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
8260Sstevel@tonic-gate  */
8270Sstevel@tonic-gate static boolean_t
parse_s(char * str,uint_t * resp)8280Sstevel@tonic-gate parse_s(char *str, uint_t *resp)
8290Sstevel@tonic-gate {
8300Sstevel@tonic-gate 	/* Look at the last character */
8310Sstevel@tonic-gate 	char *cp, *last;
8320Sstevel@tonic-gate 	char str2[BUFSIZ];	/* For local modification */
8330Sstevel@tonic-gate 	int multiplier = 1;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	(void) strncpy(str2, str, sizeof (str2));
8360Sstevel@tonic-gate 	str2[sizeof (str2) - 1] = '\0';
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	last = str2;
8390Sstevel@tonic-gate 	for (cp = str2; *cp != '\0'; cp++) {
8400Sstevel@tonic-gate 		last = cp;
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 	if (debug & D_PARSE) {
8430Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_s: last <%c>\n",
8440Sstevel@tonic-gate 		    (last != NULL ? *last : ' '));
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 	switch (*last) {
8470Sstevel@tonic-gate 	case 'd':
8480Sstevel@tonic-gate 		multiplier *= 24;
8490Sstevel@tonic-gate 		/* FALLTHRU */
8500Sstevel@tonic-gate 	case 'h':
8510Sstevel@tonic-gate 		multiplier *= 60;
8520Sstevel@tonic-gate 		/* FALLTHRU */
8530Sstevel@tonic-gate 	case 'm':
8540Sstevel@tonic-gate 		multiplier *= 60;
8550Sstevel@tonic-gate 		/* FALLTHRU */
8560Sstevel@tonic-gate 	case 's':
8570Sstevel@tonic-gate 		*last = '\0';
8580Sstevel@tonic-gate 		break;
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 	if (!parse_int(str2, resp))
8610Sstevel@tonic-gate 		return (_B_FALSE);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	*resp *= multiplier;
8640Sstevel@tonic-gate 	return (_B_TRUE);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate  * Return prefixlen (0 to 128) if ok; -1 if failed.
8690Sstevel@tonic-gate  */
8700Sstevel@tonic-gate static int
parse_addrprefix(char * strin,struct in6_addr * in6)8710Sstevel@tonic-gate parse_addrprefix(char *strin, struct in6_addr *in6)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate 	char str[BUFSIZ];	/* Local copy for modification */
8740Sstevel@tonic-gate 	int prefixlen;
8750Sstevel@tonic-gate 	char *cp;
8760Sstevel@tonic-gate 	char *end;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	(void) strncpy(str, strin, sizeof (str));
8790Sstevel@tonic-gate 	str[sizeof (str) - 1] = '\0';
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	cp = strchr(str, '/');
8820Sstevel@tonic-gate 	if (cp == NULL)
8830Sstevel@tonic-gate 		return (-1);
8840Sstevel@tonic-gate 	*cp = '\0';
8850Sstevel@tonic-gate 	cp++;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	prefixlen = strtol(cp, &end, 10);
8880Sstevel@tonic-gate 	if (cp == end)
8890Sstevel@tonic-gate 		return (-1);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (prefixlen < 0 || prefixlen > IPV6_ABITS)
8920Sstevel@tonic-gate 		return (-1);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	if (inet_pton(AF_INET6, str, in6) != 1)
8950Sstevel@tonic-gate 		return (-1);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	return (prefixlen);
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate /*
9010Sstevel@tonic-gate  * Parse an absolute date using a datemsk config file.
9020Sstevel@tonic-gate  * Return the difference (measured in seconds) between that date/time and
9030Sstevel@tonic-gate  * the current date/time.
9040Sstevel@tonic-gate  * If the date has passed return zero.
9050Sstevel@tonic-gate  *
9060Sstevel@tonic-gate  * Returns true if ok (and *resp updated) and false if failed.
9070Sstevel@tonic-gate  * XXX Due to getdate limitations can not exceed year 2038.
9080Sstevel@tonic-gate  */
9090Sstevel@tonic-gate static boolean_t
parse_date(char * str,uint_t * resp)9100Sstevel@tonic-gate parse_date(char *str, uint_t *resp)
9110Sstevel@tonic-gate {
9120Sstevel@tonic-gate 	struct tm *tm;
9130Sstevel@tonic-gate 	struct timeval tvs;
9140Sstevel@tonic-gate 	time_t time, ntime;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	if (getenv("DATEMSK") == NULL) {
9170Sstevel@tonic-gate 		(void) putenv("DATEMSK=/etc/inet/datemsk.ndpd");
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	if (gettimeofday(&tvs, NULL) < 0) {
9210Sstevel@tonic-gate 		logperror("gettimeofday");
9220Sstevel@tonic-gate 		return (_B_FALSE);
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 	time = tvs.tv_sec;
9250Sstevel@tonic-gate 	tm = getdate(str);
9260Sstevel@tonic-gate 	if (tm == NULL) {
9270Sstevel@tonic-gate 		logmsg(LOG_ERR, "Bad date <%s> (error %d)\n",
9280Sstevel@tonic-gate 		    str, getdate_err);
9290Sstevel@tonic-gate 		return (_B_FALSE);
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	ntime = mktime(tm);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	if (debug & D_PARSE) {
9350Sstevel@tonic-gate 		char buf[BUFSIZ];
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 		(void) strftime(buf, sizeof (buf), "%Y-%m-%d %R %Z", tm);
9380Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "parse_date: <%s>, delta %ld seconds\n",
9390Sstevel@tonic-gate 		    buf, ntime - time);
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	if (ntime < time) {
9420Sstevel@tonic-gate 		conferr("Date in the past <%s>\n", str);
9430Sstevel@tonic-gate 		*resp = 0;
9440Sstevel@tonic-gate 		return (_B_TRUE);
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 	*resp = (ntime - time);
9470Sstevel@tonic-gate 	return (_B_TRUE);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate /* PRINTFLIKE1 */
9510Sstevel@tonic-gate static void
conferr(char * fmt,...)9520Sstevel@tonic-gate conferr(char *fmt, ...)
9530Sstevel@tonic-gate {
9540Sstevel@tonic-gate 	char msg[NDPD_LOGMSGSIZE];
9550Sstevel@tonic-gate 	size_t slen;
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	va_list ap;
9580Sstevel@tonic-gate 	va_start(ap, fmt);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	(void) snprintf(msg, NDPD_LOGMSGSIZE, "%s line %d: ",
9610Sstevel@tonic-gate 	    conf_filename, lineno);
9620Sstevel@tonic-gate 	slen = strlen(msg);
9630Sstevel@tonic-gate 	(void) vsnprintf(msg + slen, NDPD_LOGMSGSIZE - slen, fmt, ap);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	logmsg(LOG_ERR, "%s", msg);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	va_end(ap);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate static FILE *
open_conffile(char * filename)9710Sstevel@tonic-gate open_conffile(char *filename)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate 	if (strlcpy(conf_filename, filename, MAXPATHLEN) >= MAXPATHLEN) {
9740Sstevel@tonic-gate 		logmsg(LOG_ERR, "config file pathname is too long\n");
9750Sstevel@tonic-gate 		return (NULL);
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	lineno = 0;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	return (fopen(filename, "r"));
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate }
983