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