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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
32 * Parse the config file which consists of entries of the form:
33 * ifdefault [<variable> <value>]*
34 * prefixdefault [<variable> <value>]*
35 * if <ifname> [<variable> <value>]*
36 * prefix <prefix>/<length> <ifname> [<variable> <value>]*
38 * All "ifdefault" and "prefixdefault" entries must preceed any
39 * "if" and "prefix" entries.
41 * Values (such as expiry dates) which contain white space
42 * can be quoted with single or double quotes.
45 /* maximum length of messages we send to syslog */
46 #define NDPD_LOGMSGSIZE 1024
47 typedef boolean_t (*pfb_t
)(char *, uint_t
*);
51 uint_t ci_min
; /* 0: no min check */
52 uint_t ci_max
; /* ~0U: no max check */
54 uint_t ci_index
; /* Into result array */
55 pfb_t ci_parsefunc
; /* Parse function returns -1 on failure */
58 enum config_type
{ CONFIG_IF
, CONFIG_PREFIX
};
59 typedef enum config_type config_type_t
;
61 static void set_protocol_defaults(void);
62 static void print_defaults(void);
63 static void parse_var_value(config_type_t
, struct configinfo
*, char *, char *,
65 static void parse_default(config_type_t
, struct configinfo
*, char **, int,
67 static void parse_if(struct configinfo
*, char **, int);
68 static void parse_prefix(struct configinfo
*, char **, int);
69 static boolean_t
parse_onoff(char *, uint_t
*); /* boolean */
70 static boolean_t
parse_int(char *, uint_t
*); /* integer */
71 static boolean_t
parse_ms(char *, uint_t
*); /* milliseconds */
72 static boolean_t
parse_s(char *, uint_t
*); /* seconds */
73 static boolean_t
parse_date(char *, uint_t
*); /* date format */
74 static void conferr(char *fmt
, ...);
75 static FILE *open_conffile(char *filename
);
76 static int parse_line(char *line
, char *argvec
[], int argcount
);
77 static int readline(FILE *fp
, char *line
, int length
);
78 static int parse_addrprefix(char *strin
, struct in6_addr
*in6
);
81 * Per interface configuration variables.
82 * Min, max, and default values are from RFC 2461.
84 static struct configinfo iflist
[] = {
85 /* Name, Min, Max, Default, Index */
86 { "DupAddrDetectTransmits", 0, 100, 1, I_DupAddrDetectTransmits
,
88 { "AdvSendAdvertisements", 0, 1, 0, I_AdvSendAdvertisements
,
90 { "MaxRtrAdvInterval", 4, 1800, 600, I_MaxRtrAdvInterval
, parse_s
},
91 { "MinRtrAdvInterval", 3, 1350, 200, I_MinRtrAdvInterval
, parse_s
},
93 * No greater than .75 * MaxRtrAdvInterval.
94 * Default: 0.33 * MaxRtrAdvInterval
96 { "AdvManagedFlag", 0, 1, 0, I_AdvManagedFlag
, parse_onoff
},
97 { "AdvOtherConfigFlag", 0, 1, 0, I_AdvOtherConfigFlag
, parse_onoff
},
98 { "AdvLinkMTU", IPV6_MIN_MTU
, 65535, 0, I_AdvLinkMTU
, parse_int
},
99 { "AdvReachableTime", 0, 3600000, 0, I_AdvReachableTime
, parse_ms
},
100 { "AdvRetransTimer", 0, ~0U, 0, I_AdvRetransTimer
, parse_ms
},
101 { "AdvCurHopLimit", 0, 255, 0, I_AdvCurHopLimit
, parse_int
},
102 { "AdvDefaultLifetime", 0, 9000, 1800, I_AdvDefaultLifetime
, parse_s
},
104 * MUST be either zero or between MaxRtrAdvInterval and 9000 seconds.
105 * Default: 3 * MaxRtrAdvInterval
107 { "StatelessAddrConf", 0, 1, 1, I_StatelessAddrConf
, parse_onoff
},
108 { "StatefulAddrConf", 0, 1, 1, I_StatefulAddrConf
, parse_onoff
},
110 * Tmp* variables from RFC 3041, where defaults are defined.
112 { "TmpAddrsEnabled", 0, 1, 0, I_TmpAddrsEnabled
, parse_onoff
},
113 { "TmpValidLifetime", 0, ~0U, 604800, I_TmpValidLifetime
, parse_s
},
114 { "TmpPreferredLifetime", 0, ~0U, 86400, I_TmpPreferredLifetime
,
116 { "TmpRegenAdvance", 0, 60, 5, I_TmpRegenAdvance
, parse_s
},
117 { "TmpMaxDesyncFactor", 0, 600, 600, I_TmpMaxDesyncFactor
, parse_s
},
122 * Per prefix: AdvPrefixList configuration variables.
123 * Min, max, and default values are from RFC 2461.
125 static struct configinfo prefixlist
[] = {
126 /* Name, Min, Max, Default, Index */
127 { "AdvValidLifetime", 0, ~0U, 2592000, I_AdvValidLifetime
,
129 { "AdvOnLinkFlag", 0, 1, 1, I_AdvOnLinkFlag
, parse_onoff
},
130 { "AdvPreferredLifetime", 0, ~0U, 604800, I_AdvPreferredLifetime
,
132 { "AdvAutonomousFlag", 0, 1, 1, I_AdvAutonomousFlag
, parse_onoff
},
133 { "AdvValidExpiration", 0, ~0U, 0, I_AdvValidExpiration
,
135 { "AdvPreferredExpiration", 0, ~0U, 0, I_AdvPreferredExpiration
,
137 { NULL
, 0, 0, 0, 0 },
141 * Data structures used to merge above protocol defaults
142 * with defaults specified in the configuration file.
143 * ifdefault is not static because new interfaces can be
144 * created outside of the configuration context.
146 struct confvar ifdefaults
[I_IFSIZE
];
147 static struct confvar prefixdefaults
[I_PREFIXSIZE
];
149 static char conf_filename
[MAXPATHLEN
];
153 * Checks for violations of section 5.5.3 (c) of RFC 2462.
156 check_var_consistency(struct confvar
*cv
, void *save
, int size
)
158 boolean_t rollback
= _B_FALSE
;
159 int prefl
, prefe
, valid
;
161 prefl
= cv
[I_AdvPreferredLifetime
].cf_value
;
162 prefe
= cv
[I_AdvPreferredExpiration
].cf_value
;
163 valid
= cv
[I_AdvValidLifetime
].cf_value
;
166 conferr("AdvPreferredLifetime (%u) is greater than "
167 "valid lifetime (%u)\n", prefl
, valid
);
172 conferr("AdvPreferredExpiration (%u) is greater than "
173 "valid lifetime (%u)\n", prefe
, valid
);
178 (void) memcpy(cv
, save
, size
);
183 * Check for invalid lifetime values for RFC3041 addresses
186 check_if_var_consistency(struct confvar
*cv
, void *save
, int size
)
188 boolean_t rollback
= _B_FALSE
;
189 int tpref
, tvalid
, tdesync
, tregen
;
191 tpref
= cv
[I_TmpPreferredLifetime
].cf_value
;
192 tvalid
= cv
[I_TmpValidLifetime
].cf_value
;
193 tdesync
= cv
[I_TmpMaxDesyncFactor
].cf_value
;
194 tregen
= cv
[I_TmpRegenAdvance
].cf_value
;
197 * Only need to do this if tmp addrs are enabled.
199 if (cv
[I_TmpAddrsEnabled
].cf_value
== 0)
202 if (tdesync
> tpref
) {
203 conferr("TmpDesyncFactor (%u) is greater than "
204 "TmpPreferredLifetime (%u)\n", tdesync
, tpref
);
208 if (tpref
> tvalid
) {
209 conferr("TmpPreferredLifetime (%u) is greater than "
210 "TmpValidLifetime (%u)\n", tpref
, tvalid
);
214 if (tregen
> tvalid
) {
215 conferr("TmpRegenAdvance (%u) is greater than "
216 "TmpValidLifetime (%u)\n", tregen
, tvalid
);
221 (void) memcpy(cv
, save
, size
);
226 parse_config(char *config_file
, boolean_t file_required
)
229 char line
[MAXLINELEN
];
230 char pline
[MAXLINELEN
];
232 char *argvec
[MAXARGSPERLINE
];
233 int defaultdone
= 0; /* Set when first non-default command found */
235 if (debug
& D_CONFIG
)
236 logmsg(LOG_DEBUG
, "parse_config()\n");
238 set_protocol_defaults();
239 if (debug
& D_DEFAULTS
)
242 fp
= open_conffile(config_file
);
244 if (errno
== ENOENT
&& !file_required
)
246 logperror(config_file
);
249 while (readline(fp
, line
, sizeof (line
)) != 0) {
250 (void) strncpy(pline
, line
, sizeof (pline
));
251 pline
[sizeof (pline
) - 1] = '\0'; /* NULL terminate */
252 argcount
= parse_line(pline
, argvec
,
253 sizeof (argvec
) / sizeof (argvec
[0]));
254 if (debug
& D_PARSE
) {
257 logmsg(LOG_DEBUG
, "scanned %d args\n", argcount
);
258 for (i
= 0; i
< argcount
; i
++)
259 logmsg(LOG_DEBUG
, "arg[%d]: %s\n",
263 /* Empty line - or comment only line */
266 if (strcmp(argvec
[0], "ifdefault") == 0) {
267 char save
[sizeof (ifdefaults
)];
270 conferr("ifdefault after non-default "
275 * Save existing values in case what we read is
276 * invalid and we need to restore previous settings.
278 (void) memcpy(save
, ifdefaults
, sizeof (ifdefaults
));
279 parse_default(CONFIG_IF
, iflist
, argvec
+1, argcount
-1,
281 check_if_var_consistency(ifdefaults
, save
,
283 } else if (strcmp(argvec
[0], "prefixdefault") == 0) {
284 char save
[sizeof (prefixdefaults
)];
287 conferr("prefixdefault after non-default "
292 * Save existing values in case what we read is
293 * invalid and we need to restore previous settings.
295 (void) memcpy(save
, prefixdefaults
,
296 sizeof (prefixdefaults
));
297 parse_default(CONFIG_PREFIX
, prefixlist
, argvec
+1,
298 argcount
-1, prefixdefaults
);
299 check_var_consistency(prefixdefaults
, save
,
301 } else if (strcmp(argvec
[0], "if") == 0) {
303 parse_if(iflist
, argvec
+1, argcount
-1);
304 } else if (strcmp(argvec
[0], "prefix") == 0) {
306 parse_prefix(prefixlist
, argvec
+1, argcount
-1);
308 conferr("Unknown command: %s\n", argvec
[0]);
312 if (debug
& D_DEFAULTS
)
318 * Extract the defaults from the configinfo tables to initialize
319 * the ifdefaults and prefixdefaults arrays.
320 * The arrays are needed to track which defaults have been changed
321 * by the config file.
324 set_protocol_defaults(void)
326 struct configinfo
*cip
;
328 if (debug
& D_DEFAULTS
)
329 logmsg(LOG_DEBUG
, "extract_protocol_defaults\n");
330 for (cip
= iflist
; cip
->ci_name
!= NULL
; cip
++) {
331 ifdefaults
[cip
->ci_index
].cf_value
= cip
->ci_default
;
332 ifdefaults
[cip
->ci_index
].cf_notdefault
= _B_FALSE
;
334 for (cip
= prefixlist
; cip
->ci_name
!= NULL
; cip
++) {
335 prefixdefaults
[cip
->ci_index
].cf_value
= cip
->ci_default
;
336 prefixdefaults
[cip
->ci_index
].cf_notdefault
= _B_FALSE
;
341 print_iflist(struct confvar
*confvar
)
343 struct configinfo
*cip
;
345 for (cip
= iflist
; cip
->ci_name
!= NULL
; cip
++) {
346 logmsg(LOG_DEBUG
, "\t%s min %u max %u def %u value %u set %d\n",
347 cip
->ci_name
, cip
->ci_min
, cip
->ci_max
, cip
->ci_default
,
348 confvar
[cip
->ci_index
].cf_value
,
349 confvar
[cip
->ci_index
].cf_notdefault
);
354 print_prefixlist(struct confvar
*confvar
)
356 struct configinfo
*cip
;
358 for (cip
= prefixlist
; cip
->ci_name
!= NULL
; cip
++) {
359 logmsg(LOG_DEBUG
, "\t%s min %u max %u def %u value %u set %d\n",
360 cip
->ci_name
, cip
->ci_min
, cip
->ci_max
, cip
->ci_default
,
361 confvar
[cip
->ci_index
].cf_value
,
362 confvar
[cip
->ci_index
].cf_notdefault
);
370 logmsg(LOG_DEBUG
, "Default interface variables:\n");
371 print_iflist(ifdefaults
);
372 logmsg(LOG_DEBUG
, "Default prefix variables:\n");
373 print_prefixlist(prefixdefaults
);
377 * Read from fp. Handle \ at the end of the line by joining lines together.
381 readline(FILE *fp
, char *line
, int length
)
387 if (fgets(line
, length
, fp
) == NULL
) {
397 /* Look for trailing \. Note that fgets includes the linefeed. */
398 if (got
>= 2 && line
[got
-2] == '\\') {
404 /* Remove the trailing linefeed */
412 * Parse a line splitting it off at whitspace characters.
413 * Modifies the content of the string by inserting NULLs.
414 * If more arguments than fits in argvec/argcount then ignore the last.
416 * Handles single quotes and double quotes.
419 parse_line(char *line
, char *argvec
[], int argcount
)
423 boolean_t insingle_quote
= _B_FALSE
;
424 boolean_t indouble_quote
= _B_FALSE
;
426 /* Truncate at the beginning of a comment */
427 cp
= strchr(line
, '#');
432 /* Skip any whitespace */
433 while (isspace(*line
) && *line
!= '\0')
440 insingle_quote
= _B_TRUE
;
441 } else if (*line
== '"') {
445 indouble_quote
= _B_TRUE
;
451 /* Skip until next whitespace or end of quoted text */
452 if (insingle_quote
) {
453 while (*line
!= '\'' && *line
!= '\0')
458 /* Handle missing quote at end */
460 conferr("Missing end quote - ignoring <%s>\n",
464 insingle_quote
= _B_FALSE
;
465 } else if (indouble_quote
) {
466 while (*line
!= '"' && *line
!= '\0')
471 /* Handle missing quote at end */
473 conferr("Missing end quote - ignoring <%s>\n",
477 indouble_quote
= _B_FALSE
;
479 while (!isspace(*line
) && *line
!= '\0')
483 /* Break off argument */
493 parse_var_value(config_type_t type
, struct configinfo
*list
, char *varstr
,
494 char *valstr
, struct confvar
*confvar
)
496 struct configinfo
*cip
;
499 if (debug
& D_CONFIG
) {
500 logmsg(LOG_DEBUG
, "parse_var_value(%d, %s, %s)\n",
501 (int)type
, varstr
, valstr
);
504 for (cip
= list
; cip
->ci_name
!= NULL
; cip
++) {
505 if (strcasecmp(cip
->ci_name
, varstr
) == 0)
508 if (cip
->ci_name
== NULL
) {
509 conferr("Unknown variable: <%s>\n", varstr
);
512 if (!(*cip
->ci_parsefunc
)(valstr
, &val
)) {
513 conferr("Bad value: <%s>\n", valstr
);
516 if (cip
->ci_min
!= 0 && val
< cip
->ci_min
) {
517 conferr("Value %s is below minimum %u for %s\n",
518 valstr
, cip
->ci_min
, varstr
);
521 if (cip
->ci_max
!= ~0U && val
> cip
->ci_max
) {
522 conferr("Value %s is above maximum %u for %s\n",
523 valstr
, cip
->ci_max
, varstr
);
526 /* Check against dynamic/relative limits */
527 if (type
== CONFIG_IF
) {
528 if (cip
->ci_index
== I_MinRtrAdvInterval
&&
529 confvar
[I_MaxRtrAdvInterval
].cf_notdefault
&&
530 val
> confvar
[I_MaxRtrAdvInterval
].cf_value
* 0.75) {
531 conferr("MinRtrAdvInterval exceeds .75 * "
532 "MaxRtrAdvInterval (%u)\n",
533 confvar
[I_MaxRtrAdvInterval
].cf_value
);
536 if (cip
->ci_index
== I_MaxRtrAdvInterval
&&
537 confvar
[I_MinRtrAdvInterval
].cf_notdefault
&&
538 confvar
[I_MinRtrAdvInterval
].cf_value
> val
* 0.75) {
539 conferr("MinRtrAdvInterval (%u) exceeds .75 * "
540 "MaxRtrAdvInterval\n",
541 confvar
[I_MinRtrAdvInterval
].cf_value
);
544 if (cip
->ci_index
== I_AdvDefaultLifetime
&&
545 confvar
[I_MaxRtrAdvInterval
].cf_notdefault
&&
547 val
< confvar
[I_MaxRtrAdvInterval
].cf_value
) {
548 conferr("AdvDefaultLifetime is not between "
549 "MaxRtrAdrInterval (%u) and 9000 seconds\n",
550 confvar
[I_MaxRtrAdvInterval
].cf_value
);
553 if (cip
->ci_index
== I_MaxRtrAdvInterval
&&
554 confvar
[I_AdvDefaultLifetime
].cf_notdefault
&&
555 confvar
[I_AdvDefaultLifetime
].cf_value
< val
) {
556 conferr("AdvDefaultLifetime (%u) is not between "
557 "MaxRtrAdrInterval and 9000 seconds\n",
558 confvar
[I_AdvDefaultLifetime
].cf_value
);
562 confvar
[cip
->ci_index
].cf_value
= val
;
563 confvar
[cip
->ci_index
].cf_notdefault
= _B_TRUE
;
565 /* Derive dynamic/relative variables based on this one */
566 if (type
== CONFIG_IF
) {
567 if (cip
->ci_index
== I_MaxRtrAdvInterval
&&
568 !confvar
[I_MinRtrAdvInterval
].cf_notdefault
)
569 confvar
[I_MinRtrAdvInterval
].cf_value
= val
/ 3;
570 if (cip
->ci_index
== I_MaxRtrAdvInterval
&&
571 !confvar
[I_AdvDefaultLifetime
].cf_notdefault
)
572 confvar
[I_AdvDefaultLifetime
].cf_value
= 3 * val
;
577 * Split up the line into <variable> <value> pairs
580 parse_default(config_type_t type
, struct configinfo
*list
,
581 char *argvec
[], int argcount
, struct confvar
*defaults
)
583 if (debug
& D_CONFIG
)
584 logmsg(LOG_DEBUG
, "parse_default: argc %d\n", argcount
);
585 while (argcount
>= 2) {
586 parse_var_value(type
, list
, argvec
[0], argvec
[1], defaults
);
592 conferr("Trailing text <%s> ignored\n", argvec
[0]);
596 * Returns true if ok; otherwise false.
599 parse_if(struct configinfo
*list
, char *argvec
[], int argcount
)
603 char save
[sizeof (pi
->pi_config
)];
605 if (debug
& D_CONFIG
)
606 logmsg(LOG_DEBUG
, "parse_if: argc %d\n", argcount
);
609 conferr("Missing interface name\n");
616 pi
= phyint_lookup(ifname
);
619 * Create the physical interface structure.
620 * Note, phyint_create() sets the interface
621 * defaults in pi_config.
623 pi
= phyint_create(ifname
);
625 conferr("Unable to use interface %s\n", ifname
);
630 (void) memcpy(save
, pi
->pi_config
, sizeof (save
));
631 while (argcount
>= 2) {
632 parse_var_value(CONFIG_IF
, list
, argvec
[0], argvec
[1],
639 logmsg(LOG_ERR
, "Trailing text <%s> ignored\n", argvec
[0]);
640 check_if_var_consistency(pi
->pi_config
, save
, sizeof (save
));
644 parse_prefix(struct configinfo
*list
, char *argvec
[], int argcount
)
646 char *ifname
, *prefix
;
648 struct adv_prefix
*adv_pr
;
651 char save
[sizeof (adv_pr
->adv_pr_config
)];
653 if (debug
& D_CONFIG
)
654 logmsg(LOG_DEBUG
, "parse_prefix: argc %d\n", argcount
);
657 conferr("Missing prefix and/or interface name\n");
665 prefixlen
= parse_addrprefix(prefix
, &in6
);
666 if (prefixlen
== -1) {
667 conferr("Bad prefix %s\n", prefix
);
671 pi
= phyint_lookup(ifname
);
674 * Create the physical interface structure.
675 * Note, phyint_create() sets the interface
676 * defaults in pi_config.
678 pi
= phyint_create(ifname
);
680 conferr("Unable to use interface %s\n", ifname
);
684 adv_pr
= adv_prefix_lookup(pi
, in6
, prefixlen
);
685 if (adv_pr
== NULL
) {
688 adv_pr
= adv_prefix_create(pi
, in6
, prefixlen
);
689 if (adv_pr
== NULL
) {
690 conferr("Unable to create prefix %s\n", prefix
);
694 * Copy the defaults from the default array.
696 for (i
= 0; i
< I_PREFIXSIZE
; i
++) {
697 adv_pr
->adv_pr_config
[i
].cf_value
=
698 prefixdefaults
[i
].cf_value
;
699 adv_pr
->adv_pr_config
[i
].cf_notdefault
=
700 prefixdefaults
[i
].cf_notdefault
;
704 (void) memcpy(save
, adv_pr
->adv_pr_config
, sizeof (save
));
705 while (argcount
>= 2) {
706 parse_var_value(CONFIG_PREFIX
, list
, argvec
[0], argvec
[1],
707 adv_pr
->adv_pr_config
);
712 check_var_consistency(adv_pr
->adv_pr_config
, save
, sizeof (save
));
714 logmsg(LOG_ERR
, "Trailing text <%s> ignored\n", argvec
[0]);
718 * Returns true if ok (and *resp updated) and false if failed.
721 parse_onoff(char *str
, uint_t
*resp
)
723 if (strcasecmp(str
, "on") == 0) {
727 if (strcasecmp(str
, "off") == 0) {
731 if (strcasecmp(str
, "true") == 0) {
735 if (strcasecmp(str
, "false") == 0) {
739 if (parse_int(str
, resp
)) {
740 if (*resp
== 0 || *resp
== 1)
747 * Returns true if ok (and *resp updated) and false if failed.
750 parse_int(char *str
, uint_t
*resp
)
755 res
= strtoul(str
, &end
, 0);
763 * Parse something with a unit of millseconds.
764 * Regognizes the suffixes "ms", "s", "m", "h", and "d".
766 * Returns true if ok (and *resp updated) and false if failed.
769 parse_ms(char *str
, uint_t
*resp
)
771 /* Look at the last and next to last character */
772 char *cp
, *last
, *nlast
;
773 char str2
[BUFSIZ
]; /* For local modification */
776 (void) strncpy(str2
, str
, sizeof (str2
));
777 str2
[sizeof (str2
) - 1] = '\0';
781 for (cp
= str2
; *cp
!= '\0'; cp
++) {
785 if (debug
& D_PARSE
) {
786 logmsg(LOG_DEBUG
, "parse_ms: last <%c> nlast <%c>\n",
787 (last
!= NULL
? *last
: ' '),
788 (nlast
!= NULL
? *nlast
: ' '));
800 multiplier
*= 1000; /* Convert to milliseconds */
803 /* Could be "ms" or "s" */
804 if (nlast
!= NULL
&& *nlast
== 'm') {
809 multiplier
*= 1000; /* Convert to milliseconds */
814 if (!parse_int(str2
, resp
))
822 * Parse something with a unit of seconds.
823 * Regognizes the suffixes "s", "m", "h", and "d".
825 * Returns true if ok (and *resp updated) and false if failed.
828 parse_s(char *str
, uint_t
*resp
)
830 /* Look at the last character */
832 char str2
[BUFSIZ
]; /* For local modification */
835 (void) strncpy(str2
, str
, sizeof (str2
));
836 str2
[sizeof (str2
) - 1] = '\0';
839 for (cp
= str2
; *cp
!= '\0'; cp
++) {
842 if (debug
& D_PARSE
) {
843 logmsg(LOG_DEBUG
, "parse_s: last <%c>\n",
844 (last
!= NULL
? *last
: ' '));
860 if (!parse_int(str2
, resp
))
868 * Return prefixlen (0 to 128) if ok; -1 if failed.
871 parse_addrprefix(char *strin
, struct in6_addr
*in6
)
873 char str
[BUFSIZ
]; /* Local copy for modification */
878 (void) strncpy(str
, strin
, sizeof (str
));
879 str
[sizeof (str
) - 1] = '\0';
881 cp
= strchr(str
, '/');
887 prefixlen
= strtol(cp
, &end
, 10);
891 if (prefixlen
< 0 || prefixlen
> IPV6_ABITS
)
894 if (inet_pton(AF_INET6
, str
, in6
) != 1)
901 * Parse an absolute date using a datemsk config file.
902 * Return the difference (measured in seconds) between that date/time and
903 * the current date/time.
904 * If the date has passed return zero.
906 * Returns true if ok (and *resp updated) and false if failed.
907 * XXX Due to getdate limitations can not exceed year 2038.
910 parse_date(char *str
, uint_t
*resp
)
916 if (getenv("DATEMSK") == NULL
) {
917 (void) putenv("DATEMSK=/etc/inet/datemsk.ndpd");
920 if (gettimeofday(&tvs
, NULL
) < 0) {
921 logperror("gettimeofday");
927 logmsg(LOG_ERR
, "Bad date <%s> (error %d)\n",
934 if (debug
& D_PARSE
) {
937 (void) strftime(buf
, sizeof (buf
), "%Y-%m-%d %R %Z", tm
);
938 logmsg(LOG_DEBUG
, "parse_date: <%s>, delta %ld seconds\n",
942 conferr("Date in the past <%s>\n", str
);
946 *resp
= (ntime
- time
);
952 conferr(char *fmt
, ...)
954 char msg
[NDPD_LOGMSGSIZE
];
960 (void) snprintf(msg
, NDPD_LOGMSGSIZE
, "%s line %d: ",
961 conf_filename
, lineno
);
963 (void) vsnprintf(msg
+ slen
, NDPD_LOGMSGSIZE
- slen
, fmt
, ap
);
965 logmsg(LOG_ERR
, "%s", msg
);
971 open_conffile(char *filename
)
973 if (strlcpy(conf_filename
, filename
, MAXPATHLEN
) >= MAXPATHLEN
) {
974 logmsg(LOG_ERR
, "config file pathname is too long\n");
980 return (fopen(filename
, "r"));