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