xref: /titanic_51/usr/src/common/net/wanboot/bootinfo.c (revision 2ca5b6595b95478e6568b0e77c6c83c8a870867a)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <dhcp_impl.h>
32 #include <sys/time.h>
33 #include <sys/nvpair.h>
34 #include <netinet/inetutil.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <strings.h>
38 #include <net/if.h>
39 #if	defined(_BOOT)
40 #include <sys/salib.h>
41 #include <sys/bootcmn.h>
42 #include <ipv4.h>
43 #include <dhcpv4.h>
44 #endif	/* defined(_BOOT) */
45 #include <bootinfo.h>
46 #include <bootinfo_aux.h>
47 
48 /*
49  * Declarations and definitions describing parameters which may be known by
50  * a bootconf name, a property of /chosen, a DHCP option or a 'bootmisc' name.
51  */
52 typedef struct {
53 	const char	*opt_name;	/* DHCP option name */
54 	dsym_cdtype_t	opt_type;	/* DHCP option type (dhcp_symbol.h) */
55 	uchar_t		opt_cat;	/* DHCP option category */
56 	uint16_t	opt_code;	/* DHCP option code */
57 	uint16_t	opt_size;	/* DHCP option size (FIELDs only) */
58 } bi_dhcpopt_t;
59 
60 /*
61  * Possible values for the 'bi_flags' field below.
62  */
63 #define	BI_F_BYTES	0x01		/* chosen value is bytes, not string */
64 
65 typedef struct {
66 	const char	*bi_name;	/* parameter name */
67 	int		bi_repository;	/* entry's repository(s) */
68 	int		bi_flags;	/* BI_F_BYTES or zero */
69 	bi_dhcpopt_t	*bi_dhcp;	/* &dhcpopt struct */
70 } bi_param_t;
71 
72 /*
73  * DHCP options which have bootinfo equivalents, and the information
74  * necessary to retrieve their values via dhcp_getinfo().  The 'type'
75  * is necessary so that all values may be converted to ascii strings.
76  */
77 static bi_dhcpopt_t	Yiaddr	    = {
78 	"Yiaddr",	DSYM_IP,	DSYM_FIELD,	16,	4
79 };
80 static bi_dhcpopt_t	Subnet	    = {
81 	"Subnet",	DSYM_IP,	DSYM_STANDARD,	1,	0
82 };
83 static bi_dhcpopt_t	Router	    = {
84 	"Router",	DSYM_IP,	DSYM_STANDARD,	3,	0
85 };
86 static bi_dhcpopt_t	Hostname    = {
87 	"Hostname",	DSYM_ASCII,	DSYM_STANDARD,	12,	0
88 };
89 static bi_dhcpopt_t	ClientID    = {
90 	"ClientID",	DSYM_OCTET,	DSYM_STANDARD,	61,	0
91 };
92 static bi_dhcpopt_t	SHTTPproxy  = {
93 	"SHTTPproxy",	DSYM_ASCII,	DSYM_VENDOR,	17,	0
94 };
95 #if	defined(_BOOT)
96 static bi_dhcpopt_t	BootFile    = {
97 	"BootFile",	DSYM_ASCII,	DSYM_FIELD,	108,	128
98 };
99 static bi_dhcpopt_t	SbootURI    = {
100 	"SbootURI",	DSYM_ASCII,	DSYM_VENDOR,	16,	0
101 };
102 #else
103 static bi_dhcpopt_t	SsysidCF    = {
104 	"SsysidCF",	DSYM_ASCII,	DSYM_VENDOR,	13,	0
105 };
106 static bi_dhcpopt_t	SjumpsCF    = {
107 	"SjumpsCF",	DSYM_ASCII,	DSYM_VENDOR,	14,	0
108 };
109 #endif	/* defined(_BOOT) */
110 
111 /*
112  * bootinfo's main data structure.
113  */
114 static bi_param_t	bi_params[] = {
115 	/*
116 	 * Parameters from /chosen or DHCP:
117 	 */
118 	{ BI_HOST_IP,			BI_R_CHOSEN|BI_R_DHCPOPT,
119 	    0,		&Yiaddr					},
120 	{ BI_SUBNET_MASK,		BI_R_CHOSEN|BI_R_DHCPOPT,
121 	    0,		&Subnet					},
122 	{ BI_ROUTER_IP,			BI_R_CHOSEN|BI_R_DHCPOPT,
123 	    0,		&Router					},
124 	{ BI_HOSTNAME,			BI_R_CHOSEN|BI_R_DHCPOPT,
125 	    0,		&Hostname				},
126 	{ BI_CLIENT_ID,			BI_R_CHOSEN|BI_R_DHCPOPT,
127 	    BI_F_BYTES,	&ClientID				},
128 	{ BI_HTTP_PROXY,		BI_R_CHOSEN|BI_R_DHCPOPT,
129 	    0,		&SHTTPproxy				},
130 
131 #if	defined(_BOOT)
132 	/*
133 	 * Parameters from /chosen or DHCP:
134 	 */
135 	{ BI_NETWORK_BOOT_FILE,		BI_R_CHOSEN|BI_R_DHCPOPT,
136 	    0,		&SbootURI				},
137 
138 	/*
139 	 * Parameters from DHCP only:
140 	 */
141 	{ BI_BOOTFILE,			BI_R_DHCPOPT,
142 	    0,		&BootFile				},
143 
144 	/*
145 	 * Parameters from /chosen only:
146 	 */
147 	{ BI_BOOTP_RESPONSE,		BI_R_CHOSEN,
148 	    BI_F_BYTES,	NULL					},
149 	{ BI_NET_CONFIG_STRATEGY,	BI_R_CHOSEN,
150 	    0,		NULL					},
151 
152 	/*
153 	 * Parameters from 'bootmisc' only:
154 	 */
155 	{ BI_BOOTSERVER,		BI_R_BOOTMISC,
156 	    0,		NULL					},
157 	{ BI_AES_KEY,			BI_R_BOOTMISC,
158 	    BI_F_BYTES,	NULL					},
159 	{ BI_3DES_KEY,			BI_R_BOOTMISC,
160 	    BI_F_BYTES,	NULL					},
161 	{ BI_SHA1_KEY,			BI_R_BOOTMISC,
162 	    BI_F_BYTES,	NULL					},
163 #else
164 	/*
165 	 * Parameters from DHCP only:
166 	 */
167 	{ BI_SYSIDCFG,			BI_R_DHCPOPT,
168 	    0,		&SsysidCF				},
169 	{ BI_JUMPSCFG,			BI_R_DHCPOPT,
170 	    0,		&SjumpsCF				},
171 
172 	/*
173 	 * Parameters from /chosen or 'bootmisc':
174 	 */
175 	{ BI_NET_CONFIG_STRATEGY,	BI_R_CHOSEN|BI_R_BOOTMISC,
176 	    0,		NULL					},
177 
178 	/*
179 	 * Parameters from 'bootmisc' only:
180 	 */
181 	{ BI_ROOTFS_TYPE,		BI_R_BOOTMISC,
182 	    0,		NULL					},
183 	{ BI_INTERFACE_NAME,		BI_R_BOOTMISC,
184 	    0,		NULL					},
185 #endif	/* defined(_BOOT) */
186 
187 	NULL
188 };
189 
190 /*
191  * Bootmisc data is handled internally as a nvpair list.
192  */
193 static nvlist_t		*bi_nvl = NULL;
194 
195 
196 /*
197  * Scan our parameter table to see whether 'name' matches any entry.
198  */
199 static bi_param_t *
200 bi_find_param(const char *name)
201 {
202 	bi_param_t	*bip;
203 
204 	for (bip = bi_params; bip->bi_name != NULL; bip++) {
205 		if (strcmp(name, bip->bi_name) == 0 ||
206 		    ((bip->bi_repository & BI_R_DHCPOPT) &&
207 		    strcmp(name, bip->bi_dhcp->opt_name) == 0)) {
208 			return (bip);
209 		}
210 	}
211 	return (NULL);
212 }
213 
214 /*
215  * Functions for retrieving /chosen, DHCP and bootmisc data.
216  */
217 static int
218 bi_getval_chosen(bi_param_t *bip, void *valbuf, size_t *vallenp)
219 {
220 	size_t	buflen = *vallenp;
221 
222 	if (!bi_get_chosen_prop(bip->bi_name, valbuf, vallenp)) {
223 		return (BI_E_NOVAL);
224 	} else if (*vallenp > buflen) {
225 		return (BI_E_BUF2SMALL);
226 	}
227 
228 	return (BI_E_SUCCESS);
229 }
230 
231 static int
232 bi_getval_dhcpopt(bi_param_t *bip, void *valbuf, size_t *vallenp)
233 {
234 	void		*val;
235 	size_t		len, buflen = *vallenp;
236 	struct in_addr	ipaddr;
237 
238 	if (bip->bi_dhcp->opt_type == DSYM_IP) {
239 		val = &ipaddr;
240 		len = sizeof (ipaddr);
241 	} else {
242 		val = valbuf;
243 		len = *vallenp;
244 	}
245 
246 	if (!bi_get_dhcp_info(bip->bi_dhcp->opt_cat, bip->bi_dhcp->opt_code,
247 	    bip->bi_dhcp->opt_size, val, &len)) {
248 		return (BI_E_NOVAL);
249 	}
250 
251 	switch (bip->bi_dhcp->opt_type) {
252 	case DSYM_IP:
253 		if (buflen < INET_ADDRSTRLEN + 1) {
254 			*vallenp = len;
255 			return (BI_E_BUF2SMALL);
256 		}
257 		len = strlen(strcpy(valbuf, inet_ntoa(ipaddr))) + 1;
258 		break;
259 
260 	case DSYM_ASCII:
261 		if (len >= buflen)
262 			return (BI_E_BUF2SMALL);
263 
264 		((uchar_t *)valbuf)[len++] = '\0';
265 		break;
266 	}
267 	*vallenp = len;
268 
269 	return (BI_E_SUCCESS);
270 }
271 
272 static int
273 bi_getval_bootmisc(bi_param_t *bip, void *valbuf, size_t *vallenp)
274 {
275 	uchar_t		*val;
276 	uint_t		len;
277 
278 	if (nvlist_lookup_byte_array(bi_nvl, (char *)bip->bi_name,
279 	    &val, &len) != 0) {
280 		return (BI_E_NOVAL);
281 	} else if (*vallenp < len) {
282 		*vallenp = len;
283 		return (BI_E_BUF2SMALL);
284 	}
285 	*vallenp = len;
286 	(void) memcpy(valbuf, val, *vallenp);
287 
288 	return (BI_E_SUCCESS);
289 }
290 
291 /*
292  * This is also called from the userland bootinfo_aux.c to initialize
293  * its bootmisc data.
294  */
295 boolean_t
296 bi_put_bootmisc(const char *name, const void *valbuf, size_t vallen)
297 {
298 	return (nvlist_add_byte_array(bi_nvl, (char *)name,
299 	    (uchar_t *)valbuf, (uint_t)vallen) == 0);
300 }
301 
302 #if	defined(_BOOT)
303 /*
304  * Functions for storing /chosen and bootmisc data.
305  */
306 static int
307 bi_putval_chosen(bi_param_t *bip, const void *valbuf, size_t vallen)
308 {
309 	return (bi_put_chosen_prop(bip->bi_name, valbuf, vallen,
310 	    (bip->bi_flags & BI_F_BYTES)) ? BI_E_SUCCESS : BI_E_ERROR);
311 }
312 
313 static int
314 bi_putval_bootmisc(bi_param_t *bip, const void *valbuf, size_t vallen)
315 {
316 	return (bi_put_bootmisc(bip->bi_name, valbuf, vallen)
317 	    ? BI_E_SUCCESS : BI_E_ERROR);
318 }
319 #endif	/* defined(_BOOT) */
320 
321 
322 /*
323  * Deallocate resources, etc. after accessing bootinfo.
324  */
325 void
326 bootinfo_end(void)
327 {
328 	if (bi_nvl != NULL) {
329 		nvlist_free(bi_nvl);
330 		bi_nvl = NULL;
331 		bi_end_bootinfo();
332 	}
333 }
334 
335 /*
336  * Perform bootinfo initialization.
337  */
338 boolean_t
339 bootinfo_init(void)
340 {
341 	if (bi_nvl == NULL &&
342 	    nvlist_alloc(&bi_nvl, NV_UNIQUE_NAME, 0) == 0) {
343 		if (!bi_init_bootinfo()) {
344 			nvlist_free(bi_nvl);
345 			bi_nvl = NULL;
346 		}
347 	}
348 
349 	return (bi_nvl != NULL);
350 }
351 
352 /*
353  * bootinfo_get(const char *name, void *valbuf, size_t *vallenp,
354  *     int *repository);
355  *
356  * Obtain a value for a named boot parameter from one of a number of possible
357  * repositories:
358  *
359  *   - stored properties under /chosen in the device tree;
360  *   - returned DHCP data;
361  *   - miscellaneous boot information, determined from the standalone or
362  *     the kernel (depending on whether we're in the standalone or userland).
363  *
364  * These repositories are interrogated in the order listed above; the first
365  * one to match is value returned.
366  *
367  * Returns:
368  *	0  => successful, value copied to valbuf, length assigned to *vallen.
369  *	>0 => error (BI_E_* codes defined in bootinfo.h)
370  */
371 bi_errcode_t
372 bootinfo_get(const char *name, void *valbufp, size_t *vallenp,
373     int *repositoryp)
374 {
375 	bi_param_t	*bip;
376 	int		repositories;
377 	int		err;
378 	size_t		zerolen = 0;
379 
380 	/*
381 	 * Check whether we were successfully initialized.
382 	 */
383 	if (bi_nvl == NULL) {
384 		return (BI_E_ERROR);
385 	}
386 
387 	/*
388 	 * Determine which repositories might be accessed; a NULL pointer
389 	 * means to (possibly) access them all.
390 	 */
391 	if (repositoryp != NULL) {
392 		repositories = *repositoryp;
393 		*repositoryp = 0;
394 	} else {
395 		repositories = BI_R_ALL;
396 	}
397 
398 	/*
399 	 * Check that we know about this name in one or more of the
400 	 * requested repositories.
401 	 */
402 	if ((bip = bi_find_param(name)) == NULL) {
403 		return (BI_E_ILLNAME);
404 	}
405 	repositories &= bip->bi_repository;
406 	if (repositories == 0) {
407 		return (BI_E_ILLNAME);
408 	}
409 
410 	/*
411 	 * The caller may simply be enquiring whether a value is present:
412 	 *
413 	 *    bootinfo_get(name, NULL, NULL, repository) == BI_E_BUF2SMALL
414 	 *
415 	 * indicates that there is a value, but doesn't fetch it.
416 	 */
417 	if (vallenp == NULL) {
418 		vallenp = &zerolen;
419 	}
420 
421 	/*
422 	 * To retrieve a value, try the various repositories in order.
423 	 */
424 	if ((repositories & BI_R_CHOSEN) != 0 &&
425 	    (err = bi_getval_chosen(bip, valbufp, vallenp)) != BI_E_NOVAL) {
426 		if (repositoryp != NULL) {
427 			*repositoryp = BI_R_CHOSEN;
428 		}
429 		return (err);
430 	}
431 	if ((repositories & BI_R_DHCPOPT) != 0 &&
432 	    (err = bi_getval_dhcpopt(bip, valbufp, vallenp)) != BI_E_NOVAL) {
433 		if (repositoryp != NULL) {
434 			*repositoryp = BI_R_DHCPOPT;
435 		}
436 		return (err);
437 	}
438 	if ((repositories & BI_R_BOOTMISC) != 0 &&
439 	    (err = bi_getval_bootmisc(bip, valbufp, vallenp)) != BI_E_NOVAL) {
440 		if (repositoryp != NULL) {
441 			*repositoryp = BI_R_BOOTMISC;
442 		}
443 		return (err);
444 	}
445 
446 	/*
447 	 * No-one has a value for 'name'.
448 	 */
449 	return (BI_E_NOVAL);
450 }
451 
452 #if	defined(_BOOT)
453 /*
454  * bootinfo_put(const char *name, char *valbuf, int vallen,
455  *     int repository);
456  *
457  * Create/update a value in the bootinfo repository (standalone only).
458  *
459  * Returns:
460  *	0  => successful, valbuf[0..vallen-1] bytes stored in repository
461  *	>0 => error (BI_E_* codes defined in bootinfo.h)
462  */
463 int
464 bootinfo_put(const char *name, const void *valbuf, size_t vallen,
465     int repository)
466 {
467 	bi_param_t	*bip;
468 
469 	/*
470 	 * Check whether we were successfully initialized.
471 	 */
472 	if (bi_nvl == NULL) {
473 		return (BI_E_ERROR);
474 	}
475 
476 	/*
477 	 * Determine which repositories might be accessed; a zero value
478 	 * means to (possibly) access them all.
479 	 */
480 	if (repository == 0) {
481 		repository = BI_R_ALL;
482 	}
483 
484 	/*
485 	 * Check that we know about this name in the specified repository,
486 	 * and that it may be written (note that DHCP options cannot be
487 	 * written).
488 	 */
489 	if ((bip = bi_find_param(name)) == NULL ||
490 	    (repository & bip->bi_repository) == 0) {
491 		return (BI_E_ILLNAME);
492 	}
493 	if ((repository & bip->bi_repository) == BI_R_DHCPOPT) {
494 		return (BI_E_RDONLY);
495 	}
496 
497 	/*
498 	 * To put the value, try the various repositories in order.
499 	 */
500 	if ((bip->bi_repository & BI_R_CHOSEN) != 0) {
501 		return (bi_putval_chosen(bip, valbuf, vallen));
502 	}
503 	if ((bip->bi_repository & BI_R_BOOTMISC) != 0) {
504 		return (bi_putval_bootmisc(bip, valbuf, vallen));
505 	}
506 
507 	return (BI_E_ERROR);
508 }
509 #endif	/* defined(_BOOT) */
510