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