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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 /* EXPORT DELETE START */
  29 #include <sys/types.h>
  30 #include <sys/param.h>
  31 #include <sys/salib.h>
  32 #include <sys/promif.h>
  33 #include <sys/wanboot_impl.h>
  34 #include <netinet/in.h>
  35 #include <parseURL.h>
  36 #include <bootlog.h>
  37 #include <sys/socket.h>
  38 #include <netinet/inetutil.h>
  39 #include <netinet/dhcp.h>
  40 #include <dhcp_impl.h>
  41 #include <lib/inet/mac.h>
  42 #include <lib/inet/ipv4.h>
  43 #include <lib/inet/dhcpv4.h>
  44 #include <lib/sock/sock_test.h>
  45 #include <sys/sunos_dhcp_class.h>
  46 #include <aes.h>
  47 #include <des3.h>
  48 #include <hmac_sha1.h>
  49 #include <netdb.h>
  50 #include <wanboot_conf.h>
  51 #include <bootinfo.h>
  52 /* EXPORT DELETE END */
  53 
  54 #include "wbcli.h"
  55 
  56 /* EXPORT DELETE START */
  57 
  58 #define skipspace(p)    while (isspace(*(p))) ++p
  59 
  60 #define skiptext(p)     while (*(p) != '\0' && !isspace(*(p)) && \
  61                             *(p) != '=' && *(p) != ',') ++p
  62 
  63 #define PROMPT          "boot> "
  64 #define TEST_PROMPT     "boot-test> "
  65 
  66 #define CLI_SET         0
  67 #define CLI_FAIL        (-1)
  68 #define CLI_EXIT        (-2)
  69 #define CLI_CONT        (-3)
  70 
  71 #define CLF_CMD         0x00000001      /* builtin command */
  72 #define CLF_ARG         0x00000002      /* boot argument directive */
  73 
  74 #define CLF_IF          0x00000100      /* interface parameter */
  75 #define CLF_BM          0x00000200      /* bootmisc parameter */
  76 
  77 #define CLF_VALSET      0x00010000      /* value set, may be null */
  78 #define CLF_HIDDEN      0x00020000      /* don't show its value (key) */
  79 #define CLF_VALMOD      0x00040000      /* value modified by the user */
  80 
  81 /*
  82  * Macros for use in managing the flags in the cli_list[].
  83  * The conventions we follow are:
  84  *
  85  *      CLF_VALSET is cleared   if a value is removed from varptr
  86  *      CLF_VALSET is set       if a value has been placed in varptr
  87  *                              (that value need not be vetted)
  88  *      CLF_HIDDEN is set       if a value must not be exposed to the user
  89  *      CLF_HIDDEN is cleared   if a value can be exposed to the user
  90  *      CLF_VALMOD is cleared   if a value in varptr has not been modified
  91  *      CLF_VALMOD is set       if a value in varptr has been modified by
  92  *                              the user
  93  */
  94 #ifdef  DEBUG
  95 #define CLF_SETVAL(var)         {                                       \
  96                                         (((var)->flags) |= CLF_VALSET);      \
  97                                         printf("set %s\n", var->varname);\
  98                                 }
  99 
 100 #define CLF_ISSET(var)          (printf("%s\n",                         \
 101                                     (((var)->flags) & CLF_VALSET) != 0   \
 102                                     ? "is set" : "not set"),            \
 103                                     ((((var)->flags) & CLF_VALSET) != 0))
 104 
 105 #define CLF_CLRHIDDEN(var)      {                                       \
 106                                         (((var)->flags) &= ~CLF_HIDDEN); \
 107                                         printf("unhide %s\n", var->varname); \
 108                                 }
 109 
 110 #define CLF_ISHIDDEN(var)       (printf("%s\n",                         \
 111                                     (((var)->flags) & CLF_HIDDEN) != 0   \
 112                                     ? "is hidden" : "not hidden"),      \
 113                                     ((((var)->flags) & CLF_HIDDEN) != 0))
 114 
 115 #define CLF_MODVAL(var)         {                                       \
 116                                         (((var)->flags) |=           \
 117                                         (CLF_VALMOD | CLF_VALSET));     \
 118                                         printf("modified %s\n", var->varname);\
 119                                 }
 120 
 121 #define CLF_ISMOD(var)          (printf("%s\n",                         \
 122                                     (((var)->flags) & CLF_VALMOD) != 0 \
 123                                     ? "is set" : "not set"),    \
 124                                     ((((var)->flags) & CLF_VALMOD) != 0))
 125 #else   /* DEBUG */
 126 
 127 #define CLF_SETVAL(var)         (((var)->flags) |= CLF_VALSET)
 128 #define CLF_ISSET(var)          ((((var)->flags) & CLF_VALSET) != 0)
 129 #define CLF_CLRHIDDEN(var)      (((var)->flags) &= ~CLF_HIDDEN)
 130 #define CLF_ISHIDDEN(var)       ((((var)->flags) & CLF_HIDDEN) != 0)
 131 #define CLF_MODVAL(var)         (((var)->flags) |= (CLF_VALMOD | CLF_VALSET))
 132 #define CLF_ISMOD(var)          ((((var)->flags) & CLF_VALMOD) != 0)
 133 
 134 #endif  /* DEBUG */
 135 
 136 /*
 137  * The width of the widest varname below - currently "subnet_mask".
 138  */
 139 #define VAR_MAXWIDTH    strlen(BI_SUBNET_MASK)
 140 
 141 struct cli_ent;
 142 typedef int claction_t(struct cli_ent *, char *, boolean_t);
 143 
 144 typedef struct cli_ent {
 145         char            *varname;
 146         claction_t      *action;
 147         int             flags;
 148         void            *varptr;
 149         uint_t          varlen;
 150         uint_t          varmax;
 151 } cli_ent_t;
 152 
 153 static cli_ent_t         *find_cli_ent(char *varstr);
 154 
 155 static char             cmdbuf[2048];                   /* interpreter buffer */
 156 static char             hostip[INET_ADDRSTRLEN];
 157 static char             subnet[INET_ADDRSTRLEN];
 158 static char             router[INET_ADDRSTRLEN];
 159 static char             hostname[MAXHOSTNAMELEN];
 160 static char             httpproxy[INET_ADDRSTRLEN + 5];         /* a.b.c.d:p */
 161 static char             bootserverURL[URL_MAX_STRLEN + 1];
 162 static unsigned char    clientid[WB_MAX_CID_LEN];
 163 static unsigned char    aeskey[AES_128_KEY_SIZE];
 164 static unsigned char    des3key[DES3_KEY_SIZE];
 165 static unsigned char    sha1key[WANBOOT_HMAC_KEY_SIZE];
 166 static boolean_t        args_specified_prompt = B_FALSE;
 167 
 168 extern bc_handle_t      bc_handle;
 169 extern int              getchar(void);
 170 
 171 static claction_t       clcid, clkey, clip, clstr, clurl, clhp;
 172 static claction_t       clhelp, cllist, clprompt, cldhcp, cltest, clgo, clexit;
 173 
 174 static cli_ent_t cli_list[] = {
 175         /*
 176          * Commands/bootargs:
 177          */
 178         { "test",               cltest,         CLF_ARG,
 179             NULL,               0,              0                       },
 180         { "dhcp",               cldhcp,         CLF_ARG,
 181             NULL,               0,              0                       },
 182         { "prompt",             clprompt,       CLF_CMD | CLF_ARG,
 183             NULL,               0,              0                       },
 184         { "list",               cllist,         CLF_CMD,
 185             NULL,               0,              0                       },
 186         { "help",               clhelp,         CLF_CMD,
 187             NULL,               0,              0                       },
 188         { "go",                 clgo,           CLF_CMD,
 189             NULL,               0,              0                       },
 190         { "exit",               clexit,         CLF_CMD,
 191             NULL,               0,              0                       },
 192 
 193         /*
 194          * Interface:
 195          */
 196         { BI_HOST_IP,           clip,           CLF_IF,
 197             hostip,             0,              sizeof (hostip)         },
 198         { BI_SUBNET_MASK,       clip,           CLF_IF,
 199             subnet,             0,              sizeof (subnet)         },
 200         { BI_ROUTER_IP,         clip,           CLF_IF,
 201             router,             0,              sizeof (router)         },
 202         { BI_HOSTNAME,          clstr,          CLF_IF,
 203             hostname,           0,              sizeof (hostname)       },
 204         { BI_HTTP_PROXY,        clhp,           CLF_IF,
 205             httpproxy,          0,              sizeof (httpproxy)      },
 206         { BI_CLIENT_ID,         clcid,          CLF_IF,
 207             clientid,           0,              sizeof (clientid)       },
 208 
 209         /*
 210          * Bootmisc:
 211          */
 212         { BI_AES_KEY,           clkey,          CLF_BM | CLF_HIDDEN,
 213             aeskey,             0,              sizeof (aeskey)         },
 214         { BI_3DES_KEY,          clkey,          CLF_BM | CLF_HIDDEN,
 215             des3key,            0,              sizeof (des3key)        },
 216         { BI_SHA1_KEY,          clkey,          CLF_BM | CLF_HIDDEN,
 217             sha1key,            0,              sizeof (sha1key)        },
 218         { BI_BOOTSERVER,        clurl,          CLF_BM,
 219             bootserverURL,      0,              sizeof (bootserverURL)  },
 220 };
 221 
 222 static int num_cli_ent = (sizeof (cli_list) / sizeof (cli_ent_t));
 223 
 224 /*
 225  * Fetch a line from the user, handling backspace appropriately.
 226  */
 227 static int
 228 editline(char *buf, int count)
 229 {
 230         int     i = 0;
 231         char    c;
 232 
 233         while (i < count - 1) {
 234                 c = getchar();
 235                 if (c == '\n') {
 236                         break;
 237                 } else if (c == '\b') {
 238                         /* Clear for backspace. */
 239                         if (i > 0)
 240                                 i--;
 241                         continue;
 242                 } else {
 243                         buf[i++] = c;
 244                 }
 245         }
 246         buf[i] = '\0';
 247         return (i);
 248 }
 249 
 250 /*
 251  * Assign a client-id to cliptr, or output cliptr's value as a client-id.
 252  * On assignment the value is specified in valstr, either in hexascii or
 253  * as a quoted string; on output its value is printed in hexascii.
 254  */
 255 static int
 256 clcid(cli_ent_t *cliptr, char *valstr, boolean_t out)
 257 {
 258         uint_t          len, vmax;
 259         boolean_t       hexascii = B_TRUE;
 260         char            buffer[2 * WB_MAX_CID_LEN + 1];
 261 
 262         if (out) {
 263                 len = cliptr->varlen * 2 + 1;
 264                 (void) octet_to_hexascii(cliptr->varptr, cliptr->varlen,
 265                     buffer, &len);
 266                 printf("%s", buffer);
 267                 return (CLI_CONT);
 268         } else {
 269                 len = strlen(valstr);
 270                 vmax = cliptr->varmax - 1;   /* space for the prefix */
 271 
 272                 /*
 273                  * Check whether the value is a quoted string; if so, strip
 274                  * the quotes and note that it's not in hexascii.
 275                  */
 276                 if ((valstr[0] == '"' || valstr[0] == '\'') &&
 277                     valstr[len-1] == valstr[0]) {
 278                         hexascii = B_FALSE;
 279                         ++valstr;
 280                         len -= 2;
 281                         valstr[len] = '\0';
 282                 } else {
 283                         /*
 284                          * If the value contains any non-hex digits assume
 285                          * that it's not in hexascii.
 286                          */
 287                         char    *p;
 288 
 289                         for (p = valstr; *p != '\0'; ++p) {
 290                                 if (!isxdigit(*p)) {
 291                                         hexascii = B_FALSE;
 292                                         break;
 293                                 }
 294                         }
 295                 }
 296 
 297                 if (hexascii) {
 298                         if (len > vmax * 2 ||
 299                             hexascii_to_octet(valstr, len,
 300                             (char *)(cliptr->varptr), &vmax) != 0) {
 301                                 return (CLI_FAIL);
 302                         }
 303                         cliptr->varlen = vmax;
 304                 } else {
 305                         if (len > vmax) {
 306                                 return (CLI_FAIL);
 307                         }
 308                         bcopy(valstr, cliptr->varptr, len);
 309                         cliptr->varlen = len;
 310                 }
 311 
 312                 return (CLI_SET);
 313         }
 314 }
 315 
 316 /*
 317  * Assign a key to cliptr, or output cliptr's value as a key.
 318  * On assignment the value is specified in valstr in hexascii;
 319  * on output its value is printed in hexascii, provided the key
 320  * was entered at the interpreter (not obtained from OBP and
 321  * thus hidden).
 322  */
 323 static int
 324 clkey(cli_ent_t *cliptr, char *valstr, boolean_t out)
 325 {
 326         uint_t  len, vmax;
 327 
 328         if (out) {
 329                 char buffer[2 * WANBOOT_MAXKEYLEN + 1];
 330 
 331                 if (!CLF_ISHIDDEN(cliptr)) {
 332                         len = cliptr->varlen * 2 + 1;
 333                         (void) octet_to_hexascii(cliptr->varptr,
 334                             cliptr->varlen, buffer, &len);
 335                         printf("%s", buffer);
 336                 } else {
 337                         printf("*HIDDEN*");
 338                 }
 339                 return (CLI_CONT);
 340         } else {
 341                 len = strlen(valstr);
 342                 vmax = cliptr->varmax;
 343                 if (len != vmax * 2 || hexascii_to_octet(valstr, len,
 344                     cliptr->varptr, &vmax) != 0) {
 345                         return (CLI_FAIL);
 346                 }
 347                 cliptr->varlen = vmax;
 348                 CLF_CLRHIDDEN(cliptr);
 349                 return (CLI_SET);
 350         }
 351 }
 352 
 353 /*
 354  * Assign an IP address to cliptr, or output cliptr's value as an
 355  * IP address.  On assignment the value is specified in valstr in
 356  * dotted-decimal format; on output its value is printed in dotted-
 357  * decimal format.
 358  */
 359 static int
 360 clip(cli_ent_t *cliptr, char *valstr, boolean_t out)
 361 {
 362         uint_t          len;
 363 
 364         if (out) {
 365                 printf("%s", (char *)cliptr->varptr);
 366                 return (CLI_CONT);
 367         }
 368 
 369         if (inet_addr(valstr) == (in_addr_t)-1 ||
 370             (len = strlen(valstr)) >= cliptr->varmax) {
 371                 return (CLI_FAIL);
 372         }
 373 
 374         (void) strcpy(cliptr->varptr, valstr);
 375         cliptr->varlen = len + 1;
 376         return (CLI_SET);
 377 }
 378 
 379 /*
 380  * Assign an arbitrary string to cliptr, or output cliptr's value as a string.
 381  */
 382 static int
 383 clstr(cli_ent_t *cliptr, char *valstr, boolean_t out)
 384 {
 385         uint_t  len;
 386 
 387         if (out) {
 388                 printf("%s", (char *)cliptr->varptr);
 389                 return (CLI_CONT);
 390         } else {
 391                 if ((len = strlen(valstr)) >= cliptr->varmax) {
 392                         return (CLI_FAIL);
 393                 } else {
 394                         (void) strcpy(cliptr->varptr, valstr);
 395                         cliptr->varlen = len + 1;
 396                         return (CLI_SET);
 397                 }
 398         }
 399 }
 400 
 401 /*
 402  * Assign a URL to cliptr (having verified the format), or output cliptr's
 403  * value as a URL.  The host must be specified in dotted-decimal, and the
 404  * scheme must not be https.
 405  */
 406 static int
 407 clurl(cli_ent_t *cliptr, char *valstr, boolean_t out)
 408 {
 409         url_t           u;
 410         uint_t          len;
 411 
 412         if (out) {
 413                 printf("%s", (char *)cliptr->varptr);
 414                 return (CLI_CONT);
 415         }
 416 
 417         if (url_parse(valstr, &u) != URL_PARSE_SUCCESS ||
 418             u.https || inet_addr(u.hport.hostname) == (in_addr_t)-1 ||
 419             (len = strlen(valstr)) >= cliptr->varmax) {
 420                 return (CLI_FAIL);
 421         }
 422 
 423         (void) strcpy(cliptr->varptr, valstr);
 424         cliptr->varlen = len + 1;
 425         return (CLI_SET);
 426 }
 427 
 428 /*
 429  * Assign a hostport to cliptr (having verified the format), or output cliptr's
 430  * value as a hostport.  The host must be specified in dotted-decimal.
 431  */
 432 static int
 433 clhp(cli_ent_t *cliptr, char *valstr, boolean_t out)
 434 {
 435         url_hport_t     u;
 436         uint_t          len;
 437 
 438         if (out) {
 439                 printf("%s", (char *)cliptr->varptr);
 440                 return (CLI_CONT);
 441         }
 442 
 443         if (url_parse_hostport(valstr, &u, URL_DFLT_PROXY_PORT) !=
 444             URL_PARSE_SUCCESS ||
 445             inet_addr(u.hostname) == (in_addr_t)-1 ||
 446             (len = strlen(valstr)) >= cliptr->varmax) {
 447                 return (CLI_FAIL);
 448         }
 449 
 450         (void) strcpy(cliptr->varptr, valstr);
 451         cliptr->varlen = len + 1;
 452         return (CLI_SET);
 453 }
 454 
 455 /*
 456  * Exit the interpreter and return to the booter.
 457  */
 458 /*ARGSUSED*/
 459 static int
 460 clgo(cli_ent_t *cliptr, char *valstr, boolean_t out)
 461 {
 462         return (CLI_EXIT);
 463 }
 464 
 465 /*
 466  * Exit the interpreter and return to OBP.
 467  */
 468 /*ARGSUSED*/
 469 static int
 470 clexit(cli_ent_t *cliptr, char *valstr, boolean_t out)
 471 {
 472         prom_exit_to_mon();
 473         /*NOTREACHED*/
 474         return (CLI_EXIT);
 475 }
 476 
 477 /*
 478  * Provide simple help information.
 479  */
 480 /*ARGSUSED*/
 481 static int
 482 clhelp(cli_ent_t *cliptr, char *valstr, boolean_t out)
 483 {
 484         printf("var=val         - set variable\n");
 485         printf("var=            - unset variable\n");
 486         printf("var             - print variable\n");
 487         printf("list            - list variables and their values\n");
 488         printf("prompt          - prompt for unset variables\n");
 489         printf("go              - continue booting\n");
 490         printf("exit            - quit boot interpreter and return to OBP\n");
 491 
 492         return (CLI_CONT);
 493 }
 494 
 495 /*
 496  * List variables and their current values.
 497  */
 498 /*ARGSUSED*/
 499 static int
 500 cllist(cli_ent_t *cliptr, char *valstr, boolean_t out)
 501 {
 502         int     wanted = (int)(uintptr_t)valstr; /* use uintptr_t for gcc */
 503         int     i;
 504 
 505         wanted  &= ~(CLF_CMD | CLF_ARG);
 506 
 507         for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; cliptr++) {
 508                 if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0 ||
 509                     (cliptr->flags & wanted) == 0) {
 510                         continue;
 511                 }
 512                 printf("%s: ", cliptr->varname);
 513                 /*
 514                  * Line the values up - space to the width of the widest
 515                  * varname + 1 for the ':'.
 516                  */
 517                 for (i = VAR_MAXWIDTH + 1 - strlen(cliptr->varname);
 518                     i > 0; --i) {
 519                         printf(" ");
 520                 }
 521 
 522                 if (CLF_ISSET(cliptr) || CLF_ISHIDDEN(cliptr)) {
 523                         (void) cliptr->action(cliptr, NULL, B_TRUE);
 524                         printf("\n");
 525                 } else {
 526                         printf("UNSET\n");
 527                 }
 528         }
 529 
 530         return (CLI_CONT);
 531 }
 532 
 533 /*
 534  * Prompt for wanted values.
 535  */
 536 /*ARGSUSED*/
 537 static int
 538 clprompt(cli_ent_t *cliptr, char *valstr, boolean_t out)
 539 {
 540         char    *p;
 541         int     wanted = (int)(uintptr_t)valstr; /* use uintrptr_t for gcc */
 542 
 543         /*
 544          * If processing boot arguments, simply note the fact that clprompt()
 545          * should be invoked later when other parameters may be supplied.
 546          */
 547         if ((wanted & CLF_ARG) != 0) {
 548                 args_specified_prompt = B_TRUE;
 549                 return (CLI_CONT);
 550         }
 551         wanted  &= ~(CLF_CMD | CLF_ARG);
 552 
 553         for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) {
 554                 if ((cliptr->flags & wanted) == 0) {
 555                         continue;
 556                 }
 557 
 558                 printf("%s", cliptr->varname);
 559                 if (CLF_ISSET(cliptr)) {
 560                         printf(" [");
 561                         (void) cliptr->action(cliptr, NULL, B_TRUE);
 562                         printf("]");
 563                 }
 564                 printf("? ");
 565                 (void) editline(cmdbuf, sizeof (cmdbuf));
 566                 printf("\n");
 567 
 568                 p = cmdbuf;
 569                 skipspace(p);
 570                 if (*p == '\0') {       /* nothing there */
 571                         continue;
 572                 }
 573 
 574                 /* Get valstr and nul terminate */
 575                 valstr = p;
 576                 ++p;
 577                 skiptext(p);
 578                 *p = '\0';
 579 
 580                 /* If empty value, do nothing */
 581                 if (strlen(valstr) == 0) {
 582                         continue;
 583                 }
 584 
 585                 switch (cliptr->action(cliptr, valstr, B_FALSE)) {
 586                 case CLI_SET:
 587                         CLF_MODVAL(cliptr);
 588                         break;
 589                 case CLI_FAIL:
 590                         printf("Incorrect format, parameter unchanged!\n");
 591                         break;
 592                 case CLI_EXIT:
 593                         return (CLI_EXIT);
 594                 case CLI_CONT:
 595                         break;
 596                 }
 597         }
 598 
 599         return (CLI_CONT);
 600 }
 601 
 602 /*
 603  * If the PROM has done DHCP, bind the interface; otherwise do the full
 604  * DHCP packet exchange.
 605  */
 606 /*ARGSUSED*/
 607 static int
 608 cldhcp(cli_ent_t *cliptr, char *valstr, boolean_t out)
 609 {
 610         static boolean_t        first_time = B_TRUE;
 611         static int              ret = CLI_CONT;
 612 
 613         if (first_time) {
 614                 /*
 615                  * Set DHCP's idea of the client_id from our cached value.
 616                  */
 617                 cliptr = find_cli_ent(BI_CLIENT_ID);
 618                 if (CLF_ISMOD(cliptr)) {
 619                         dhcp_set_client_id(cliptr->varptr, cliptr->varlen);
 620                 }
 621 
 622                 bootlog("wanboot", BOOTLOG_INFO, "Starting DHCP configuration");
 623 
 624                 (void) ipv4_setpromiscuous(B_TRUE);
 625                 if (dhcp() == 0) {
 626                         bootlog("wanboot", BOOTLOG_INFO,
 627                             "DHCP configuration succeeded");
 628                 } else {
 629                         bootlog("wanboot", BOOTLOG_CRIT,
 630                             "DHCP configuration failed");
 631                         ret = CLI_FAIL;
 632                 }
 633                 (void) ipv4_setpromiscuous(B_FALSE);
 634 
 635                 first_time = B_FALSE;
 636         }
 637 
 638         return (ret);
 639 }
 640 
 641 /*
 642  * Invoke the socket test interpreter (for testing purposes only).
 643  */
 644 /*ARGSUSED*/
 645 static int
 646 cltest(cli_ent_t *cliptr, char *valstr, boolean_t out)
 647 {
 648         (void) ipv4_setpromiscuous(B_FALSE);
 649         printf("\n");
 650         for (;;) {
 651                 printf(TEST_PROMPT);
 652                 if (editline(cmdbuf, sizeof (cmdbuf)) > 0) {
 653                         printf("\n");
 654                         (void) st_interpret(cmdbuf);
 655                 } else {
 656                         prom_exit_to_mon();
 657                         /* NOTREACHED */
 658                 }
 659         }
 660 
 661         /* NOTREACHED */
 662         return (CLI_CONT);
 663 }
 664 
 665 /*
 666  * Return the cliptr corresponding to the named variable.
 667  */
 668 static cli_ent_t *
 669 find_cli_ent(char *varstr)
 670 {
 671         cli_ent_t       *cliptr;
 672 
 673         for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) {
 674                 if (strcmp(varstr, cliptr->varname) == 0) {
 675                         return (cliptr);
 676                 }
 677         }
 678 
 679         return (NULL);
 680 }
 681 
 682 /*
 683  * Evaluate the commands provided by the user (either as "-o" boot arguments
 684  * or interactively at the boot interpreter).
 685  */
 686 static int
 687 cli_eval_buf(char *inbuf, int wanted)
 688 {
 689         char            *p, *varstr, *end_varstr, *valstr, *end_valstr;
 690         boolean_t       assign;
 691         cli_ent_t       *cliptr;
 692 
 693         for (p = inbuf; *p != '\0'; ) {
 694                 skipspace(p);
 695 
 696                 /* If nothing more on line, go get the next one */
 697                 if (*p == '\0') {
 698                         break;
 699                 } else if (*p == ',') {         /* orphan ',' ? */
 700                         ++p;
 701                         continue;
 702                 }
 703 
 704                 /* Get ptrs to start & end of variable */
 705                 varstr = p;
 706                 ++p;
 707                 skiptext(p);
 708                 end_varstr = p;
 709                 skipspace(p);
 710 
 711                 /* See if we're doing an assignment */
 712                 valstr = NULL;
 713                 if (*p != '=') {        /* nope, just printing */
 714                         assign = B_FALSE;
 715                 } else {
 716                         assign = B_TRUE;
 717                         ++p;                    /* past '=' */
 718                         skipspace(p);
 719 
 720                         /* Assigning something? (else clear variable) */
 721                         if (*p != '\0' && *p != ',') {
 722                                 /* Get ptrs to start & end of valstr */
 723                                 valstr = p;
 724                                 ++p;
 725                                 skiptext(p);
 726                                 end_valstr = p;
 727                                 skipspace(p);
 728                         }
 729                 }
 730 
 731                 /* Skip ',' delimiter if present */
 732                 if (*p == ',') {
 733                         ++p;
 734                 }
 735 
 736                 /* Nul-terminate varstr and valstr (if appropriate) */
 737                 *end_varstr = '\0';
 738                 if (valstr != NULL) {
 739                         *end_valstr = '\0';
 740                 }
 741 
 742                 if ((cliptr = find_cli_ent(varstr)) == NULL) {
 743                         printf("Unknown variable '%s'; ignored\n", varstr);
 744                         continue;
 745                 }
 746 
 747                 /*
 748                  * It's an error to specify a parameter which can only be a
 749                  * boot argument (and not a command) when not processing the
 750                  * boot arguments.
 751                  */
 752                 if ((cliptr->flags & (CLF_CMD | CLF_ARG)) == CLF_ARG &&
 753                     (wanted & CLF_ARG) == 0) {
 754                         printf("'%s' may only be specified as a "
 755                             "boot argument; ignored\n", varstr);
 756                         continue;
 757                 }
 758 
 759                 /*
 760                  * When doing an assignment, verify that it's not a command
 761                  * or argument name, and that it is permissible in the current
 762                  * context.  An 'empty' assignment (var=) is treated the same
 763                  * as a null assignment (var="").
 764                  *
 765                  * If processing the boot arguments, it is an error to not
 766                  * assign a value to a non-argument parameter.
 767                  */
 768                 if (assign) {
 769                         if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0) {
 770                                 printf("'%s' is a command and cannot "
 771                                     "be assigned\n", varstr);
 772                                 return (CLI_FAIL);
 773                         }
 774                         if ((cliptr->flags & wanted) == 0) {
 775                                 printf("'%s' cannot be assigned\n", varstr);
 776                                 return (CLI_FAIL);
 777                         }
 778 
 779                         if (valstr == NULL) {
 780                                 cliptr->varlen = 0;
 781                                 CLF_MODVAL(cliptr);
 782                                 continue;
 783                         }
 784                 } else if ((wanted & CLF_ARG) != 0 &&
 785                     (cliptr->flags & (CLF_CMD | CLF_ARG)) == 0) {
 786                         printf("'%s' must be assigned when specified in "
 787                             " the boot arguments\n", varstr);
 788                         return (CLI_FAIL);
 789                 }
 790 
 791                 /*
 792                  * Pass 'wanted' to command-handling functions, in particular
 793                  * clprompt() and cllist().
 794                  */
 795                 if ((cliptr->flags & CLF_CMD) != 0) {
 796                         /* use uintptr_t to suppress the gcc warning */
 797                         valstr = (char *)(uintptr_t)wanted;
 798                 }
 799 
 800                 /*
 801                  * Call the parameter's action function.
 802                  */
 803                 switch (cliptr->action(cliptr, valstr, !assign)) {
 804                 case CLI_SET:
 805                         CLF_MODVAL(cliptr);
 806                         break;
 807                 case CLI_FAIL:
 808                         printf("Incorrect format: variable '%s' not set\n",
 809                             cliptr->varname);
 810                         break;
 811                 case CLI_EXIT:
 812                         return (CLI_EXIT);
 813                 case CLI_CONT:
 814                         if (!assign) {
 815                                 printf("\n");
 816                         }
 817                         break;
 818                 }
 819         }
 820 
 821         return (CLI_CONT);
 822 }
 823 
 824 static void
 825 cli_interpret(int wanted)
 826 {
 827         printf("\n");
 828         do {
 829                 printf(PROMPT);
 830                 (void) editline(cmdbuf, sizeof (cmdbuf));
 831                 printf("\n");
 832 
 833         } while (cli_eval_buf(cmdbuf, wanted) != CLI_EXIT);
 834 }
 835 
 836 #if     defined(__sparcv9)
 837 /*
 838  * This routine queries the PROM to see what encryption keys exist.
 839  */
 840 static void
 841 get_prom_encr_keys()
 842 {
 843         cli_ent_t *cliptr;
 844         char encr_key[WANBOOT_MAXKEYLEN];
 845         int keylen;
 846         int status;
 847         int ret;
 848 
 849         /*
 850          * At the top of the priority list, we have AES.
 851          */
 852         ret = prom_get_security_key(WANBOOT_AES_128_KEY_NAME, encr_key,
 853             WANBOOT_MAXKEYLEN, &keylen, &status);
 854         if ((ret == 0) && (status == 0) && (keylen == AES_128_KEY_SIZE)) {
 855                 cliptr = find_cli_ent(BI_AES_KEY);
 856                 bcopy(encr_key, cliptr->varptr, AES_128_KEY_SIZE);
 857                 cliptr->varlen = AES_128_KEY_SIZE;
 858                 CLF_MODVAL(cliptr);
 859         }
 860 
 861         /*
 862          * Next, 3DES.
 863          */
 864         ret = prom_get_security_key(WANBOOT_DES3_KEY_NAME, encr_key,
 865             WANBOOT_MAXKEYLEN, &keylen, &status);
 866         if ((ret == 0) && (status == 0) && (keylen == DES3_KEY_SIZE)) {
 867                 cliptr = find_cli_ent(BI_3DES_KEY);
 868                 bcopy(encr_key, cliptr->varptr, DES3_KEY_SIZE);
 869                 cliptr->varlen = DES3_KEY_SIZE;
 870                 CLF_MODVAL(cliptr);
 871         }
 872 }
 873 
 874 /*
 875  * This routine queries the PROM to see what hashing keys exist.
 876  */
 877 static void
 878 get_prom_hash_keys()
 879 {
 880         cli_ent_t *cliptr;
 881         char hash_key[WANBOOT_HMAC_KEY_SIZE];
 882         int keylen;
 883         int status;
 884         int ret;
 885 
 886         /*
 887          * The only supported key thus far is SHA1.
 888          */
 889         ret = prom_get_security_key(WANBOOT_HMAC_SHA1_KEY_NAME, hash_key,
 890             WANBOOT_HMAC_KEY_SIZE, &keylen, &status);
 891         if ((ret == 0) && (status == 0) && (keylen == WANBOOT_HMAC_KEY_SIZE)) {
 892                 cliptr = find_cli_ent(BI_SHA1_KEY);
 893                 bcopy(hash_key, cliptr->varptr, WANBOOT_HMAC_KEY_SIZE);
 894                 cliptr->varlen = WANBOOT_HMAC_KEY_SIZE;
 895                 CLF_MODVAL(cliptr);
 896         }
 897 }
 898 #endif  /* defined(__sparcv9) */
 899 
 900 /*
 901  * For the given parameter type(s), get values from bootinfo and cache in
 902  * the local variables used by the "boot>" interpreter.
 903  */
 904 static void
 905 bootinfo_defaults(int which)
 906 {
 907         cli_ent_t       *cliptr;
 908 
 909         for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) {
 910                 if ((cliptr->flags & which) != 0 && !CLF_ISSET(cliptr)) {
 911                         size_t  len = cliptr->varmax;
 912 
 913                         if (bootinfo_get(cliptr->varname, cliptr->varptr,
 914                             &len, NULL) == BI_E_SUCCESS) {
 915                                 cliptr->varlen = len;
 916                                 CLF_SETVAL(cliptr);
 917                         }
 918                 }
 919         }
 920 }
 921 
 922 /*
 923  * For the given parameter type(s), store values entered at the "boot>"
 924  * interpreter back into bootinfo.
 925  */
 926 static void
 927 update_bootinfo(int which)
 928 {
 929         cli_ent_t       *cliptr;
 930 
 931         for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) {
 932                 if ((cliptr->flags & which) != 0 && CLF_ISMOD(cliptr)) {
 933                         (void) bootinfo_put(cliptr->varname,
 934                             cliptr->varptr, cliptr->varlen, 0);
 935                 }
 936         }
 937 }
 938 
 939 /*
 940  * Return the net-config-strategy: "dhcp", "manual" or "rarp"
 941  */
 942 static char *
 943 net_config_strategy(void)
 944 {
 945         static char     ncs[8];         /* "dhcp" or "manual" */
 946         size_t          len = sizeof (ncs);
 947 
 948         if (ncs[0] == '\0' &&
 949             bootinfo_get(BI_NET_CONFIG_STRATEGY, ncs, &len, NULL) !=
 950             BI_E_SUCCESS) {
 951                 /*
 952                  * Support for old PROMs: create the net-config-strategy
 953                  * property under /chosen with an appropriate value.  If we
 954                  * have a bootp-response (not interested in its value, just
 955                  * its presence) then we did DHCP; otherwise configuration
 956                  * is manual.
 957                  */
 958                 if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL,
 959                     NULL) == BI_E_BUF2SMALL) {
 960                         (void) strcpy(ncs, "dhcp");
 961                 } else {
 962                         (void) strcpy(ncs, "manual");
 963                 }
 964                 (void) bootinfo_put(BI_NET_CONFIG_STRATEGY, ncs, strlen(ncs),
 965                     BI_R_CHOSEN);
 966 
 967                 bootlog("wanboot", BOOTLOG_INFO,
 968                     "Default net-config-strategy: %s", ncs);
 969         }
 970 
 971         return (ncs);
 972 }
 973 
 974 /*
 975  * If there is no client-id property published in /chosen (by the PROM or the
 976  * boot interpreter) provide a default client-id based on the MAC address of
 977  * the client.
 978  * As specified in RFC2132 (section 9.14), this is prefixed with a byte
 979  * which specifies the ARP hardware type defined in RFC1700 (for Ethernet,
 980  * this should be 1).
 981  */
 982 static void
 983 generate_default_clientid(void)
 984 {
 985         char    clid[WB_MAX_CID_LEN];
 986         size_t  len = sizeof (clid);
 987 
 988         if (bootinfo_get(BI_CLIENT_ID, clid, &len, NULL) != BI_E_SUCCESS) {
 989                 len = mac_get_addr_len() + 1;   /* include hwtype */
 990 
 991                 if (len > sizeof (clid)) {
 992                         return;
 993                 }
 994 
 995                 clid[0] = mac_arp_type(mac_get_type());
 996                 bcopy(mac_get_addr_buf(), &clid[1], len - 1);
 997 
 998                 (void) bootinfo_put(BI_CLIENT_ID, clid, len, 0);
 999         }
1000 }
1001 
1002 /*
1003  * Determine the URL of the boot server from the 'file' parameter to OBP,
1004  * the SbootURI or BootFile DHCP options, or the 'bootserver' value entered
1005  * either as a "-o" argument or at the interpreter.
1006  */
1007 static void
1008 determine_bootserver_url(void)
1009 {
1010         char    bs[URL_MAX_STRLEN + 1];
1011         size_t  len;
1012         url_t   url;
1013 
1014         if (bootinfo_get(BI_BOOTSERVER, bs, &len, NULL) != BI_E_SUCCESS) {
1015                 /*
1016                  * If OBP has published a network-boot-file property in
1017                  * /chosen (or there is a DHCP BootFile or SbootURI vendor
1018                  * option) and it's a URL, construct the bootserver URL
1019                  * from it.
1020                  */
1021                 len = URL_MAX_STRLEN;
1022                 if (bootinfo_get(BI_NETWORK_BOOT_FILE, bs, &len, NULL) !=
1023                     BI_E_SUCCESS) {
1024                         len = URL_MAX_STRLEN;
1025                         if (bootinfo_get(BI_BOOTFILE, bs, &len, NULL) !=
1026                             BI_E_SUCCESS) {
1027                                 return;
1028                         }
1029                 }
1030                 if (url_parse(bs, &url) == URL_PARSE_SUCCESS) {
1031                         (void) bootinfo_put(BI_BOOTSERVER, bs, len, 0);
1032                 }
1033         }
1034 }
1035 
1036 /*
1037  * Provide a classful subnet mask based on the client's IP address.
1038  */
1039 static in_addr_t
1040 generate_classful_subnet(in_addr_t client_ipaddr)
1041 {
1042         struct in_addr  subnetmask;
1043         char            *netstr;
1044 
1045         if (IN_CLASSA(client_ipaddr)) {
1046                 subnetmask.s_addr = IN_CLASSA_NET;
1047         } else if (IN_CLASSB(client_ipaddr)) {
1048                 subnetmask.s_addr = IN_CLASSB_NET;
1049         } else if (IN_CLASSC(client_ipaddr)) {
1050                 subnetmask.s_addr = IN_CLASSC_NET;
1051         } else {
1052                 subnetmask.s_addr = IN_CLASSE_NET;
1053         }
1054 
1055         netstr = inet_ntoa(subnetmask);
1056         (void) bootinfo_put(BI_SUBNET_MASK, netstr, strlen(netstr) + 1, 0);
1057 
1058         return (subnetmask.s_addr);
1059 }
1060 
1061 /*
1062  * Informational output to the user (if interactive) or the bootlogger.
1063  */
1064 static void
1065 info(const char *msg, boolean_t interactive)
1066 {
1067         if (interactive) {
1068                 printf("%s\n", msg);
1069         } else {
1070                 bootlog("wanboot", BOOTLOG_INFO, "%s", msg);
1071         }
1072 }
1073 
1074 /*
1075  * Determine whether we have sufficient information to proceed with booting,
1076  * either for configuring the interface and downloading the bootconf file,
1077  * or for downloading the miniroot.
1078  */
1079 static int
1080 config_incomplete(int why, boolean_t interactive)
1081 {
1082         boolean_t               error = B_FALSE;
1083         char                    buf[URL_MAX_STRLEN + 1];
1084         size_t                  len;
1085         char                    *urlstr;
1086         url_t                   u;
1087         struct hostent          *hp;
1088         in_addr_t               client_ipaddr, ipaddr, bsnet, pxnet;
1089         static in_addr_t        subnetmask, clnet;
1090         static boolean_t        have_router = B_FALSE;
1091         static boolean_t        have_proxy = B_FALSE;
1092         boolean_t               have_root_server = B_FALSE;
1093         boolean_t               have_boot_logger = B_FALSE;
1094         in_addr_t               rsnet, blnet;
1095 
1096         /*
1097          * Note that 'have_router', 'have_proxy', 'subnetmask', and 'clnet'
1098          * are static, so that their values (gathered when checking the
1099          * interface configuration) may be used again when checking the boot
1100          * configuration.
1101          */
1102         if (why == CLF_IF) {
1103                 /*
1104                  * A valid host IP address is an absolute requirement.
1105                  */
1106                 len = sizeof (buf);
1107                 if (bootinfo_get(BI_HOST_IP, buf, &len, NULL) == BI_E_SUCCESS) {
1108                         if ((client_ipaddr = inet_addr(buf)) == (in_addr_t)-1) {
1109                                 info("host-ip invalid!", interactive);
1110                                 error = B_TRUE;
1111                         }
1112                 } else {
1113                         info("host-ip not set!", interactive);
1114                         error = B_TRUE;
1115                 }
1116 
1117                 /*
1118                  * If a subnet mask was provided, use it; otherwise infer it.
1119                  */
1120                 len = sizeof (buf);
1121                 if (bootinfo_get(BI_SUBNET_MASK, buf, &len, NULL) ==
1122                     BI_E_SUCCESS) {
1123                         if ((subnetmask = inet_addr(buf)) == (in_addr_t)-1) {
1124                                 info("subnet-mask invalid!", interactive);
1125                                 error = B_TRUE;
1126                         }
1127                 } else {
1128                         info("Defaulting to classful subnetting", interactive);
1129 
1130                         subnetmask = generate_classful_subnet(client_ipaddr);
1131                 }
1132                 clnet = client_ipaddr & subnetmask;
1133 
1134                 /*
1135                  * A legal bootserver URL is also an absolute requirement.
1136                  */
1137                 len = sizeof (buf);
1138                 if (bootinfo_get(BI_BOOTSERVER, buf, &len, NULL) ==
1139                     BI_E_SUCCESS) {
1140                         if (url_parse(buf, &u) != URL_PARSE_SUCCESS ||
1141                             u.https ||
1142                             (ipaddr = inet_addr(u.hport.hostname)) ==
1143                             (in_addr_t)-1) {
1144                                 info("bootserver not legal URL!", interactive);
1145                                 error = B_TRUE;
1146                         } else {
1147                                 bsnet = ipaddr & subnetmask;
1148                         }
1149                 } else {
1150                         info("bootserver not specified!", interactive);
1151                         error = B_TRUE;
1152                 }
1153 
1154                 /*
1155                  * Is there a correctly-defined router?
1156                  */
1157                 len = sizeof (buf);
1158                 if (bootinfo_get(BI_ROUTER_IP, buf, &len, NULL) ==
1159                     BI_E_SUCCESS) {
1160                         if ((ipaddr = inet_addr(buf)) == (in_addr_t)-1) {
1161                                 info("router-ip invalid!", interactive);
1162                                 error = B_TRUE;
1163                         } else if (clnet != (ipaddr & subnetmask)) {
1164                                 info("router not on local subnet!",
1165                                     interactive);
1166                                 error = B_TRUE;
1167                         } else {
1168                                 have_router = B_TRUE;
1169                         }
1170                 }
1171 
1172                 /*
1173                  * Is there a correctly-defined proxy?
1174                  */
1175                 len = sizeof (buf);
1176                 if (bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) ==
1177                     BI_E_SUCCESS) {
1178                         url_hport_t     u;
1179 
1180                         if (url_parse_hostport(buf, &u, URL_DFLT_PROXY_PORT) !=
1181                             URL_PARSE_SUCCESS ||
1182                             (ipaddr = inet_addr(u.hostname)) == (in_addr_t)-1) {
1183                                 info("http-proxy port invalid!", interactive);
1184                                 error = B_TRUE;
1185                         } else {
1186                                 /*
1187                                  * The proxy is only of use to us if it's on
1188                                  * our local subnet, or if a router has been
1189                                  * specified (which should hopefully allow us
1190                                  * to access the proxy).
1191                                  */
1192                                 pxnet = ipaddr & subnetmask;
1193                                 have_proxy = (have_router || pxnet == clnet);
1194                         }
1195                 }
1196 
1197                 /*
1198                  * If there is no router and no proxy (either on the local
1199                  * subnet or reachable via a router), then the bootserver
1200                  * URL must be on the local net.
1201                  */
1202                 if (!error && !have_router && !have_proxy && bsnet != clnet) {
1203                         info("bootserver URL not on local subnet",
1204                             interactive);
1205                         error = B_TRUE;
1206                 }
1207         } else {
1208                 /*
1209                  * There must be a correctly-defined root_server URL.
1210                  */
1211                 if ((urlstr = bootconf_get(&bc_handle,
1212                     BC_ROOT_SERVER)) == NULL) {
1213                         info("no root_server URL!", interactive);
1214                         error = B_TRUE;
1215                 } else if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) {
1216                         info("root_server not legal URL!", interactive);
1217                         error = B_TRUE;
1218                 } else if ((hp = gethostbyname(u.hport.hostname)) == NULL) {
1219                         info("cannot resolve root_server hostname!",
1220                             interactive);
1221                         error = B_TRUE;
1222                 } else {
1223                         rsnet = *(in_addr_t *)hp->h_addr & subnetmask;
1224                         have_root_server = B_TRUE;
1225                 }
1226 
1227                 /*
1228                  * Is there a correctly-defined (non-empty) boot_logger URL?
1229                  */
1230                 if ((urlstr = bootconf_get(&bc_handle,
1231                     BC_BOOT_LOGGER)) != NULL) {
1232                         if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) {
1233                                 info("boot_logger not legal URL!", interactive);
1234                                 error = B_TRUE;
1235                         } else if ((hp = gethostbyname(u.hport.hostname)) ==
1236                             NULL) {
1237                                 info("cannot resolve boot_logger hostname!",
1238                                     interactive);
1239                                 error = B_TRUE;
1240                         } else {
1241                                 blnet = *(in_addr_t *)hp->h_addr & subnetmask;
1242                                 have_boot_logger = B_TRUE;
1243                         }
1244                 }
1245 
1246                 /*
1247                  * If there is no router and no proxy (either on the local
1248                  * subnet or reachable via a router), then the root_server
1249                  * URL (and the boot_logger URL if specified) must be on the
1250                  * local net.
1251                  */
1252                 if (!error && !have_router && !have_proxy) {
1253                         if (have_root_server && rsnet != clnet) {
1254                                 info("root_server URL not on local subnet",
1255                                     interactive);
1256                                 error = B_TRUE;
1257                         }
1258                         if (have_boot_logger && blnet != clnet) {
1259                                 info("boot_logger URL not on local subnet",
1260                                     interactive);
1261                                 error = B_TRUE;
1262                         }
1263                 }
1264         }
1265 
1266         return (error);
1267 }
1268 
1269 /*
1270  * Actually setup our network interface with the values derived from the
1271  * PROM, DHCP or interactively from the user.
1272  */
1273 static void
1274 setup_interface()
1275 {
1276         char            str[MAXHOSTNAMELEN];    /* will accomodate an IP too */
1277         size_t          len;
1278         struct in_addr  in_addr;
1279 
1280         len = sizeof (str);
1281         if (bootinfo_get(BI_HOST_IP, str, &len, NULL) == BI_E_SUCCESS &&
1282             (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) {
1283                 in_addr.s_addr = htonl(in_addr.s_addr);
1284                 ipv4_setipaddr(&in_addr);
1285         }
1286 
1287         len = sizeof (str);
1288         if (bootinfo_get(BI_SUBNET_MASK, str, &len, NULL) == BI_E_SUCCESS &&
1289             (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) {
1290                 in_addr.s_addr = htonl(in_addr.s_addr);
1291                 ipv4_setnetmask(&in_addr);
1292         }
1293 
1294         len = sizeof (str);
1295         if (bootinfo_get(BI_ROUTER_IP, str, &len, NULL) == BI_E_SUCCESS &&
1296             (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) {
1297                 in_addr.s_addr = htonl(in_addr.s_addr);
1298                 ipv4_setdefaultrouter(&in_addr);
1299                 (void) ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, &in_addr);
1300         }
1301 
1302         len = sizeof (str);
1303         if (bootinfo_get(BI_HOSTNAME, str, &len, NULL) == BI_E_SUCCESS) {
1304                 (void) sethostname(str, len);
1305         }
1306 }
1307 
1308 /* EXPORT DELETE END */
1309 boolean_t
1310 wanboot_init_interface(char *boot_arguments)
1311 {
1312 /* EXPORT DELETE START */
1313         boolean_t       interactive;
1314         int             which;
1315 
1316 #if     defined(__sparcv9)
1317         /*
1318          * Get the keys from PROM before we allow the user
1319          * to override them from the CLI.
1320          */
1321         get_prom_encr_keys();
1322         get_prom_hash_keys();
1323 #endif  /* defined(__sparcv9) */
1324 
1325         /*
1326          * If there is already a bootp-response property under
1327          * /chosen then the PROM must have done DHCP for us;
1328          * invoke dhcp() to 'bind' the interface.
1329          */
1330         if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL, NULL) ==
1331             BI_E_BUF2SMALL) {
1332                 (void) cldhcp(NULL, NULL, 0);
1333         }
1334 
1335         /*
1336          * Obtain default interface values from bootinfo.
1337          */
1338         bootinfo_defaults(CLF_IF);
1339 
1340         /*
1341          * Process the boot arguments (following the "-o" option).
1342          */
1343         if (boot_arguments != NULL) {
1344                 (void) cli_eval_buf(boot_arguments,
1345                     (CLF_ARG | CLF_IF | CLF_BM));
1346         }
1347 
1348         /*
1349          * Stash away any interface/bootmisc parameter values we got
1350          * from either the PROM or the boot arguments.
1351          */
1352         update_bootinfo(CLF_IF | CLF_BM);
1353 
1354         /*
1355          * If we don't already have a value for bootserver, try to
1356          * deduce one.  Refresh wbcli's idea of these values.
1357          */
1358         determine_bootserver_url();
1359         bootinfo_defaults(CLF_BM);
1360 
1361         /*
1362          * Check that the information we have collected thus far is sufficient.
1363          */
1364         interactive = args_specified_prompt;
1365 
1366         if (interactive) {
1367                 /*
1368                  * Drop into the boot interpreter to allow the input
1369                  * of keys, bootserver and bootmisc, and in the case
1370                  * that net-config-strategy == "manual" the interface
1371                  * parameters.
1372                  */
1373                 which = CLF_BM | CLF_CMD;
1374                 if (strcmp(net_config_strategy(), "manual") == 0)
1375                         which |= CLF_IF;
1376 
1377                 do {
1378                         cli_interpret(which);
1379                         update_bootinfo(CLF_IF | CLF_BM);
1380                 } while (config_incomplete(CLF_IF, interactive));
1381         } else {
1382                 /*
1383                  * The user is not to be given the opportunity to
1384                  * enter further values; fail.
1385                  */
1386                 if (config_incomplete(CLF_IF, interactive)) {
1387                         bootlog("wanboot", BOOTLOG_CRIT,
1388                             "interface incorrectly configured");
1389                         return (B_FALSE);
1390                 }
1391         }
1392 
1393         /*
1394          * If a wanboot-enabled PROM hasn't processed client-id in
1395          * network-boot-arguments, or no value for client-id has been
1396          * specified to the boot interpreter, then provide a default
1397          * client-id based on our MAC address.
1398          */
1399         generate_default_clientid();
1400 
1401         /*
1402          * If net-config-strategy == "manual" then we must setup
1403          * the interface now; if "dhcp" then it will already have
1404          * been setup.
1405          */
1406         if (strcmp(net_config_strategy(), "manual") == 0)
1407                 setup_interface();
1408 /* EXPORT DELETE END */
1409         return (B_TRUE);
1410 }
1411 
1412 boolean_t
1413 wanboot_verify_config(void)
1414 {
1415 /* EXPORT DELETE START */
1416         /*
1417          * Check that the wanboot.conf file defines a valid root_server
1418          * URL, and check that, if given, the boot_logger URL is valid.
1419          */
1420         if (config_incomplete(0, B_FALSE)) {
1421                 bootlog("wanboot", BOOTLOG_CRIT,
1422                     "incomplete boot configuration");
1423                 return (B_FALSE);
1424         }
1425 /* EXPORT DELETE END */
1426         return (B_TRUE);
1427 }