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
editline(char * buf,int count)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
clcid(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clkey(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clip(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clstr(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clurl(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clhp(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clgo(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clexit(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clhelp(cli_ent_t * cliptr,char * valstr,boolean_t out)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
cllist(cli_ent_t * cliptr,char * valstr,boolean_t out)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
clprompt(cli_ent_t * cliptr,char * valstr,boolean_t out)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
cldhcp(cli_ent_t * cliptr,char * valstr,boolean_t out)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
cltest(cli_ent_t * cliptr,char * valstr,boolean_t out)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 *
find_cli_ent(char * varstr)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
cli_eval_buf(char * inbuf,int wanted)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
cli_interpret(int wanted)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
get_prom_encr_keys()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
get_prom_hash_keys()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
bootinfo_defaults(int which)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
update_bootinfo(int which)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 *
net_config_strategy(void)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
generate_default_clientid(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
determine_bootserver_url(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
generate_classful_subnet(in_addr_t client_ipaddr)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
info(const char * msg,boolean_t interactive)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
config_incomplete(int why,boolean_t interactive)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
setup_interface()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
wanboot_init_interface(char * boot_arguments)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
wanboot_verify_config(void)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