xref: /onnv-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/defaults.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 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 <sys/types.h>
30*0Sstevel@tonic-gate #include <netinet/in.h>
31*0Sstevel@tonic-gate #include <netinet/inetutil.h>
32*0Sstevel@tonic-gate #include <netinet/dhcp.h>
33*0Sstevel@tonic-gate #include <stdlib.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate #include <dhcpmsg.h>
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate #include <sys/stat.h>
39*0Sstevel@tonic-gate #include <libnvpair.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include "defaults.h"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate struct dhcp_default {
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate 	const char	*df_name;	/* parameter name */
46*0Sstevel@tonic-gate 	const char	*df_default;	/* default value */
47*0Sstevel@tonic-gate 	int		df_min;		/* min value if type DF_INTEGER */
48*0Sstevel@tonic-gate 	int		df_max;		/* max value if type DF_INTEGER */
49*0Sstevel@tonic-gate };
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate  * note: keep in the same order as tunable parameter constants in defaults.h
53*0Sstevel@tonic-gate  */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static struct dhcp_default defaults[] = {
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate 	{ "RELEASE_ON_SIGTERM",  "0",	 0,   0	  },
58*0Sstevel@tonic-gate 	{ "IGNORE_FAILED_ARP",	 "1",	 0,   0	  },
59*0Sstevel@tonic-gate 	{ "OFFER_WAIT",		 "3",	 1,   20  },
60*0Sstevel@tonic-gate 	{ "ARP_WAIT",		 "1000", 100, 4000 },
61*0Sstevel@tonic-gate 	{ "CLIENT_ID",		 NULL,	 0,   0	  },
62*0Sstevel@tonic-gate 	{ "PARAM_REQUEST_LIST",  NULL,	 0,   0    },
63*0Sstevel@tonic-gate 	{ "REQUEST_HOSTNAME",	 "1",	 0,   0	  }
64*0Sstevel@tonic-gate };
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate /*
67*0Sstevel@tonic-gate  * df_build_cache(): builds the defaults nvlist cache
68*0Sstevel@tonic-gate  *
69*0Sstevel@tonic-gate  *   input: void
70*0Sstevel@tonic-gate  *  output: a pointer to an nvlist of the current defaults, or NULL on failure
71*0Sstevel@tonic-gate  */
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static nvlist_t *
74*0Sstevel@tonic-gate df_build_cache(void)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	char		entry[1024];
77*0Sstevel@tonic-gate 	int		i;
78*0Sstevel@tonic-gate 	char		*param, *value, *end;
79*0Sstevel@tonic-gate 	FILE		*fp;
80*0Sstevel@tonic-gate 	nvlist_t 	*nvlist;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if ((fp = fopen(DHCP_AGENT_DEFAULTS, "r")) == NULL)
83*0Sstevel@tonic-gate 		return (NULL);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
86*0Sstevel@tonic-gate 		dhcpmsg(MSG_WARNING, "cannot build default value cache; "
87*0Sstevel@tonic-gate 		    "using built-in defaults");
88*0Sstevel@tonic-gate 		(void) fclose(fp);
89*0Sstevel@tonic-gate 		return (NULL);
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	while (fgets(entry, sizeof (entry), fp) != NULL) {
93*0Sstevel@tonic-gate 		for (i = 0; entry[i] == ' '; i++)
94*0Sstevel@tonic-gate 			;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 		end = strrchr(entry, '\n');
97*0Sstevel@tonic-gate 		value = strchr(entry, '=');
98*0Sstevel@tonic-gate 		if (end == NULL || value == NULL || entry[i] == '#')
99*0Sstevel@tonic-gate 			continue;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 		*end = '\0';
102*0Sstevel@tonic-gate 		*value++ = '\0';
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 		/*
105*0Sstevel@tonic-gate 		 * to be compatible with the old defread()-based code
106*0Sstevel@tonic-gate 		 * which ignored case, store the parameters (except for the
107*0Sstevel@tonic-gate 		 * leading interface name) in upper case.
108*0Sstevel@tonic-gate 		 */
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 		if ((param = strchr(entry, '.')) == NULL)
111*0Sstevel@tonic-gate 			param = entry;
112*0Sstevel@tonic-gate 		else
113*0Sstevel@tonic-gate 			param++;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 		for (; *param != '\0'; param++)
116*0Sstevel@tonic-gate 			*param = toupper(*param);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 		if (nvlist_add_string(nvlist, &entry[i], value) != 0) {
119*0Sstevel@tonic-gate 			dhcpmsg(MSG_WARNING, "cannot build default value cache;"
120*0Sstevel@tonic-gate 			    " using built-in defaults");
121*0Sstevel@tonic-gate 			nvlist_free(nvlist);
122*0Sstevel@tonic-gate 			nvlist = NULL;
123*0Sstevel@tonic-gate 			break;
124*0Sstevel@tonic-gate 		}
125*0Sstevel@tonic-gate 	}
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	(void) fclose(fp);
128*0Sstevel@tonic-gate 	return (nvlist);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * df_get_string(): gets the string value of a given user-tunable parameter
133*0Sstevel@tonic-gate  *
134*0Sstevel@tonic-gate  *   input: const char *: the interface the parameter applies to
135*0Sstevel@tonic-gate  *	    unsigned int: the parameter number to look up
136*0Sstevel@tonic-gate  *  output: const char *: the parameter's value, or default if not set
137*0Sstevel@tonic-gate  *			  (must be copied by caller to be kept)
138*0Sstevel@tonic-gate  *    NOTE: df_get_string() is both used by functions outside this source
139*0Sstevel@tonic-gate  *	    file to retrieve strings from the defaults file, *and*
140*0Sstevel@tonic-gate  *	    internally by other df_get_*() functions.
141*0Sstevel@tonic-gate  */
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate const char *
144*0Sstevel@tonic-gate df_get_string(const char *if_name, unsigned int p)
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate 	char			*value;
147*0Sstevel@tonic-gate 	char			param[256];
148*0Sstevel@tonic-gate 	struct stat		statbuf;
149*0Sstevel@tonic-gate 	static struct stat	df_statbuf;
150*0Sstevel@tonic-gate 	static boolean_t	df_unavail_msg = B_FALSE;
151*0Sstevel@tonic-gate 	static nvlist_t		*df_nvlist = NULL;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
154*0Sstevel@tonic-gate 		return (NULL);
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	if (stat(DHCP_AGENT_DEFAULTS, &statbuf) != 0) {
157*0Sstevel@tonic-gate 		if (!df_unavail_msg) {
158*0Sstevel@tonic-gate 			dhcpmsg(MSG_WARNING, "cannot access %s; using "
159*0Sstevel@tonic-gate 			    "built-in defaults", DHCP_AGENT_DEFAULTS);
160*0Sstevel@tonic-gate 			df_unavail_msg = B_TRUE;
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 		return (defaults[p].df_default);
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * if our cached parameters are stale, rebuild.
167*0Sstevel@tonic-gate 	 */
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if (statbuf.st_mtime != df_statbuf.st_mtime ||
170*0Sstevel@tonic-gate 	    statbuf.st_size != df_statbuf.st_size) {
171*0Sstevel@tonic-gate 		df_statbuf = statbuf;
172*0Sstevel@tonic-gate 		if (df_nvlist != NULL)
173*0Sstevel@tonic-gate 			nvlist_free(df_nvlist);
174*0Sstevel@tonic-gate 		df_nvlist = df_build_cache();
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	(void) snprintf(param, sizeof (param), "%s.%s", if_name,
178*0Sstevel@tonic-gate 	    defaults[p].df_name);
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/*
181*0Sstevel@tonic-gate 	 * first look for `if_name.param', then `param'.  if neither
182*0Sstevel@tonic-gate 	 * has been set, use the built-in default.
183*0Sstevel@tonic-gate 	 */
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	if (nvlist_lookup_string(df_nvlist, param, &value) == 0 ||
186*0Sstevel@tonic-gate 	    nvlist_lookup_string(df_nvlist, defaults[p].df_name, &value) == 0)
187*0Sstevel@tonic-gate 		return (value);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	return (defaults[p].df_default);
190*0Sstevel@tonic-gate }
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate /*
193*0Sstevel@tonic-gate  * df_get_octet(): gets the integer value of a given user-tunable parameter
194*0Sstevel@tonic-gate  *
195*0Sstevel@tonic-gate  *   input: const char *: the interface the parameter applies to
196*0Sstevel@tonic-gate  *	    unsigned int: the parameter number to look up
197*0Sstevel@tonic-gate  *	    unsigned int *: the length of the returned value
198*0Sstevel@tonic-gate  *  output: uchar_t *: a pointer to byte array (default value if not set)
199*0Sstevel@tonic-gate  *		       (must be copied by caller to be kept)
200*0Sstevel@tonic-gate  */
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate uchar_t *
203*0Sstevel@tonic-gate df_get_octet(const char *if_name, unsigned int p, unsigned int *len)
204*0Sstevel@tonic-gate {
205*0Sstevel@tonic-gate 	const char	*value;
206*0Sstevel@tonic-gate 	static uchar_t	octet_value[256]; /* as big as defread() returns */
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
209*0Sstevel@tonic-gate 		return (NULL);
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	value = df_get_string(if_name, p);
212*0Sstevel@tonic-gate 	if (value == NULL)
213*0Sstevel@tonic-gate 		goto do_default;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if (strncasecmp("0x", value, 2) != 0) {
216*0Sstevel@tonic-gate 		*len = strlen(value);			/* no NUL */
217*0Sstevel@tonic-gate 		return ((uchar_t *)value);
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/* skip past the 0x and convert the value to binary */
221*0Sstevel@tonic-gate 	value += 2;
222*0Sstevel@tonic-gate 	*len = sizeof (octet_value);
223*0Sstevel@tonic-gate 	if (hexascii_to_octet(value, strlen(value), octet_value, len) != 0) {
224*0Sstevel@tonic-gate 		dhcpmsg(MSG_WARNING, "df_get_octet: cannot convert value "
225*0Sstevel@tonic-gate 		    "for parameter `%s', using default", defaults[p].df_name);
226*0Sstevel@tonic-gate 		goto do_default;
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 	return (octet_value);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate do_default:
231*0Sstevel@tonic-gate 	if (defaults[p].df_default == NULL) {
232*0Sstevel@tonic-gate 		*len = 0;
233*0Sstevel@tonic-gate 		return (NULL);
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	*len = strlen(defaults[p].df_default);		/* no NUL */
237*0Sstevel@tonic-gate 	return ((uchar_t *)defaults[p].df_default);
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate /*
241*0Sstevel@tonic-gate  * df_get_int(): gets the integer value of a given user-tunable parameter
242*0Sstevel@tonic-gate  *
243*0Sstevel@tonic-gate  *   input: const char *: the interface the parameter applies to
244*0Sstevel@tonic-gate  *	    unsigned int: the parameter number to look up
245*0Sstevel@tonic-gate  *  output: int: the parameter's value, or default if not set
246*0Sstevel@tonic-gate  */
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate int
249*0Sstevel@tonic-gate df_get_int(const char *if_name, unsigned int p)
250*0Sstevel@tonic-gate {
251*0Sstevel@tonic-gate 	const char	*value;
252*0Sstevel@tonic-gate 	int		value_int;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
255*0Sstevel@tonic-gate 		return (0);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	value = df_get_string(if_name, p);
258*0Sstevel@tonic-gate 	if (value == NULL || !isdigit(*value))
259*0Sstevel@tonic-gate 		goto failure;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	value_int = atoi(value);
262*0Sstevel@tonic-gate 	if (value_int > defaults[p].df_max || value_int < defaults[p].df_min)
263*0Sstevel@tonic-gate 		goto failure;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	return (value_int);
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate failure:
268*0Sstevel@tonic-gate 	dhcpmsg(MSG_WARNING, "df_get_int: parameter `%s' is not between %d and "
269*0Sstevel@tonic-gate 	    "%d, defaulting to `%s'", defaults[p].df_name, defaults[p].df_min,
270*0Sstevel@tonic-gate 	    defaults[p].df_max, defaults[p].df_default);
271*0Sstevel@tonic-gate 	return (atoi(defaults[p].df_default));
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate /*
275*0Sstevel@tonic-gate  * df_get_bool(): gets the boolean value of a given user-tunable parameter
276*0Sstevel@tonic-gate  *
277*0Sstevel@tonic-gate  *   input: const char *: the interface the parameter applies to
278*0Sstevel@tonic-gate  *	    unsigned int: the parameter number to look up
279*0Sstevel@tonic-gate  *  output: boolean_t: B_TRUE if true, B_FALSE if false, default if not set
280*0Sstevel@tonic-gate  */
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate boolean_t
283*0Sstevel@tonic-gate df_get_bool(const char *if_name, unsigned int p)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	const char	*value;
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	if (p >= (sizeof (defaults) / sizeof (*defaults)))
288*0Sstevel@tonic-gate 		return (0);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	value = df_get_string(if_name, p);
291*0Sstevel@tonic-gate 	if (value != NULL) {
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 		if (strcasecmp(value, "true") == 0 ||
294*0Sstevel@tonic-gate 		    strcasecmp(value, "yes") == 0 || strcmp(value, "1") == 0)
295*0Sstevel@tonic-gate 			return (B_TRUE);
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 		if (strcasecmp(value, "false") == 0 ||
298*0Sstevel@tonic-gate 		    strcasecmp(value, "no") == 0 || strcmp(value, "0") == 0)
299*0Sstevel@tonic-gate 			return (B_FALSE);
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	dhcpmsg(MSG_WARNING, "df_get_bool: parameter `%s' has invalid value "
303*0Sstevel@tonic-gate 	    "`%s', defaulting to `%s'", defaults[p].df_name,
304*0Sstevel@tonic-gate 	    value ? value : "NULL", defaults[p].df_default);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	return ((atoi(defaults[p].df_default) == 0) ? B_FALSE : B_TRUE);
307*0Sstevel@tonic-gate }
308