xref: /onnv-gate/usr/src/psm/stand/boot/sparc/common/wbcli.c (revision 0:68f95e015346)
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