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