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