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