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