10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*785Seota * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* EXPORT DELETE START */ 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/salib.h> 330Sstevel@tonic-gate #include <sys/promif.h> 340Sstevel@tonic-gate #include <sys/wanboot_impl.h> 350Sstevel@tonic-gate #include <netinet/in.h> 360Sstevel@tonic-gate #include <parseURL.h> 370Sstevel@tonic-gate #include <bootlog.h> 380Sstevel@tonic-gate #include <sys/socket.h> 390Sstevel@tonic-gate #include <netinet/inetutil.h> 400Sstevel@tonic-gate #include <netinet/dhcp.h> 410Sstevel@tonic-gate #include <dhcp_impl.h> 420Sstevel@tonic-gate #include <lib/inet/mac.h> 430Sstevel@tonic-gate #include <lib/inet/ipv4.h> 440Sstevel@tonic-gate #include <lib/inet/dhcpv4.h> 450Sstevel@tonic-gate #include <lib/sock/sock_test.h> 460Sstevel@tonic-gate #include <sys/sunos_dhcp_class.h> 470Sstevel@tonic-gate #include <aes.h> 480Sstevel@tonic-gate #include <des3.h> 490Sstevel@tonic-gate #include <hmac_sha1.h> 500Sstevel@tonic-gate #include <netdb.h> 510Sstevel@tonic-gate #include <wanboot_conf.h> 520Sstevel@tonic-gate #include <bootinfo.h> 530Sstevel@tonic-gate /* EXPORT DELETE END */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include "wbcli.h" 560Sstevel@tonic-gate 570Sstevel@tonic-gate /* EXPORT DELETE START */ 580Sstevel@tonic-gate 590Sstevel@tonic-gate #define skipspace(p) while (isspace(*(p))) ++p 600Sstevel@tonic-gate 610Sstevel@tonic-gate #define skiptext(p) while (*(p) != '\0' && !isspace(*(p)) && \ 620Sstevel@tonic-gate *(p) != '=' && *(p) != ',') ++p 630Sstevel@tonic-gate 640Sstevel@tonic-gate #define PROMPT "boot> " 650Sstevel@tonic-gate #define TEST_PROMPT "boot-test> " 660Sstevel@tonic-gate 670Sstevel@tonic-gate #define CLI_SET 0 680Sstevel@tonic-gate #define CLI_FAIL (-1) 690Sstevel@tonic-gate #define CLI_EXIT (-2) 700Sstevel@tonic-gate #define CLI_CONT (-3) 710Sstevel@tonic-gate 720Sstevel@tonic-gate #define CLF_CMD 0x00000001 /* builtin command */ 730Sstevel@tonic-gate #define CLF_ARG 0x00000002 /* boot argument directive */ 740Sstevel@tonic-gate 750Sstevel@tonic-gate #define CLF_IF 0x00000100 /* interface parameter */ 760Sstevel@tonic-gate #define CLF_BM 0x00000200 /* bootmisc parameter */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate #define CLF_VALSET 0x00010000 /* value set, may be null */ 790Sstevel@tonic-gate #define CLF_HIDDEN 0x00020000 /* don't show its value (key) */ 800Sstevel@tonic-gate #define CLF_VALMOD 0x00040000 /* value modified by the user */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * Macros for use in managing the flags in the cli_list[]. 840Sstevel@tonic-gate * The conventions we follow are: 850Sstevel@tonic-gate * 860Sstevel@tonic-gate * CLF_VALSET is cleared if a value is removed from varptr 870Sstevel@tonic-gate * CLF_VALSET is set if a value has been placed in varptr 880Sstevel@tonic-gate * (that value need not be vetted) 890Sstevel@tonic-gate * CLF_HIDDEN is set if a value must not be exposed to the user 900Sstevel@tonic-gate * CLF_HIDDEN is cleared if a value can be exposed to the user 910Sstevel@tonic-gate * CLF_VALMOD is cleared if a value in varptr has not been modified 920Sstevel@tonic-gate * CLF_VALMOD is set if a value in varptr has been modified by 930Sstevel@tonic-gate * the user 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate #ifdef DEBUG 960Sstevel@tonic-gate #define CLF_SETVAL(var) { \ 970Sstevel@tonic-gate (((var)->flags) |= CLF_VALSET); \ 980Sstevel@tonic-gate printf("set %s\n", var->varname);\ 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate #define CLF_ISSET(var) (printf("%s\n", \ 1020Sstevel@tonic-gate (((var)->flags) & CLF_VALSET) != 0 \ 1030Sstevel@tonic-gate ? "is set" : "not set"), \ 1040Sstevel@tonic-gate ((((var)->flags) & CLF_VALSET) != 0)) 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate #define CLF_CLRHIDDEN(var) { \ 1070Sstevel@tonic-gate (((var)->flags) &= ~CLF_HIDDEN); \ 1080Sstevel@tonic-gate printf("unhide %s\n", var->varname); \ 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate #define CLF_ISHIDDEN(var) (printf("%s\n", \ 1120Sstevel@tonic-gate (((var)->flags) & CLF_HIDDEN) != 0 \ 1130Sstevel@tonic-gate ? "is hidden" : "not hidden"), \ 1140Sstevel@tonic-gate ((((var)->flags) & CLF_HIDDEN) != 0)) 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate #define CLF_MODVAL(var) { \ 1170Sstevel@tonic-gate (((var)->flags) |= \ 1180Sstevel@tonic-gate (CLF_VALMOD | CLF_VALSET)); \ 1190Sstevel@tonic-gate printf("modified %s\n", var->varname);\ 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate #define CLF_ISMOD(var) (printf("%s\n", \ 1230Sstevel@tonic-gate (((var)->flags) & CLF_VALMOD) != 0 \ 1240Sstevel@tonic-gate ? "is set" : "not set"), \ 1250Sstevel@tonic-gate ((((var)->flags) & CLF_VALMOD) != 0)) 1260Sstevel@tonic-gate #else /* DEBUG */ 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate #define CLF_SETVAL(var) (((var)->flags) |= CLF_VALSET) 1290Sstevel@tonic-gate #define CLF_ISSET(var) ((((var)->flags) & CLF_VALSET) != 0) 1300Sstevel@tonic-gate #define CLF_CLRHIDDEN(var) (((var)->flags) &= ~CLF_HIDDEN) 1310Sstevel@tonic-gate #define CLF_ISHIDDEN(var) ((((var)->flags) & CLF_HIDDEN) != 0) 1320Sstevel@tonic-gate #define CLF_MODVAL(var) (((var)->flags) |= (CLF_VALMOD | CLF_VALSET)) 1330Sstevel@tonic-gate #define CLF_ISMOD(var) ((((var)->flags) & CLF_VALMOD) != 0) 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate #endif /* DEBUG */ 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * The width of the widest varname below - currently "subnet_mask". 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate #define VAR_MAXWIDTH strlen(BI_SUBNET_MASK) 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate struct cli_ent; 1430Sstevel@tonic-gate typedef int claction_t(struct cli_ent *, char *, boolean_t); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate typedef struct cli_ent { 1460Sstevel@tonic-gate char *varname; 1470Sstevel@tonic-gate claction_t *action; 1480Sstevel@tonic-gate int flags; 1490Sstevel@tonic-gate void *varptr; 1500Sstevel@tonic-gate uint_t varlen; 1510Sstevel@tonic-gate uint_t varmax; 1520Sstevel@tonic-gate } cli_ent_t; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate static cli_ent_t *find_cli_ent(char *varstr); 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate static char cmdbuf[2048]; /* interpreter buffer */ 1570Sstevel@tonic-gate static char hostip[INET_ADDRSTRLEN]; 1580Sstevel@tonic-gate static char subnet[INET_ADDRSTRLEN]; 1590Sstevel@tonic-gate static char router[INET_ADDRSTRLEN]; 1600Sstevel@tonic-gate static char hostname[MAXHOSTNAMELEN]; 1610Sstevel@tonic-gate static char httpproxy[INET_ADDRSTRLEN + 5]; /* a.b.c.d:p */ 1620Sstevel@tonic-gate static char bootserverURL[URL_MAX_STRLEN + 1]; 1630Sstevel@tonic-gate static unsigned char clientid[WB_MAX_CID_LEN]; 1640Sstevel@tonic-gate static unsigned char aeskey[AES_128_KEY_SIZE]; 1650Sstevel@tonic-gate static unsigned char des3key[DES3_KEY_SIZE]; 1660Sstevel@tonic-gate static unsigned char sha1key[WANBOOT_HMAC_KEY_SIZE]; 1670Sstevel@tonic-gate static boolean_t args_specified_prompt = B_FALSE; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate extern bc_handle_t bc_handle; 1700Sstevel@tonic-gate extern int getchar(void); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate static claction_t clcid, clkey, clip, clstr, clurl, clhp; 1730Sstevel@tonic-gate static claction_t clhelp, cllist, clprompt, cldhcp, cltest, clgo, clexit; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate static cli_ent_t cli_list[] = { 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Commands/bootargs: 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate { "test", cltest, CLF_ARG, 1800Sstevel@tonic-gate NULL, 0, 0 }, 1810Sstevel@tonic-gate { "dhcp", cldhcp, CLF_ARG, 1820Sstevel@tonic-gate NULL, 0, 0 }, 1830Sstevel@tonic-gate { "prompt", clprompt, CLF_CMD | CLF_ARG, 1840Sstevel@tonic-gate NULL, 0, 0 }, 1850Sstevel@tonic-gate { "list", cllist, CLF_CMD, 1860Sstevel@tonic-gate NULL, 0, 0 }, 1870Sstevel@tonic-gate { "help", clhelp, CLF_CMD, 1880Sstevel@tonic-gate NULL, 0, 0 }, 1890Sstevel@tonic-gate { "go", clgo, CLF_CMD, 1900Sstevel@tonic-gate NULL, 0, 0 }, 1910Sstevel@tonic-gate { "exit", clexit, CLF_CMD, 1920Sstevel@tonic-gate NULL, 0, 0 }, 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * Interface: 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate { BI_HOST_IP, clip, CLF_IF, 1980Sstevel@tonic-gate hostip, 0, sizeof (hostip) }, 1990Sstevel@tonic-gate { BI_SUBNET_MASK, clip, CLF_IF, 2000Sstevel@tonic-gate subnet, 0, sizeof (subnet) }, 2010Sstevel@tonic-gate { BI_ROUTER_IP, clip, CLF_IF, 2020Sstevel@tonic-gate router, 0, sizeof (router) }, 2030Sstevel@tonic-gate { BI_HOSTNAME, clstr, CLF_IF, 2040Sstevel@tonic-gate hostname, 0, sizeof (hostname) }, 2050Sstevel@tonic-gate { BI_HTTP_PROXY, clhp, CLF_IF, 2060Sstevel@tonic-gate httpproxy, 0, sizeof (httpproxy) }, 2070Sstevel@tonic-gate { BI_CLIENT_ID, clcid, CLF_IF, 2080Sstevel@tonic-gate clientid, 0, sizeof (clientid) }, 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Bootmisc: 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate { BI_AES_KEY, clkey, CLF_BM | CLF_HIDDEN, 2140Sstevel@tonic-gate aeskey, 0, sizeof (aeskey) }, 2150Sstevel@tonic-gate { BI_3DES_KEY, clkey, CLF_BM | CLF_HIDDEN, 2160Sstevel@tonic-gate des3key, 0, sizeof (des3key) }, 2170Sstevel@tonic-gate { BI_SHA1_KEY, clkey, CLF_BM | CLF_HIDDEN, 2180Sstevel@tonic-gate sha1key, 0, sizeof (sha1key) }, 2190Sstevel@tonic-gate { BI_BOOTSERVER, clurl, CLF_BM, 2200Sstevel@tonic-gate bootserverURL, 0, sizeof (bootserverURL) }, 2210Sstevel@tonic-gate }; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate static int num_cli_ent = (sizeof (cli_list) / sizeof (cli_ent_t)); 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * Fetch a line from the user, handling backspace appropriately. 2270Sstevel@tonic-gate */ 2280Sstevel@tonic-gate static int 2290Sstevel@tonic-gate editline(char *buf, int count) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate int i = 0; 2320Sstevel@tonic-gate char c; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate while (i < count - 1) { 2350Sstevel@tonic-gate c = getchar(); 2360Sstevel@tonic-gate if (c == '\n') { 2370Sstevel@tonic-gate break; 2380Sstevel@tonic-gate } else if (c == '\b') { 2390Sstevel@tonic-gate /* Clear for backspace. */ 2400Sstevel@tonic-gate if (i > 0) 2410Sstevel@tonic-gate i--; 2420Sstevel@tonic-gate continue; 2430Sstevel@tonic-gate } else { 2440Sstevel@tonic-gate buf[i++] = c; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate buf[i] = '\0'; 2480Sstevel@tonic-gate return (i); 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * Assign a client-id to cliptr, or output cliptr's value as a client-id. 2530Sstevel@tonic-gate * On assignment the value is specified in valstr, either in hexascii or 2540Sstevel@tonic-gate * as a quoted string; on output its value is printed in hexascii. 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate static int 2570Sstevel@tonic-gate clcid(cli_ent_t *cliptr, char *valstr, boolean_t out) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate uint_t len, vmax; 2600Sstevel@tonic-gate boolean_t hexascii = B_TRUE; 2610Sstevel@tonic-gate char buffer[2 * WB_MAX_CID_LEN + 1]; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate if (out) { 2640Sstevel@tonic-gate len = cliptr->varlen * 2 + 1; 2650Sstevel@tonic-gate (void) octet_to_hexascii(cliptr->varptr, cliptr->varlen, 2660Sstevel@tonic-gate buffer, &len); 2670Sstevel@tonic-gate printf("%s", buffer); 2680Sstevel@tonic-gate return (CLI_CONT); 2690Sstevel@tonic-gate } else { 2700Sstevel@tonic-gate len = strlen(valstr); 2710Sstevel@tonic-gate vmax = cliptr->varmax - 1; /* space for the prefix */ 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * Check whether the value is a quoted string; if so, strip 2750Sstevel@tonic-gate * the quotes and note that it's not in hexascii. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate if ((valstr[0] == '"' || valstr[0] == '\'') && 2780Sstevel@tonic-gate valstr[len-1] == valstr[0]) { 2790Sstevel@tonic-gate hexascii = B_FALSE; 2800Sstevel@tonic-gate ++valstr; 2810Sstevel@tonic-gate len -= 2; 2820Sstevel@tonic-gate valstr[len] = '\0'; 2830Sstevel@tonic-gate } else { 2840Sstevel@tonic-gate /* 2850Sstevel@tonic-gate * If the value contains any non-hex digits assume 2860Sstevel@tonic-gate * that it's not in hexascii. 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate char *p; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate for (p = valstr; *p != '\0'; ++p) { 2910Sstevel@tonic-gate if (!isxdigit(*p)) { 2920Sstevel@tonic-gate hexascii = B_FALSE; 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate if (hexascii) { 2990Sstevel@tonic-gate if (len > vmax * 2 || 3000Sstevel@tonic-gate hexascii_to_octet(valstr, len, 3010Sstevel@tonic-gate (char *)(cliptr->varptr), &vmax) != 0) { 3020Sstevel@tonic-gate return (CLI_FAIL); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate cliptr->varlen = vmax; 3050Sstevel@tonic-gate } else { 3060Sstevel@tonic-gate if (len > vmax) { 3070Sstevel@tonic-gate return (CLI_FAIL); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate bcopy(valstr, cliptr->varptr, len); 3100Sstevel@tonic-gate cliptr->varlen = len; 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate return (CLI_SET); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Assign a key to cliptr, or output cliptr's value as a key. 3190Sstevel@tonic-gate * On assignment the value is specified in valstr in hexascii; 3200Sstevel@tonic-gate * on output its value is printed in hexascii, provided the key 3210Sstevel@tonic-gate * was entered at the interpreter (not obtained from OBP and 3220Sstevel@tonic-gate * thus hidden). 3230Sstevel@tonic-gate */ 3240Sstevel@tonic-gate static int 3250Sstevel@tonic-gate clkey(cli_ent_t *cliptr, char *valstr, boolean_t out) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate uint_t len, vmax; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate if (out) { 3300Sstevel@tonic-gate char buffer[2 * WANBOOT_MAXKEYLEN + 1]; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate if (!CLF_ISHIDDEN(cliptr)) { 3330Sstevel@tonic-gate len = cliptr->varlen * 2 + 1; 3340Sstevel@tonic-gate (void) octet_to_hexascii(cliptr->varptr, 3350Sstevel@tonic-gate cliptr->varlen, buffer, &len); 3360Sstevel@tonic-gate printf("%s", buffer); 3370Sstevel@tonic-gate } else { 3380Sstevel@tonic-gate printf("*HIDDEN*"); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate return (CLI_CONT); 3410Sstevel@tonic-gate } else { 3420Sstevel@tonic-gate len = strlen(valstr); 3430Sstevel@tonic-gate vmax = cliptr->varmax; 3440Sstevel@tonic-gate if (len != vmax * 2 || hexascii_to_octet(valstr, len, 3450Sstevel@tonic-gate cliptr->varptr, &vmax) != 0) { 3460Sstevel@tonic-gate return (CLI_FAIL); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate cliptr->varlen = vmax; 3490Sstevel@tonic-gate CLF_CLRHIDDEN(cliptr); 3500Sstevel@tonic-gate return (CLI_SET); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Assign an IP address to cliptr, or output cliptr's value as an 3560Sstevel@tonic-gate * IP address. On assignment the value is specified in valstr in 3570Sstevel@tonic-gate * dotted-decimal format; on output its value is printed in dotted- 3580Sstevel@tonic-gate * decimal format. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate static int 3610Sstevel@tonic-gate clip(cli_ent_t *cliptr, char *valstr, boolean_t out) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate uint_t len; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate if (out) { 3660Sstevel@tonic-gate printf("%s", (char *)cliptr->varptr); 3670Sstevel@tonic-gate return (CLI_CONT); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (inet_addr(valstr) == (in_addr_t)-1 || 3710Sstevel@tonic-gate (len = strlen(valstr)) >= cliptr->varmax) { 3720Sstevel@tonic-gate return (CLI_FAIL); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate (void) strcpy(cliptr->varptr, valstr); 3760Sstevel@tonic-gate cliptr->varlen = len + 1; 3770Sstevel@tonic-gate return (CLI_SET); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * Assign an arbitrary string to cliptr, or output cliptr's value as a string. 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate static int 3840Sstevel@tonic-gate clstr(cli_ent_t *cliptr, char *valstr, boolean_t out) 3850Sstevel@tonic-gate { 3860Sstevel@tonic-gate uint_t len; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate if (out) { 3890Sstevel@tonic-gate printf("%s", (char *)cliptr->varptr); 3900Sstevel@tonic-gate return (CLI_CONT); 3910Sstevel@tonic-gate } else { 3920Sstevel@tonic-gate if ((len = strlen(valstr)) >= cliptr->varmax) { 3930Sstevel@tonic-gate return (CLI_FAIL); 3940Sstevel@tonic-gate } else { 3950Sstevel@tonic-gate (void) strcpy(cliptr->varptr, valstr); 3960Sstevel@tonic-gate cliptr->varlen = len + 1; 3970Sstevel@tonic-gate return (CLI_SET); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* 4030Sstevel@tonic-gate * Assign a URL to cliptr (having verified the format), or output cliptr's 4040Sstevel@tonic-gate * value as a URL. The host must be specified in dotted-decimal, and the 4050Sstevel@tonic-gate * scheme must not be https. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate static int 4080Sstevel@tonic-gate clurl(cli_ent_t *cliptr, char *valstr, boolean_t out) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate url_t u; 4110Sstevel@tonic-gate uint_t len; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate if (out) { 4140Sstevel@tonic-gate printf("%s", (char *)cliptr->varptr); 4150Sstevel@tonic-gate return (CLI_CONT); 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate if (url_parse(valstr, &u) != URL_PARSE_SUCCESS || 4190Sstevel@tonic-gate u.https || inet_addr(u.hport.hostname) == (in_addr_t)-1 || 4200Sstevel@tonic-gate (len = strlen(valstr)) >= cliptr->varmax) { 4210Sstevel@tonic-gate return (CLI_FAIL); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate (void) strcpy(cliptr->varptr, valstr); 4250Sstevel@tonic-gate cliptr->varlen = len + 1; 4260Sstevel@tonic-gate return (CLI_SET); 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* 4300Sstevel@tonic-gate * Assign a hostport to cliptr (having verified the format), or output cliptr's 4310Sstevel@tonic-gate * value as a hostport. The host must be specified in dotted-decimal. 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate static int 4340Sstevel@tonic-gate clhp(cli_ent_t *cliptr, char *valstr, boolean_t out) 4350Sstevel@tonic-gate { 4360Sstevel@tonic-gate url_hport_t u; 4370Sstevel@tonic-gate uint_t len; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate if (out) { 4400Sstevel@tonic-gate printf("%s", (char *)cliptr->varptr); 4410Sstevel@tonic-gate return (CLI_CONT); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (url_parse_hostport(valstr, &u, URL_DFLT_PROXY_PORT) != 4450Sstevel@tonic-gate URL_PARSE_SUCCESS || 4460Sstevel@tonic-gate inet_addr(u.hostname) == (in_addr_t)-1 || 4470Sstevel@tonic-gate (len = strlen(valstr)) >= cliptr->varmax) { 4480Sstevel@tonic-gate return (CLI_FAIL); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate (void) strcpy(cliptr->varptr, valstr); 4520Sstevel@tonic-gate cliptr->varlen = len + 1; 4530Sstevel@tonic-gate return (CLI_SET); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * Exit the interpreter and return to the booter. 4580Sstevel@tonic-gate */ 4590Sstevel@tonic-gate /*ARGSUSED*/ 4600Sstevel@tonic-gate static int 4610Sstevel@tonic-gate clgo(cli_ent_t *cliptr, char *valstr, boolean_t out) 4620Sstevel@tonic-gate { 4630Sstevel@tonic-gate return (CLI_EXIT); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * Exit the interpreter and return to OBP. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate /*ARGSUSED*/ 4700Sstevel@tonic-gate static int 4710Sstevel@tonic-gate clexit(cli_ent_t *cliptr, char *valstr, boolean_t out) 4720Sstevel@tonic-gate { 4730Sstevel@tonic-gate prom_exit_to_mon(); 4740Sstevel@tonic-gate /*NOTREACHED*/ 4750Sstevel@tonic-gate return (CLI_EXIT); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * Provide simple help information. 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate /*ARGSUSED*/ 4820Sstevel@tonic-gate static int 4830Sstevel@tonic-gate clhelp(cli_ent_t *cliptr, char *valstr, boolean_t out) 4840Sstevel@tonic-gate { 4850Sstevel@tonic-gate printf("var=val - set variable\n"); 4860Sstevel@tonic-gate printf("var= - unset variable\n"); 4870Sstevel@tonic-gate printf("var - print variable\n"); 4880Sstevel@tonic-gate printf("list - list variables and their values\n"); 4890Sstevel@tonic-gate printf("prompt - prompt for unset variables\n"); 4900Sstevel@tonic-gate printf("go - continue booting\n"); 4910Sstevel@tonic-gate printf("exit - quit boot interpreter and return to OBP\n"); 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate return (CLI_CONT); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* 4970Sstevel@tonic-gate * List variables and their current values. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate /*ARGSUSED*/ 5000Sstevel@tonic-gate static int 5010Sstevel@tonic-gate cllist(cli_ent_t *cliptr, char *valstr, boolean_t out) 5020Sstevel@tonic-gate { 503*785Seota int wanted = (int)(uintptr_t)valstr; /* use uintptr_t for gcc */ 5040Sstevel@tonic-gate int i; 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate wanted &= ~(CLF_CMD | CLF_ARG); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; cliptr++) { 5090Sstevel@tonic-gate if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0 || 5100Sstevel@tonic-gate (cliptr->flags & wanted) == 0) { 5110Sstevel@tonic-gate continue; 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate printf("%s: ", cliptr->varname); 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Line the values up - space to the width of the widest 5160Sstevel@tonic-gate * varname + 1 for the ':'. 5170Sstevel@tonic-gate */ 5180Sstevel@tonic-gate for (i = VAR_MAXWIDTH + 1 - strlen(cliptr->varname); 5190Sstevel@tonic-gate i > 0; --i) { 5200Sstevel@tonic-gate printf(" "); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate if (CLF_ISSET(cliptr) || CLF_ISHIDDEN(cliptr)) { 5240Sstevel@tonic-gate (void) cliptr->action(cliptr, NULL, B_TRUE); 5250Sstevel@tonic-gate printf("\n"); 5260Sstevel@tonic-gate } else { 5270Sstevel@tonic-gate printf("UNSET\n"); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate return (CLI_CONT); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Prompt for wanted values. 5360Sstevel@tonic-gate */ 5370Sstevel@tonic-gate /*ARGSUSED*/ 5380Sstevel@tonic-gate static int 5390Sstevel@tonic-gate clprompt(cli_ent_t *cliptr, char *valstr, boolean_t out) 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate char *p; 542*785Seota int wanted = (int)(uintptr_t)valstr; /* use uintrptr_t for gcc */ 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * If processing boot arguments, simply note the fact that clprompt() 5460Sstevel@tonic-gate * should be invoked later when other parameters may be supplied. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate if ((wanted & CLF_ARG) != 0) { 5490Sstevel@tonic-gate args_specified_prompt = B_TRUE; 5500Sstevel@tonic-gate return (CLI_CONT); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate wanted &= ~(CLF_CMD | CLF_ARG); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { 5550Sstevel@tonic-gate if ((cliptr->flags & wanted) == 0) { 5560Sstevel@tonic-gate continue; 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate printf("%s", cliptr->varname); 5600Sstevel@tonic-gate if (CLF_ISSET(cliptr)) { 5610Sstevel@tonic-gate printf(" ["); 5620Sstevel@tonic-gate (void) cliptr->action(cliptr, NULL, B_TRUE); 5630Sstevel@tonic-gate printf("]"); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate printf("? "); 5660Sstevel@tonic-gate (void) editline(cmdbuf, sizeof (cmdbuf)); 5670Sstevel@tonic-gate printf("\n"); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate p = cmdbuf; 5700Sstevel@tonic-gate skipspace(p); 5710Sstevel@tonic-gate if (*p == '\0') { /* nothing there */ 5720Sstevel@tonic-gate continue; 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* Get valstr and nul terminate */ 5760Sstevel@tonic-gate valstr = p; 5770Sstevel@tonic-gate ++p; 5780Sstevel@tonic-gate skiptext(p); 5790Sstevel@tonic-gate *p = '\0'; 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* If empty value, do nothing */ 5820Sstevel@tonic-gate if (strlen(valstr) == 0) { 5830Sstevel@tonic-gate continue; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate switch (cliptr->action(cliptr, valstr, B_FALSE)) { 5870Sstevel@tonic-gate case CLI_SET: 5880Sstevel@tonic-gate CLF_MODVAL(cliptr); 5890Sstevel@tonic-gate break; 5900Sstevel@tonic-gate case CLI_FAIL: 5910Sstevel@tonic-gate printf("Incorrect format, parameter unchanged!\n"); 5920Sstevel@tonic-gate break; 5930Sstevel@tonic-gate case CLI_EXIT: 5940Sstevel@tonic-gate return (CLI_EXIT); 5950Sstevel@tonic-gate case CLI_CONT: 5960Sstevel@tonic-gate break; 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate return (CLI_CONT); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate /* 6040Sstevel@tonic-gate * If the PROM has done DHCP, bind the interface; otherwise do the full 6050Sstevel@tonic-gate * DHCP packet exchange. 6060Sstevel@tonic-gate */ 6070Sstevel@tonic-gate /*ARGSUSED*/ 6080Sstevel@tonic-gate static int 6090Sstevel@tonic-gate cldhcp(cli_ent_t *cliptr, char *valstr, boolean_t out) 6100Sstevel@tonic-gate { 6110Sstevel@tonic-gate static boolean_t first_time = B_TRUE; 6120Sstevel@tonic-gate static int ret = CLI_CONT; 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if (first_time) { 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * Set DHCP's idea of the client_id from our cached value. 6170Sstevel@tonic-gate */ 6180Sstevel@tonic-gate cliptr = find_cli_ent(BI_CLIENT_ID); 6190Sstevel@tonic-gate if (CLF_ISMOD(cliptr)) { 6200Sstevel@tonic-gate dhcp_set_client_id(cliptr->varptr, cliptr->varlen); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_INFO, "Starting DHCP configuration"); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate (void) ipv4_setpromiscuous(B_TRUE); 6260Sstevel@tonic-gate if (dhcp() == 0) { 6270Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_INFO, 6280Sstevel@tonic-gate "DHCP configuration succeeded"); 6290Sstevel@tonic-gate } else { 6300Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_CRIT, 6310Sstevel@tonic-gate "DHCP configuration failed"); 6320Sstevel@tonic-gate ret = CLI_FAIL; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate (void) ipv4_setpromiscuous(B_FALSE); 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate first_time = B_FALSE; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate return (ret); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * Invoke the socket test interpreter (for testing purposes only). 6440Sstevel@tonic-gate */ 6450Sstevel@tonic-gate /*ARGSUSED*/ 6460Sstevel@tonic-gate static int 6470Sstevel@tonic-gate cltest(cli_ent_t *cliptr, char *valstr, boolean_t out) 6480Sstevel@tonic-gate { 6490Sstevel@tonic-gate (void) ipv4_setpromiscuous(B_FALSE); 6500Sstevel@tonic-gate printf("\n"); 6510Sstevel@tonic-gate for (;;) { 6520Sstevel@tonic-gate printf(TEST_PROMPT); 6530Sstevel@tonic-gate if (editline(cmdbuf, sizeof (cmdbuf)) > 0) { 6540Sstevel@tonic-gate printf("\n"); 6550Sstevel@tonic-gate (void) st_interpret(cmdbuf); 6560Sstevel@tonic-gate } else { 6570Sstevel@tonic-gate prom_exit_to_mon(); 6580Sstevel@tonic-gate /* NOTREACHED */ 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* NOTREACHED */ 6630Sstevel@tonic-gate return (CLI_CONT); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * Return the cliptr corresponding to the named variable. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate static cli_ent_t * 6700Sstevel@tonic-gate find_cli_ent(char *varstr) 6710Sstevel@tonic-gate { 6720Sstevel@tonic-gate cli_ent_t *cliptr; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { 6750Sstevel@tonic-gate if (strcmp(varstr, cliptr->varname) == 0) { 6760Sstevel@tonic-gate return (cliptr); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate return (NULL); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * Evaluate the commands provided by the user (either as "-o" boot arguments 6850Sstevel@tonic-gate * or interactively at the boot interpreter). 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate static int 6880Sstevel@tonic-gate cli_eval_buf(char *inbuf, int wanted) 6890Sstevel@tonic-gate { 6900Sstevel@tonic-gate char *p, *varstr, *end_varstr, *valstr, *end_valstr; 6910Sstevel@tonic-gate boolean_t assign; 6920Sstevel@tonic-gate cli_ent_t *cliptr; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate for (p = inbuf; *p != '\0'; ) { 6950Sstevel@tonic-gate skipspace(p); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate /* If nothing more on line, go get the next one */ 6980Sstevel@tonic-gate if (*p == '\0') { 6990Sstevel@tonic-gate break; 7000Sstevel@tonic-gate } else if (*p == ',') { /* orphan ',' ? */ 7010Sstevel@tonic-gate ++p; 7020Sstevel@tonic-gate continue; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* Get ptrs to start & end of variable */ 7060Sstevel@tonic-gate varstr = p; 7070Sstevel@tonic-gate ++p; 7080Sstevel@tonic-gate skiptext(p); 7090Sstevel@tonic-gate end_varstr = p; 7100Sstevel@tonic-gate skipspace(p); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* See if we're doing an assignment */ 7130Sstevel@tonic-gate valstr = NULL; 7140Sstevel@tonic-gate if (*p != '=') { /* nope, just printing */ 7150Sstevel@tonic-gate assign = B_FALSE; 7160Sstevel@tonic-gate } else { 7170Sstevel@tonic-gate assign = B_TRUE; 7180Sstevel@tonic-gate ++p; /* past '=' */ 7190Sstevel@tonic-gate skipspace(p); 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* Assigning something? (else clear variable) */ 7220Sstevel@tonic-gate if (*p != '\0' && *p != ',') { 7230Sstevel@tonic-gate /* Get ptrs to start & end of valstr */ 7240Sstevel@tonic-gate valstr = p; 7250Sstevel@tonic-gate ++p; 7260Sstevel@tonic-gate skiptext(p); 7270Sstevel@tonic-gate end_valstr = p; 7280Sstevel@tonic-gate skipspace(p); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* Skip ',' delimiter if present */ 7330Sstevel@tonic-gate if (*p == ',') { 7340Sstevel@tonic-gate ++p; 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate /* Nul-terminate varstr and valstr (if appropriate) */ 7380Sstevel@tonic-gate *end_varstr = '\0'; 7390Sstevel@tonic-gate if (valstr != NULL) { 7400Sstevel@tonic-gate *end_valstr = '\0'; 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if ((cliptr = find_cli_ent(varstr)) == NULL) { 7440Sstevel@tonic-gate printf("Unknown variable '%s'; ignored\n", varstr); 7450Sstevel@tonic-gate continue; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * It's an error to specify a parameter which can only be a 7500Sstevel@tonic-gate * boot argument (and not a command) when not processing the 7510Sstevel@tonic-gate * boot arguments. 7520Sstevel@tonic-gate */ 7530Sstevel@tonic-gate if ((cliptr->flags & (CLF_CMD | CLF_ARG)) == CLF_ARG && 7540Sstevel@tonic-gate (wanted & CLF_ARG) == 0) { 7550Sstevel@tonic-gate printf("'%s' may only be specified as a " 7560Sstevel@tonic-gate "boot argument; ignored\n", varstr); 7570Sstevel@tonic-gate continue; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * When doing an assignment, verify that it's not a command 7620Sstevel@tonic-gate * or argument name, and that it is permissible in the current 7630Sstevel@tonic-gate * context. An 'empty' assignment (var=) is treated the same 7640Sstevel@tonic-gate * as a null assignment (var=""). 7650Sstevel@tonic-gate * 7660Sstevel@tonic-gate * If processing the boot arguments, it is an error to not 7670Sstevel@tonic-gate * assign a value to a non-argument parameter. 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate if (assign) { 7700Sstevel@tonic-gate if ((cliptr->flags & (CLF_CMD | CLF_ARG)) != 0) { 7710Sstevel@tonic-gate printf("'%s' is a command and cannot " 7720Sstevel@tonic-gate "be assigned\n", varstr); 7730Sstevel@tonic-gate return (CLI_FAIL); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate if ((cliptr->flags & wanted) == 0) { 7760Sstevel@tonic-gate printf("'%s' cannot be assigned\n", varstr); 7770Sstevel@tonic-gate return (CLI_FAIL); 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate if (valstr == NULL) { 7810Sstevel@tonic-gate cliptr->varlen = 0; 7820Sstevel@tonic-gate CLF_MODVAL(cliptr); 7830Sstevel@tonic-gate continue; 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate } else if ((wanted & CLF_ARG) != 0 && 7860Sstevel@tonic-gate (cliptr->flags & (CLF_CMD | CLF_ARG)) == 0) { 7870Sstevel@tonic-gate printf("'%s' must be assigned when specified in " 7880Sstevel@tonic-gate " the boot arguments\n", varstr); 7890Sstevel@tonic-gate return (CLI_FAIL); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * Pass 'wanted' to command-handling functions, in particular 7940Sstevel@tonic-gate * clprompt() and cllist(). 7950Sstevel@tonic-gate */ 7960Sstevel@tonic-gate if ((cliptr->flags & CLF_CMD) != 0) { 797*785Seota /* use uintptr_t to suppress the gcc warning */ 798*785Seota valstr = (char *)(uintptr_t)wanted; 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate /* 8020Sstevel@tonic-gate * Call the parameter's action function. 8030Sstevel@tonic-gate */ 8040Sstevel@tonic-gate switch (cliptr->action(cliptr, valstr, !assign)) { 8050Sstevel@tonic-gate case CLI_SET: 8060Sstevel@tonic-gate CLF_MODVAL(cliptr); 8070Sstevel@tonic-gate break; 8080Sstevel@tonic-gate case CLI_FAIL: 8090Sstevel@tonic-gate printf("Incorrect format: variable '%s' not set\n", 8100Sstevel@tonic-gate cliptr->varname); 8110Sstevel@tonic-gate break; 8120Sstevel@tonic-gate case CLI_EXIT: 8130Sstevel@tonic-gate return (CLI_EXIT); 8140Sstevel@tonic-gate case CLI_CONT: 8150Sstevel@tonic-gate if (!assign) { 8160Sstevel@tonic-gate printf("\n"); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate return (CLI_CONT); 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate static void 8260Sstevel@tonic-gate cli_interpret(int wanted) 8270Sstevel@tonic-gate { 8280Sstevel@tonic-gate printf("\n"); 8290Sstevel@tonic-gate do { 8300Sstevel@tonic-gate printf(PROMPT); 8310Sstevel@tonic-gate (void) editline(cmdbuf, sizeof (cmdbuf)); 8320Sstevel@tonic-gate printf("\n"); 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate } while (cli_eval_buf(cmdbuf, wanted) != CLI_EXIT); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate #if defined(__sparcv9) 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * This routine queries the PROM to see what encryption keys exist. 8400Sstevel@tonic-gate */ 8410Sstevel@tonic-gate static void 8420Sstevel@tonic-gate get_prom_encr_keys() 8430Sstevel@tonic-gate { 8440Sstevel@tonic-gate cli_ent_t *cliptr; 8450Sstevel@tonic-gate char encr_key[WANBOOT_MAXKEYLEN]; 8460Sstevel@tonic-gate int keylen; 8470Sstevel@tonic-gate int status; 8480Sstevel@tonic-gate int ret; 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * At the top of the priority list, we have AES. 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate ret = prom_get_security_key(WANBOOT_AES_128_KEY_NAME, encr_key, 8540Sstevel@tonic-gate WANBOOT_MAXKEYLEN, &keylen, &status); 8550Sstevel@tonic-gate if ((ret == 0) && (status == 0) && (keylen == AES_128_KEY_SIZE)) { 8560Sstevel@tonic-gate cliptr = find_cli_ent(BI_AES_KEY); 8570Sstevel@tonic-gate bcopy(encr_key, cliptr->varptr, AES_128_KEY_SIZE); 8580Sstevel@tonic-gate cliptr->varlen = AES_128_KEY_SIZE; 8590Sstevel@tonic-gate CLF_MODVAL(cliptr); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate /* 8630Sstevel@tonic-gate * Next, 3DES. 8640Sstevel@tonic-gate */ 8650Sstevel@tonic-gate ret = prom_get_security_key(WANBOOT_DES3_KEY_NAME, encr_key, 8660Sstevel@tonic-gate WANBOOT_MAXKEYLEN, &keylen, &status); 8670Sstevel@tonic-gate if ((ret == 0) && (status == 0) && (keylen == DES3_KEY_SIZE)) { 8680Sstevel@tonic-gate cliptr = find_cli_ent(BI_3DES_KEY); 8690Sstevel@tonic-gate bcopy(encr_key, cliptr->varptr, DES3_KEY_SIZE); 8700Sstevel@tonic-gate cliptr->varlen = DES3_KEY_SIZE; 8710Sstevel@tonic-gate CLF_MODVAL(cliptr); 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 8760Sstevel@tonic-gate * This routine queries the PROM to see what hashing keys exist. 8770Sstevel@tonic-gate */ 8780Sstevel@tonic-gate static void 8790Sstevel@tonic-gate get_prom_hash_keys() 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate cli_ent_t *cliptr; 8820Sstevel@tonic-gate char hash_key[WANBOOT_HMAC_KEY_SIZE]; 8830Sstevel@tonic-gate int keylen; 8840Sstevel@tonic-gate int status; 8850Sstevel@tonic-gate int ret; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate /* 8880Sstevel@tonic-gate * The only supported key thus far is SHA1. 8890Sstevel@tonic-gate */ 8900Sstevel@tonic-gate ret = prom_get_security_key(WANBOOT_HMAC_SHA1_KEY_NAME, hash_key, 8910Sstevel@tonic-gate WANBOOT_HMAC_KEY_SIZE, &keylen, &status); 8920Sstevel@tonic-gate if ((ret == 0) && (status == 0) && (keylen == WANBOOT_HMAC_KEY_SIZE)) { 8930Sstevel@tonic-gate cliptr = find_cli_ent(BI_SHA1_KEY); 8940Sstevel@tonic-gate bcopy(hash_key, cliptr->varptr, WANBOOT_HMAC_KEY_SIZE); 8950Sstevel@tonic-gate cliptr->varlen = WANBOOT_HMAC_KEY_SIZE; 8960Sstevel@tonic-gate CLF_MODVAL(cliptr); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate #endif /* defined(__sparcv9) */ 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * For the given parameter type(s), get values from bootinfo and cache in 9030Sstevel@tonic-gate * the local variables used by the "boot>" interpreter. 9040Sstevel@tonic-gate */ 9050Sstevel@tonic-gate static void 9060Sstevel@tonic-gate bootinfo_defaults(int which) 9070Sstevel@tonic-gate { 9080Sstevel@tonic-gate cli_ent_t *cliptr; 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { 9110Sstevel@tonic-gate if ((cliptr->flags & which) != 0 && !CLF_ISSET(cliptr)) { 9120Sstevel@tonic-gate size_t len = cliptr->varmax; 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate if (bootinfo_get(cliptr->varname, cliptr->varptr, 9150Sstevel@tonic-gate &len, NULL) == BI_E_SUCCESS) { 9160Sstevel@tonic-gate cliptr->varlen = len; 9170Sstevel@tonic-gate CLF_SETVAL(cliptr); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate /* 9240Sstevel@tonic-gate * For the given parameter type(s), store values entered at the "boot>" 9250Sstevel@tonic-gate * interpreter back into bootinfo. 9260Sstevel@tonic-gate */ 9270Sstevel@tonic-gate static void 9280Sstevel@tonic-gate update_bootinfo(int which) 9290Sstevel@tonic-gate { 9300Sstevel@tonic-gate cli_ent_t *cliptr; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate for (cliptr = cli_list; cliptr < &cli_list[num_cli_ent]; ++cliptr) { 9330Sstevel@tonic-gate if ((cliptr->flags & which) != 0 && CLF_ISMOD(cliptr)) { 9340Sstevel@tonic-gate (void) bootinfo_put(cliptr->varname, 9350Sstevel@tonic-gate cliptr->varptr, cliptr->varlen, 0); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate } 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate /* 9410Sstevel@tonic-gate * Return the net-config-strategy: "dhcp", "manual" or "rarp" 9420Sstevel@tonic-gate */ 9430Sstevel@tonic-gate static char * 9440Sstevel@tonic-gate net_config_strategy(void) 9450Sstevel@tonic-gate { 9460Sstevel@tonic-gate static char ncs[8]; /* "dhcp" or "manual" */ 9470Sstevel@tonic-gate size_t len = sizeof (ncs); 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate if (ncs[0] == '\0' && 9500Sstevel@tonic-gate bootinfo_get(BI_NET_CONFIG_STRATEGY, ncs, &len, NULL) != 9510Sstevel@tonic-gate BI_E_SUCCESS) { 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * Support for old PROMs: create the net-config-strategy 9540Sstevel@tonic-gate * property under /chosen with an appropriate value. If we 9550Sstevel@tonic-gate * have a bootp-response (not interested in its value, just 9560Sstevel@tonic-gate * its presence) then we did DHCP; otherwise configuration 9570Sstevel@tonic-gate * is manual. 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL, 9600Sstevel@tonic-gate NULL) == BI_E_BUF2SMALL) { 9610Sstevel@tonic-gate (void) strcpy(ncs, "dhcp"); 9620Sstevel@tonic-gate } else { 9630Sstevel@tonic-gate (void) strcpy(ncs, "manual"); 9640Sstevel@tonic-gate } 9650Sstevel@tonic-gate (void) bootinfo_put(BI_NET_CONFIG_STRATEGY, ncs, strlen(ncs), 9660Sstevel@tonic-gate BI_R_CHOSEN); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_INFO, 9690Sstevel@tonic-gate "Default net-config-strategy: %s", ncs); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate return (ncs); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * If there is no client-id property published in /chosen (by the PROM or the 9770Sstevel@tonic-gate * boot interpreter) provide a default client-id based on the MAC address of 9780Sstevel@tonic-gate * the client. 9790Sstevel@tonic-gate * As specified in RFC2132 (section 9.14), this is prefixed with a byte 9800Sstevel@tonic-gate * which specifies the ARP hardware type defined in RFC1700 (for Ethernet, 9810Sstevel@tonic-gate * this should be 1). 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate static void 9840Sstevel@tonic-gate generate_default_clientid(void) 9850Sstevel@tonic-gate { 9860Sstevel@tonic-gate char clid[WB_MAX_CID_LEN]; 9870Sstevel@tonic-gate size_t len = sizeof (clid); 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate if (bootinfo_get(BI_CLIENT_ID, clid, &len, NULL) != BI_E_SUCCESS) { 9900Sstevel@tonic-gate len = mac_get_addr_len() + 1; /* include hwtype */ 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate if (len > sizeof (clid)) { 9930Sstevel@tonic-gate return; 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate clid[0] = mac_arp_type(mac_get_type()); 9970Sstevel@tonic-gate bcopy(mac_get_addr_buf(), &clid[1], len - 1); 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate (void) bootinfo_put(BI_CLIENT_ID, clid, len, 0); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate /* 10040Sstevel@tonic-gate * Determine the URL of the boot server from the 'file' parameter to OBP, 10050Sstevel@tonic-gate * the SbootURI or BootFile DHCP options, or the 'bootserver' value entered 10060Sstevel@tonic-gate * either as a "-o" argument or at the interpreter. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate static void 10090Sstevel@tonic-gate determine_bootserver_url(void) 10100Sstevel@tonic-gate { 10110Sstevel@tonic-gate char bs[URL_MAX_STRLEN + 1]; 10120Sstevel@tonic-gate size_t len; 10130Sstevel@tonic-gate url_t url; 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate if (bootinfo_get(BI_BOOTSERVER, bs, &len, NULL) != BI_E_SUCCESS) { 10160Sstevel@tonic-gate /* 10170Sstevel@tonic-gate * If OBP has published a network-boot-file property in 10180Sstevel@tonic-gate * /chosen (or there is a DHCP BootFile or SbootURI vendor 10190Sstevel@tonic-gate * option) and it's a URL, construct the bootserver URL 10200Sstevel@tonic-gate * from it. 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate len = URL_MAX_STRLEN; 10230Sstevel@tonic-gate if (bootinfo_get(BI_NETWORK_BOOT_FILE, bs, &len, NULL) != 10240Sstevel@tonic-gate BI_E_SUCCESS) { 10250Sstevel@tonic-gate len = URL_MAX_STRLEN; 10260Sstevel@tonic-gate if (bootinfo_get(BI_BOOTFILE, bs, &len, NULL) != 10270Sstevel@tonic-gate BI_E_SUCCESS) { 10280Sstevel@tonic-gate return; 10290Sstevel@tonic-gate } 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate if (url_parse(bs, &url) == URL_PARSE_SUCCESS) { 10320Sstevel@tonic-gate (void) bootinfo_put(BI_BOOTSERVER, bs, len, 0); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * Provide a classful subnet mask based on the client's IP address. 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate static in_addr_t 10410Sstevel@tonic-gate generate_classful_subnet(in_addr_t client_ipaddr) 10420Sstevel@tonic-gate { 10430Sstevel@tonic-gate struct in_addr subnetmask; 10440Sstevel@tonic-gate char *netstr; 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate if (IN_CLASSA(client_ipaddr)) { 10470Sstevel@tonic-gate subnetmask.s_addr = IN_CLASSA_NET; 10480Sstevel@tonic-gate } else if (IN_CLASSB(client_ipaddr)) { 10490Sstevel@tonic-gate subnetmask.s_addr = IN_CLASSB_NET; 10500Sstevel@tonic-gate } else { 10510Sstevel@tonic-gate subnetmask.s_addr = IN_CLASSC_NET; 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate netstr = inet_ntoa(subnetmask); 10550Sstevel@tonic-gate (void) bootinfo_put(BI_SUBNET_MASK, netstr, strlen(netstr) + 1, 0); 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate return (subnetmask.s_addr); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * Informational output to the user (if interactive) or the bootlogger. 10620Sstevel@tonic-gate */ 10630Sstevel@tonic-gate static void 10640Sstevel@tonic-gate info(const char *msg, boolean_t interactive) 10650Sstevel@tonic-gate { 10660Sstevel@tonic-gate if (interactive) { 10670Sstevel@tonic-gate printf("%s\n", msg); 10680Sstevel@tonic-gate } else { 10690Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_INFO, "%s", msg); 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate /* 10740Sstevel@tonic-gate * Determine whether we have sufficient information to proceed with booting, 10750Sstevel@tonic-gate * either for configuring the interface and downloading the bootconf file, 10760Sstevel@tonic-gate * or for downloading the miniroot. 10770Sstevel@tonic-gate */ 10780Sstevel@tonic-gate static int 10790Sstevel@tonic-gate config_incomplete(int why, boolean_t interactive) 10800Sstevel@tonic-gate { 10810Sstevel@tonic-gate boolean_t error = B_FALSE; 10820Sstevel@tonic-gate char buf[URL_MAX_STRLEN + 1]; 10830Sstevel@tonic-gate size_t len; 10840Sstevel@tonic-gate char *urlstr; 10850Sstevel@tonic-gate url_t u; 10860Sstevel@tonic-gate struct hostent *hp; 10870Sstevel@tonic-gate in_addr_t client_ipaddr, ipaddr, bsnet, pxnet; 10880Sstevel@tonic-gate static in_addr_t subnetmask, clnet; 10890Sstevel@tonic-gate static boolean_t have_router = B_FALSE; 10900Sstevel@tonic-gate static boolean_t have_proxy = B_FALSE; 10910Sstevel@tonic-gate boolean_t have_root_server = B_FALSE; 10920Sstevel@tonic-gate boolean_t have_boot_logger = B_FALSE; 10930Sstevel@tonic-gate in_addr_t rsnet, blnet; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Note that 'have_router', 'have_proxy', 'subnetmask', and 'clnet' 10970Sstevel@tonic-gate * are static, so that their values (gathered when checking the 10980Sstevel@tonic-gate * interface configuration) may be used again when checking the boot 10990Sstevel@tonic-gate * configuration. 11000Sstevel@tonic-gate */ 11010Sstevel@tonic-gate if (why == CLF_IF) { 11020Sstevel@tonic-gate /* 11030Sstevel@tonic-gate * A valid host IP address is an absolute requirement. 11040Sstevel@tonic-gate */ 11050Sstevel@tonic-gate len = sizeof (buf); 11060Sstevel@tonic-gate if (bootinfo_get(BI_HOST_IP, buf, &len, NULL) == BI_E_SUCCESS) { 11070Sstevel@tonic-gate if ((client_ipaddr = inet_addr(buf)) == (in_addr_t)-1) { 11080Sstevel@tonic-gate info("host-ip invalid!", interactive); 11090Sstevel@tonic-gate error = B_TRUE; 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate } else { 11120Sstevel@tonic-gate info("host-ip not set!", interactive); 11130Sstevel@tonic-gate error = B_TRUE; 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate /* 11170Sstevel@tonic-gate * If a subnet mask was provided, use it; otherwise infer it. 11180Sstevel@tonic-gate */ 11190Sstevel@tonic-gate len = sizeof (buf); 11200Sstevel@tonic-gate if (bootinfo_get(BI_SUBNET_MASK, buf, &len, NULL) == 11210Sstevel@tonic-gate BI_E_SUCCESS) { 11220Sstevel@tonic-gate if ((subnetmask = inet_addr(buf)) == (in_addr_t)-1) { 11230Sstevel@tonic-gate info("subnet-mask invalid!", interactive); 11240Sstevel@tonic-gate error = B_TRUE; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate } else { 11270Sstevel@tonic-gate info("Defaulting to classful subnetting", interactive); 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate subnetmask = generate_classful_subnet(client_ipaddr); 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate clnet = client_ipaddr & subnetmask; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate /* 11340Sstevel@tonic-gate * A legal bootserver URL is also an absolute requirement. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate len = sizeof (buf); 11370Sstevel@tonic-gate if (bootinfo_get(BI_BOOTSERVER, buf, &len, NULL) == 11380Sstevel@tonic-gate BI_E_SUCCESS) { 11390Sstevel@tonic-gate if (url_parse(buf, &u) != URL_PARSE_SUCCESS || 11400Sstevel@tonic-gate u.https || 11410Sstevel@tonic-gate (ipaddr = inet_addr(u.hport.hostname)) == 11420Sstevel@tonic-gate (in_addr_t)-1) { 11430Sstevel@tonic-gate info("bootserver not legal URL!", interactive); 11440Sstevel@tonic-gate error = B_TRUE; 11450Sstevel@tonic-gate } else { 11460Sstevel@tonic-gate bsnet = ipaddr & subnetmask; 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate } else { 11490Sstevel@tonic-gate info("bootserver not specified!", interactive); 11500Sstevel@tonic-gate error = B_TRUE; 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * Is there a correctly-defined router? 11550Sstevel@tonic-gate */ 11560Sstevel@tonic-gate len = sizeof (buf); 11570Sstevel@tonic-gate if (bootinfo_get(BI_ROUTER_IP, buf, &len, NULL) == 11580Sstevel@tonic-gate BI_E_SUCCESS) { 11590Sstevel@tonic-gate if ((ipaddr = inet_addr(buf)) == (in_addr_t)-1) { 11600Sstevel@tonic-gate info("router-ip invalid!", interactive); 11610Sstevel@tonic-gate error = B_TRUE; 11620Sstevel@tonic-gate } else if (clnet != (ipaddr & subnetmask)) { 11630Sstevel@tonic-gate info("router not on local subnet!", 11640Sstevel@tonic-gate interactive); 11650Sstevel@tonic-gate error = B_TRUE; 11660Sstevel@tonic-gate } else { 11670Sstevel@tonic-gate have_router = B_TRUE; 11680Sstevel@tonic-gate } 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate /* 11720Sstevel@tonic-gate * Is there a correctly-defined proxy? 11730Sstevel@tonic-gate */ 11740Sstevel@tonic-gate len = sizeof (buf); 11750Sstevel@tonic-gate if (bootinfo_get(BI_HTTP_PROXY, buf, &len, NULL) == 11760Sstevel@tonic-gate BI_E_SUCCESS) { 11770Sstevel@tonic-gate url_hport_t u; 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if (url_parse_hostport(buf, &u, URL_DFLT_PROXY_PORT) != 11800Sstevel@tonic-gate URL_PARSE_SUCCESS || 11810Sstevel@tonic-gate (ipaddr = inet_addr(u.hostname)) == (in_addr_t)-1) { 11820Sstevel@tonic-gate info("http-proxy port invalid!", interactive); 11830Sstevel@tonic-gate error = B_TRUE; 11840Sstevel@tonic-gate } else { 11850Sstevel@tonic-gate /* 11860Sstevel@tonic-gate * The proxy is only of use to us if it's on 11870Sstevel@tonic-gate * our local subnet, or if a router has been 11880Sstevel@tonic-gate * specified (which should hopefully allow us 11890Sstevel@tonic-gate * to access the proxy). 11900Sstevel@tonic-gate */ 11910Sstevel@tonic-gate pxnet = ipaddr & subnetmask; 11920Sstevel@tonic-gate have_proxy = (have_router || pxnet == clnet); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate } 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate /* 11970Sstevel@tonic-gate * If there is no router and no proxy (either on the local 11980Sstevel@tonic-gate * subnet or reachable via a router), then the bootserver 11990Sstevel@tonic-gate * URL must be on the local net. 12000Sstevel@tonic-gate */ 12010Sstevel@tonic-gate if (!error && !have_router && !have_proxy && bsnet != clnet) { 12020Sstevel@tonic-gate info("bootserver URL not on local subnet", 12030Sstevel@tonic-gate interactive); 12040Sstevel@tonic-gate error = B_TRUE; 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate } else { 12070Sstevel@tonic-gate /* 12080Sstevel@tonic-gate * There must be a correctly-defined root_server URL. 12090Sstevel@tonic-gate */ 12100Sstevel@tonic-gate if ((urlstr = bootconf_get(&bc_handle, 12110Sstevel@tonic-gate BC_ROOT_SERVER)) == NULL) { 12120Sstevel@tonic-gate info("no root_server URL!", interactive); 12130Sstevel@tonic-gate error = B_TRUE; 12140Sstevel@tonic-gate } else if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) { 12150Sstevel@tonic-gate info("root_server not legal URL!", interactive); 12160Sstevel@tonic-gate error = B_TRUE; 12170Sstevel@tonic-gate } else if ((hp = gethostbyname(u.hport.hostname)) == NULL) { 12180Sstevel@tonic-gate info("cannot resolve root_server hostname!", 12190Sstevel@tonic-gate interactive); 12200Sstevel@tonic-gate error = B_TRUE; 12210Sstevel@tonic-gate } else { 12220Sstevel@tonic-gate rsnet = *(in_addr_t *)hp->h_addr & subnetmask; 12230Sstevel@tonic-gate have_root_server = B_TRUE; 12240Sstevel@tonic-gate } 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate /* 12270Sstevel@tonic-gate * Is there a correctly-defined (non-empty) boot_logger URL? 12280Sstevel@tonic-gate */ 12290Sstevel@tonic-gate if ((urlstr = bootconf_get(&bc_handle, 12300Sstevel@tonic-gate BC_BOOT_LOGGER)) != NULL) { 12310Sstevel@tonic-gate if (url_parse(urlstr, &u) != URL_PARSE_SUCCESS) { 12320Sstevel@tonic-gate info("boot_logger not legal URL!", interactive); 12330Sstevel@tonic-gate error = B_TRUE; 12340Sstevel@tonic-gate } else if ((hp = gethostbyname(u.hport.hostname)) == 12350Sstevel@tonic-gate NULL) { 12360Sstevel@tonic-gate info("cannot resolve boot_logger hostname!", 12370Sstevel@tonic-gate interactive); 12380Sstevel@tonic-gate error = B_TRUE; 12390Sstevel@tonic-gate } else { 12400Sstevel@tonic-gate blnet = *(in_addr_t *)hp->h_addr & subnetmask; 12410Sstevel@tonic-gate have_boot_logger = B_TRUE; 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate /* 12460Sstevel@tonic-gate * If there is no router and no proxy (either on the local 12470Sstevel@tonic-gate * subnet or reachable via a router), then the root_server 12480Sstevel@tonic-gate * URL (and the boot_logger URL if specified) must be on the 12490Sstevel@tonic-gate * local net. 12500Sstevel@tonic-gate */ 12510Sstevel@tonic-gate if (!error && !have_router && !have_proxy) { 12520Sstevel@tonic-gate if (have_root_server && rsnet != clnet) { 12530Sstevel@tonic-gate info("root_server URL not on local subnet", 12540Sstevel@tonic-gate interactive); 12550Sstevel@tonic-gate error = B_TRUE; 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate if (have_boot_logger && blnet != clnet) { 12580Sstevel@tonic-gate info("boot_logger URL not on local subnet", 12590Sstevel@tonic-gate interactive); 12600Sstevel@tonic-gate error = B_TRUE; 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate } 12630Sstevel@tonic-gate } 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate return (error); 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate /* 12690Sstevel@tonic-gate * Actually setup our network interface with the values derived from the 12700Sstevel@tonic-gate * PROM, DHCP or interactively from the user. 12710Sstevel@tonic-gate */ 12720Sstevel@tonic-gate static void 12730Sstevel@tonic-gate setup_interface() 12740Sstevel@tonic-gate { 12750Sstevel@tonic-gate char str[MAXHOSTNAMELEN]; /* will accomodate an IP too */ 12760Sstevel@tonic-gate size_t len; 12770Sstevel@tonic-gate struct in_addr in_addr; 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate len = sizeof (str); 12800Sstevel@tonic-gate if (bootinfo_get(BI_HOST_IP, str, &len, NULL) == BI_E_SUCCESS && 12810Sstevel@tonic-gate (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { 12820Sstevel@tonic-gate in_addr.s_addr = htonl(in_addr.s_addr); 12830Sstevel@tonic-gate ipv4_setipaddr(&in_addr); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate len = sizeof (str); 12870Sstevel@tonic-gate if (bootinfo_get(BI_SUBNET_MASK, str, &len, NULL) == BI_E_SUCCESS && 12880Sstevel@tonic-gate (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { 12890Sstevel@tonic-gate in_addr.s_addr = htonl(in_addr.s_addr); 12900Sstevel@tonic-gate ipv4_setnetmask(&in_addr); 12910Sstevel@tonic-gate } 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate len = sizeof (str); 12940Sstevel@tonic-gate if (bootinfo_get(BI_ROUTER_IP, str, &len, NULL) == BI_E_SUCCESS && 12950Sstevel@tonic-gate (in_addr.s_addr = inet_addr(str)) != (in_addr_t)-1) { 12960Sstevel@tonic-gate in_addr.s_addr = htonl(in_addr.s_addr); 12970Sstevel@tonic-gate ipv4_setdefaultrouter(&in_addr); 12980Sstevel@tonic-gate (void) ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL, &in_addr); 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate len = sizeof (str); 13020Sstevel@tonic-gate if (bootinfo_get(BI_HOSTNAME, str, &len, NULL) == BI_E_SUCCESS) { 13030Sstevel@tonic-gate (void) sethostname(str, len); 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate } 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate /* EXPORT DELETE END */ 13080Sstevel@tonic-gate boolean_t 13090Sstevel@tonic-gate wanboot_init_interface(char *boot_arguments) 13100Sstevel@tonic-gate { 13110Sstevel@tonic-gate /* EXPORT DELETE START */ 13120Sstevel@tonic-gate boolean_t interactive; 13130Sstevel@tonic-gate int which; 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate #if defined(__sparcv9) 13160Sstevel@tonic-gate /* 13170Sstevel@tonic-gate * Get the keys from PROM before we allow the user 13180Sstevel@tonic-gate * to override them from the CLI. 13190Sstevel@tonic-gate */ 13200Sstevel@tonic-gate get_prom_encr_keys(); 13210Sstevel@tonic-gate get_prom_hash_keys(); 13220Sstevel@tonic-gate #endif /* defined(__sparcv9) */ 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate /* 13250Sstevel@tonic-gate * If there is already a bootp-response property under 13260Sstevel@tonic-gate * /chosen then the PROM must have done DHCP for us; 13270Sstevel@tonic-gate * invoke dhcp() to 'bind' the interface. 13280Sstevel@tonic-gate */ 13290Sstevel@tonic-gate if (bootinfo_get(BI_BOOTP_RESPONSE, NULL, NULL, NULL) == 13300Sstevel@tonic-gate BI_E_BUF2SMALL) { 13310Sstevel@tonic-gate (void) cldhcp(NULL, NULL, 0); 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate /* 13350Sstevel@tonic-gate * Obtain default interface values from bootinfo. 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate bootinfo_defaults(CLF_IF); 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate /* 13400Sstevel@tonic-gate * Process the boot arguments (following the "-o" option). 13410Sstevel@tonic-gate */ 13420Sstevel@tonic-gate if (boot_arguments != NULL) { 13430Sstevel@tonic-gate (void) cli_eval_buf(boot_arguments, 13440Sstevel@tonic-gate (CLF_ARG | CLF_IF | CLF_BM)); 13450Sstevel@tonic-gate } 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate /* 13480Sstevel@tonic-gate * Stash away any interface/bootmisc parameter values we got 13490Sstevel@tonic-gate * from either the PROM or the boot arguments. 13500Sstevel@tonic-gate */ 13510Sstevel@tonic-gate update_bootinfo(CLF_IF | CLF_BM); 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate /* 13540Sstevel@tonic-gate * If we don't already have a value for bootserver, try to 13550Sstevel@tonic-gate * deduce one. Refresh wbcli's idea of these values. 13560Sstevel@tonic-gate */ 13570Sstevel@tonic-gate determine_bootserver_url(); 13580Sstevel@tonic-gate bootinfo_defaults(CLF_BM); 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate /* 13610Sstevel@tonic-gate * Check that the information we have collected thus far is sufficient. 13620Sstevel@tonic-gate */ 13630Sstevel@tonic-gate interactive = args_specified_prompt; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate if (interactive) { 13660Sstevel@tonic-gate /* 13670Sstevel@tonic-gate * Drop into the boot interpreter to allow the input 13680Sstevel@tonic-gate * of keys, bootserver and bootmisc, and in the case 13690Sstevel@tonic-gate * that net-config-strategy == "manual" the interface 13700Sstevel@tonic-gate * parameters. 13710Sstevel@tonic-gate */ 13720Sstevel@tonic-gate which = CLF_BM | CLF_CMD; 13730Sstevel@tonic-gate if (strcmp(net_config_strategy(), "manual") == 0) 13740Sstevel@tonic-gate which |= CLF_IF; 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate do { 13770Sstevel@tonic-gate cli_interpret(which); 13780Sstevel@tonic-gate update_bootinfo(CLF_IF | CLF_BM); 13790Sstevel@tonic-gate } while (config_incomplete(CLF_IF, interactive)); 13800Sstevel@tonic-gate } else { 13810Sstevel@tonic-gate /* 13820Sstevel@tonic-gate * The user is not to be given the opportunity to 13830Sstevel@tonic-gate * enter further values; fail. 13840Sstevel@tonic-gate */ 13850Sstevel@tonic-gate if (config_incomplete(CLF_IF, interactive)) { 13860Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_CRIT, 13870Sstevel@tonic-gate "interface incorrectly configured"); 13880Sstevel@tonic-gate return (B_FALSE); 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate /* 13930Sstevel@tonic-gate * If a wanboot-enabled PROM hasn't processed client-id in 13940Sstevel@tonic-gate * network-boot-arguments, or no value for client-id has been 13950Sstevel@tonic-gate * specified to the boot interpreter, then provide a default 13960Sstevel@tonic-gate * client-id based on our MAC address. 13970Sstevel@tonic-gate */ 13980Sstevel@tonic-gate generate_default_clientid(); 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate /* 14010Sstevel@tonic-gate * If net-config-strategy == "manual" then we must setup 14020Sstevel@tonic-gate * the interface now; if "dhcp" then it will already have 14030Sstevel@tonic-gate * been setup. 14040Sstevel@tonic-gate */ 14050Sstevel@tonic-gate if (strcmp(net_config_strategy(), "manual") == 0) 14060Sstevel@tonic-gate setup_interface(); 14070Sstevel@tonic-gate /* EXPORT DELETE END */ 14080Sstevel@tonic-gate return (B_TRUE); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate boolean_t 14120Sstevel@tonic-gate wanboot_verify_config(void) 14130Sstevel@tonic-gate { 14140Sstevel@tonic-gate /* EXPORT DELETE START */ 14150Sstevel@tonic-gate /* 14160Sstevel@tonic-gate * Check that the wanboot.conf file defines a valid root_server 14170Sstevel@tonic-gate * URL, and check that, if given, the boot_logger URL is valid. 14180Sstevel@tonic-gate */ 14190Sstevel@tonic-gate if (config_incomplete(0, B_FALSE)) { 14200Sstevel@tonic-gate bootlog("wanboot", BOOTLOG_CRIT, 14210Sstevel@tonic-gate "incomplete boot configuration"); 14220Sstevel@tonic-gate return (B_FALSE); 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate /* EXPORT DELETE END */ 14250Sstevel@tonic-gate return (B_TRUE); 14260Sstevel@tonic-gate } 1427