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 *
bi_find_param(const char * name)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
bi_getval_chosen(bi_param_t * bip,void * valbuf,size_t * vallenp)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
bi_getval_dhcpopt(bi_param_t * bip,void * valbuf,size_t * vallenp)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
bi_getval_bootmisc(bi_param_t * bip,void * valbuf,size_t * vallenp)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
bi_put_bootmisc(const char * name,const void * valbuf,size_t vallen)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
bi_putval_chosen(bi_param_t * bip,const void * valbuf,size_t vallen)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
bi_putval_bootmisc(bi_param_t * bip,const void * valbuf,size_t vallen)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
bootinfo_end(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
bootinfo_init(void)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
bootinfo_get(const char * name,void * valbufp,size_t * vallenp,int * repositoryp)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
bootinfo_put(const char * name,const void * valbuf,size_t vallen,int repository)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