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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * nwamadm is a command interpreter to administer NWAM profiles. It
28 * is all in C (i.e., no lex/yacc), and all the argument passing is
29 * argc/argv based. main() calls the command's handler function,
30 * which first calls parse_argv() to parse the input arguments and set
31 * approriate variables for each command. The rest of the program is
32 * helper functions for the handler functions.
33 */
34
35 #include <arpa/inet.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <libdlwlan.h>
39 #include <libinetutil.h>
40 #include <libnwam.h>
41 #include <libscf.h>
42 #include <locale.h>
43 #include <netinet/in.h>
44 #include <ofmt.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <sys/socket.h>
51 #include <sys/types.h>
52 #include <unistd.h>
53
54 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
55 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
56 #endif
57
58 typedef void (cmd_func_t)(int, char **);
59
60 struct cmd {
61 uint_t cmd_num; /* command number */
62 const char *cmd_name; /* command name */
63 cmd_func_t *cmd_handler; /* function to call */
64 const char *cmd_usage; /* short form help */
65 const char *cmd_desc; /* command description */
66 boolean_t cmd_needs_nwamd; /* nwam needs to run */
67 };
68
69 /* constants for commands */
70 #define CMD_HELP 0
71 #define CMD_ENABLE 1
72 #define CMD_DISABLE 2
73 #define CMD_LIST 3
74 #define CMD_SHOW_EVENTS 4
75 #define CMD_SCAN_WIFI 5
76 #define CMD_SELECT_WIFI 6
77
78 #define CMD_MIN CMD_HELP
79 #define CMD_MAX CMD_SELECT_WIFI
80
81 /* functions to call */
82 static cmd_func_t help_func, enable_func, disable_func, list_func;
83 static cmd_func_t show_events_func, scan_wifi_func, select_wifi_func;
84 static ofmt_cb_t print_list_cb;
85
86 /* table of commands and usage */
87 static struct cmd cmdtab[] = {
88 { CMD_HELP, "help", help_func,
89 "help",
90 "Print this usage message.", B_FALSE },
91 { CMD_ENABLE, "enable", enable_func,
92 "enable [-p <profile-type>] [-c <ncu-class>] <object-name>",
93 "Enable the specified profile.", B_FALSE },
94 { CMD_DISABLE, "disable", disable_func,
95 "disable [-p <profile-type>] [-c <ncu-class>] <object-name>",
96 "Disable the specified profile.", B_FALSE },
97 { CMD_LIST, "list", list_func,
98 "list [-x] [-p <profile-type>] [-c <ncu-class>] [<object-name>]",
99 "List profiles and their current states.", B_TRUE },
100 { CMD_SHOW_EVENTS, "show-events", show_events_func,
101 "show-events",
102 "Display all events.", B_TRUE },
103 { CMD_SCAN_WIFI, "scan-wifi", scan_wifi_func,
104 "scan-wifi <link-name>",
105 "Request a WiFi scan for the selected link.", B_TRUE },
106 { CMD_SELECT_WIFI, "select-wifi", select_wifi_func,
107 "select-wifi <link-name>",
108 "Make a WLAN selection from the last WiFi scan.", B_TRUE }
109 };
110
111 /* Structure for "nwamadm list" output */
112
113 typedef struct profile_entry {
114 nwam_object_type_t p_type;
115 nwam_ncu_class_t p_ncu_class;
116 char p_name[NWAM_MAX_NAME_LEN];
117 nwam_state_t p_state;
118 nwam_aux_state_t p_aux_state;
119 } profile_entry_t;
120
121 /* widths of colums for printing */
122 #define TYPE_WIDTH 12 /* width of TYPE column */
123 #define PROFILE_WIDTH 15 /* width of PROFILE column */
124 #define STATE_WIDTH 15 /* width of STATE column */
125 #define AUXSTATE_WIDTH 36 /* width of AUXILIARY STATE column */
126
127 #define EVENT_WIDTH 15 /* width of EVENT column */
128 #define DESCRIPTION_WIDTH 64 /* width of DESCRIPTION column */
129
130 /* id for columns of "nwamadm list" */
131 typedef enum {
132 LIST_TYPE,
133 LIST_PROFILE,
134 LIST_STATE,
135 LIST_AUXSTATE
136 } list_field_id_t;
137
138 static const ofmt_field_t list_fields[] = {
139 /* header, width, id, callback */
140 { "TYPE", TYPE_WIDTH, LIST_TYPE, print_list_cb },
141 { "PROFILE", PROFILE_WIDTH, LIST_PROFILE, print_list_cb },
142 { "STATE", STATE_WIDTH, LIST_STATE, print_list_cb },
143 { "AUXILIARY STATE", AUXSTATE_WIDTH, LIST_AUXSTATE, print_list_cb },
144 { NULL, 0, 0, NULL }
145 };
146
147 /* Global variables */
148
149 /* set early in main(), never modified thereafter, used all over the place */
150 static char *execname;
151
152 /* whether the auxilary states are to be printed or not */
153 static boolean_t extended_list = B_FALSE;
154
155 /* Functions */
156
157 static const char *
cmd_to_str(int cmd_num)158 cmd_to_str(int cmd_num)
159 {
160 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
161 return (cmdtab[cmd_num].cmd_name);
162 }
163
164 /* returns description of given command */
165 static const char *
long_help(int cmd_num)166 long_help(int cmd_num)
167 {
168 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
169 return (gettext(cmdtab[cmd_num].cmd_desc));
170 }
171
172 /*
173 * Called with explicit B_TRUE when help is explicitly required,
174 * B_FALSE for errors
175 */
176 static void
usage(boolean_t explicit)177 usage(boolean_t explicit)
178 {
179 int i;
180 FILE *fd = explicit ? stdout : stderr;
181
182 (void) fprintf(fd, gettext("usage: <subcommand> <args> ...\n"));
183 for (i = CMD_MIN; i <= CMD_MAX; i++) {
184 (void) fprintf(fd, "\t%s\n", cmdtab[i].cmd_usage);
185 if (explicit)
186 (void) fprintf(fd, "\t\t%s\n\n", long_help(i));
187 }
188 }
189
190 /* PRINTFLIKE1 */
191 static void
die(const char * format,...)192 die(const char *format, ...)
193 {
194 va_list alist;
195
196 format = gettext(format);
197 (void) fprintf(stderr, "%s: ", execname);
198
199 va_start(alist, format);
200 (void) vfprintf(stderr, format, alist);
201 va_end(alist);
202 (void) fprintf(stderr, "\n");
203
204 exit(EXIT_FAILURE);
205 }
206
207 /* PRINTFLIKE2 */
208 static void
die_nwamerr(nwam_error_t err,const char * format,...)209 die_nwamerr(nwam_error_t err, const char *format, ...)
210 {
211 va_list alist;
212
213 format = gettext(format);
214 (void) fprintf(stderr, "%s: ", execname);
215
216 va_start(alist, format);
217 (void) vfprintf(stderr, format, alist);
218 va_end(alist);
219 (void) fprintf(stderr, ": %s\n", nwam_strerror(err));
220
221 exit(EXIT_FAILURE);
222 }
223
224 /* prints the usage for cmd_num and exits */
225 static void
die_usage(int cmd_num)226 die_usage(int cmd_num)
227 {
228 assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
229
230 (void) fprintf(stderr, "%s: %s\n", gettext("usage"),
231 cmdtab[cmd_num].cmd_usage);
232 (void) fprintf(stderr, "\t%s\n", long_help(cmd_num));
233
234 exit(EXIT_FAILURE);
235 }
236
237 /*
238 * Prints the usage and description of all commands
239 */
240 /* ARGSUSED */
241 static void
help_func(int argc,char * argv[])242 help_func(int argc, char *argv[])
243 {
244 usage(B_TRUE);
245 }
246
247 /* determines if the NCP is active or not. If so, sets arg and halts walk. */
248 static int
active_ncp_callback(nwam_ncp_handle_t ncph,void * arg)249 active_ncp_callback(nwam_ncp_handle_t ncph, void *arg)
250 {
251 char **namep = arg;
252 nwam_state_t state = NWAM_STATE_UNINITIALIZED;
253 nwam_aux_state_t aux;
254
255 (void) nwam_ncp_get_state(ncph, &state, &aux);
256 if (state == NWAM_STATE_ONLINE) {
257 if (nwam_ncp_get_name(ncph, namep) != NWAM_SUCCESS)
258 *namep = NULL;
259 return (1);
260 }
261
262 return (0);
263 }
264
265 /* find the currently active NCP and returns its handle */
266 static nwam_ncp_handle_t
determine_active_ncp()267 determine_active_ncp()
268 {
269 char *active_ncp;
270 nwam_ncp_handle_t ncph;
271 nwam_error_t ret;
272
273 if (nwam_walk_ncps(active_ncp_callback, &active_ncp, 0, NULL)
274 == NWAM_WALK_HALTED) {
275 if (active_ncp == NULL)
276 return (NULL);
277
278 /* retrieve the NCP handle */
279 ret = nwam_ncp_read(active_ncp, 0, &ncph);
280 free(active_ncp);
281 if (ret == NWAM_SUCCESS)
282 return (ncph);
283 }
284
285 return (NULL);
286 }
287
288 /* check if the given name is a valid loc, test by reading the given loc */
289 static boolean_t
valid_loc(const char * name)290 valid_loc(const char *name)
291 {
292 nwam_loc_handle_t loch;
293
294 if (nwam_loc_read(name, 0, &loch) != NWAM_SUCCESS)
295 return (B_FALSE);
296 nwam_loc_free(loch);
297 return (B_TRUE);
298 }
299
300 static boolean_t
valid_enm(const char * name)301 valid_enm(const char *name)
302 {
303 nwam_enm_handle_t enmh;
304
305 if (nwam_enm_read(name, 0, &enmh) != NWAM_SUCCESS)
306 return (B_FALSE);
307 nwam_enm_free(enmh);
308 return (B_TRUE);
309 }
310
311 static boolean_t
valid_ncp(const char * name)312 valid_ncp(const char *name)
313 {
314 nwam_ncp_handle_t ncph;
315
316 if (nwam_ncp_read(name, 0, &ncph) != NWAM_SUCCESS)
317 return (B_FALSE);
318 nwam_ncp_free(ncph);
319 return (B_TRUE);
320 }
321
322 static boolean_t
valid_ncu(const char * name)323 valid_ncu(const char *name)
324 {
325 nwam_ncp_handle_t ncph;
326 nwam_ncu_handle_t ncuh;
327 nwam_error_t ret;
328
329 if ((ncph = determine_active_ncp()) == NULL)
330 return (B_FALSE);
331
332 ret = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_ANY, 0, &ncuh);
333 nwam_ncp_free(ncph);
334 if (ret != NWAM_SUCCESS && ret != NWAM_ENTITY_MULTIPLE_VALUES)
335 return (B_FALSE);
336 nwam_ncu_free(ncuh);
337 return (B_TRUE);
338 }
339
340 /*
341 * Given a name, returns object type (loc, enm, ncp, or ncu) and how many
342 * objects matched that name.
343 */
344 static nwam_object_type_t
determine_object_type(const char * name,int * num)345 determine_object_type(const char *name, int *num)
346 {
347 nwam_object_type_t type;
348 int n = 0;
349
350 /* see if a valid loc, enm, ncp and/or ncu exists with given name */
351 if (valid_loc(name)) {
352 n++;
353 type = NWAM_OBJECT_TYPE_LOC;
354 }
355 if (valid_enm(name)) {
356 n++;
357 type = NWAM_OBJECT_TYPE_ENM;
358 }
359 if (valid_ncp(name)) {
360 n++;
361 type = NWAM_OBJECT_TYPE_NCP;
362 }
363 if (valid_ncu(name)) {
364 n++;
365 type = NWAM_OBJECT_TYPE_NCU;
366 }
367
368 /* if n > 1, then it means *type was set multiple times, undo it */
369 if (n != 1)
370 type = NWAM_OBJECT_TYPE_UNKNOWN;
371
372 *num = n;
373 return (type);
374 }
375
376 /*
377 * Parses argv array and populates object_type and name.
378 * Program exits on failure.
379 */
380 static void
parse_argv(int argc,char * argv[],int cmd_num,nwam_object_type_t * object_type,nwam_ncu_type_t * ncu_type,nwam_ncu_class_t * ncu_class,const char ** name)381 parse_argv(int argc, char *argv[], int cmd_num, nwam_object_type_t *object_type,
382 nwam_ncu_type_t *ncu_type, nwam_ncu_class_t *ncu_class, const char **name)
383 {
384 int arg;
385 nwam_object_type_t type = NWAM_OBJECT_TYPE_UNKNOWN;
386 uint64_t ncu = NWAM_NCU_TYPE_ANY;
387 uint64_t class = NWAM_NCU_CLASS_ANY;
388
389 /* check argv for option */
390 optind = 0;
391 while ((arg = getopt(argc, argv, "?p:c:x")) != EOF) {
392 switch (arg) {
393 case 'p':
394 type = nwam_string_to_object_type(optarg);
395 if (type == NWAM_OBJECT_TYPE_UNKNOWN)
396 die("Invalid profile-type: %s", optarg);
397 break;
398 case 'c':
399 if (nwam_value_string_get_uint64(NWAM_NCU_PROP_CLASS,
400 optarg, &class) != NWAM_SUCCESS) {
401 die("Invalid ncu-class: %s", optarg);
402 }
403 ncu = nwam_ncu_class_to_type(class);
404 if (ncu == NWAM_NCU_TYPE_ANY ||
405 ncu == NWAM_NCU_TYPE_UNKNOWN)
406 die("Invalid ncu-class: %s", optarg);
407 break;
408 case 'x':
409 /* -x is only for list */
410 if (cmd_num != CMD_LIST)
411 die("-x can only be used with 'list'");
412 extended_list = B_TRUE;
413 break;
414 case '?':
415 default:
416 die_usage(cmd_num);
417 }
418 }
419
420 if (ncu != NWAM_NCU_TYPE_ANY) {
421 /* If -c is given, -p must be NCU. If unspecified, assume NCU */
422 if (type != NWAM_OBJECT_TYPE_UNKNOWN &&
423 type != NWAM_OBJECT_TYPE_NCU)
424 die("'-c <ncu-class>' can only be used for ncu");
425
426 type = NWAM_OBJECT_TYPE_NCU;
427 }
428
429 /* name is mandatory for enable and disable, but not for list */
430 if (optind == (argc-1))
431 *name = argv[optind];
432 else if (argc != optind)
433 die("too many profile names given");
434 else if (cmd_num != CMD_LIST)
435 die("no profile name given");
436
437 /*
438 * No need to determine type for list.
439 * If -p is not given for enable or disable, then determine type.
440 */
441 if (cmd_num != CMD_LIST && type == NWAM_OBJECT_TYPE_UNKNOWN) {
442 int num = 0;
443
444 type = determine_object_type(*name, &num);
445 if (num == 0) {
446 die("no profile matched '%s'", *name);
447 } else if (num > 1) {
448 die("more than one profile matched '%s' - use "
449 "'-p <profile-type>' to specify a profile type.",
450 *name);
451 }
452 }
453
454 *object_type = type;
455 *ncu_type = ncu;
456 *ncu_class = class;
457 }
458
459 /* Enables/Disables profiles depending on boolean */
460 static nwam_error_t
loc_action(const char * name,boolean_t enable,char ** realnamep)461 loc_action(const char *name, boolean_t enable, char **realnamep)
462 {
463 nwam_loc_handle_t loch;
464 nwam_error_t ret;
465
466 if ((ret = nwam_loc_read(name, 0, &loch)) != NWAM_SUCCESS)
467 return (ret);
468
469 if (enable)
470 ret = nwam_loc_enable(loch);
471 else
472 ret = nwam_loc_disable(loch);
473
474 (void) nwam_loc_get_name(loch, realnamep);
475 nwam_loc_free(loch);
476 return (ret);
477 }
478
479 static nwam_error_t
enm_action(const char * name,boolean_t enable,char ** realnamep)480 enm_action(const char *name, boolean_t enable, char **realnamep)
481 {
482 nwam_enm_handle_t enmh;
483 nwam_error_t ret;
484
485 if ((ret = nwam_enm_read(name, 0, &enmh)) != NWAM_SUCCESS)
486 return (ret);
487
488 if (enable)
489 ret = nwam_enm_enable(enmh);
490 else
491 ret = nwam_enm_disable(enmh);
492
493 (void) nwam_enm_get_name(enmh, realnamep);
494 nwam_enm_free(enmh);
495 return (ret);
496 }
497
498 static nwam_error_t
ncu_action(const char * name,nwam_ncp_handle_t ncph,nwam_ncu_type_t type,boolean_t enable,char ** realnamep)499 ncu_action(const char *name, nwam_ncp_handle_t ncph, nwam_ncu_type_t type,
500 boolean_t enable, char **realnamep)
501 {
502 nwam_ncu_handle_t ncuh;
503 nwam_error_t ret;
504 boolean_t retrieved_ncph = B_FALSE;
505
506 if (ncph == NULL) {
507 if ((ncph = determine_active_ncp()) == NULL)
508 return (NWAM_ENTITY_NOT_FOUND);
509 retrieved_ncph = B_TRUE;
510 }
511
512 ret = nwam_ncu_read(ncph, name, type, 0, &ncuh);
513 switch (ret) {
514 case NWAM_SUCCESS:
515 if (enable)
516 ret = nwam_ncu_enable(ncuh);
517 else
518 ret = nwam_ncu_disable(ncuh);
519 (void) nwam_ncu_get_name(ncuh, realnamep);
520 nwam_ncu_free(ncuh);
521 break;
522 case NWAM_ENTITY_MULTIPLE_VALUES:
523 /* Call ncu_action() for link and interface types */
524 ret = ncu_action(name, ncph, NWAM_NCU_TYPE_LINK, enable,
525 realnamep);
526 if (ret != NWAM_SUCCESS)
527 break;
528
529 ret = ncu_action(name, ncph, NWAM_NCU_TYPE_INTERFACE, enable,
530 realnamep);
531 break;
532 }
533 if (retrieved_ncph)
534 nwam_ncp_free(ncph);
535
536 return (ret);
537 }
538
539 /*
540 * If more than one type of profile with the same name, return error.
541 * In such situations, the -p option must be used.
542 * If a location is enabled when a different one is already enabled, then
543 * that location is disabled automatically by nwamd.
544 */
545 static void
enable_func(int argc,char * argv[])546 enable_func(int argc, char *argv[])
547 {
548 nwam_error_t ret;
549 nwam_object_type_t type = NWAM_OBJECT_TYPE_UNKNOWN;
550 nwam_ncu_type_t ncu_type = NWAM_NCU_TYPE_ANY;
551 nwam_ncu_class_t ncu_class = NWAM_NCU_CLASS_ANY;
552 const char *name;
553 char *realname = NULL;
554
555 /* parse_argv() returns only on success */
556 parse_argv(argc, argv, CMD_ENABLE, &type, &ncu_type, &ncu_class, &name);
557
558 /*
559 * NCPs and Locations don't need to disable the currently active
560 * profile - nwamd automatically switches to the new active profile.
561 * and will disable it if necessary.
562 */
563
564 /* activate given profile */
565 switch (type) {
566 case NWAM_OBJECT_TYPE_LOC:
567 ret = loc_action(name, B_TRUE, &realname);
568 break;
569 case NWAM_OBJECT_TYPE_ENM:
570 ret = enm_action(name, B_TRUE, &realname);
571 break;
572 case NWAM_OBJECT_TYPE_NCP:
573 {
574 nwam_ncp_handle_t ncph;
575
576 if ((ret = nwam_ncp_read(name, 0, &ncph)) != NWAM_SUCCESS)
577 break;
578
579 ret = nwam_ncp_enable(ncph);
580 (void) nwam_ncp_get_name(ncph, &realname);
581 nwam_ncp_free(ncph);
582 break;
583 }
584 case NWAM_OBJECT_TYPE_NCU:
585 ret = ncu_action(name, NULL, ncu_type, B_TRUE, &realname);
586 break;
587 }
588
589 switch (ret) {
590 case NWAM_SUCCESS:
591 (void) printf(gettext("Enabling %s '%s'\n"),
592 nwam_object_type_to_string(type),
593 realname != NULL ? realname : name);
594 break;
595 case NWAM_ENTITY_NOT_MANUAL:
596 die("Only profiles with manual activation-mode can be enabled");
597 break;
598 default:
599 die_nwamerr(ret, "Could not enable %s '%s'",
600 nwam_object_type_to_string(type),
601 realname != NULL ? realname : name);
602 }
603 free(realname);
604 }
605
606 /*
607 * Disables a given profile. Similar to enable, the -p option must be used
608 * if more than one type of profile is matched by the given name.
609 */
610 static void
disable_func(int argc,char * argv[])611 disable_func(int argc, char *argv[])
612 {
613 nwam_error_t ret;
614 nwam_object_type_t type = NWAM_OBJECT_TYPE_UNKNOWN;
615 nwam_ncu_type_t ncu_type = NWAM_NCU_TYPE_ANY;
616 nwam_ncu_class_t ncu_class = NWAM_NCU_CLASS_ANY;
617 const char *name;
618 char *realname = NULL;
619
620 /* parse_argv() returns only on success */
621 parse_argv(argc, argv, CMD_DISABLE, &type, &ncu_type, &ncu_class,
622 &name);
623
624 /* deactivate the given profile */
625 switch (type) {
626 case NWAM_OBJECT_TYPE_LOC:
627 ret = loc_action(name, B_FALSE, &realname);
628 break;
629 case NWAM_OBJECT_TYPE_ENM:
630 ret = enm_action(name, B_FALSE, &realname);
631 break;
632 case NWAM_OBJECT_TYPE_NCU:
633 ret = ncu_action(name, NULL, ncu_type, B_FALSE, &realname);
634 break;
635 case NWAM_OBJECT_TYPE_NCP:
636 die("ncp's cannot be disabled. Enable a different ncp to "
637 "switch to that ncp");
638 }
639
640 switch (ret) {
641 case NWAM_SUCCESS:
642 (void) printf(gettext("Disabling %s '%s'\n"),
643 nwam_object_type_to_string(type),
644 realname != NULL ? realname : name);
645 break;
646 case NWAM_ENTITY_NOT_MANUAL:
647 die("Only profiles with manual activation-mode can be "
648 "disabled");
649 break;
650 default:
651 die_nwamerr(ret, "Could not disable %s '%s'",
652 nwam_object_type_to_string(type),
653 realname != NULL ? realname : name);
654 }
655 free(realname);
656 }
657
658 /* prints each column */
659 static boolean_t
print_list_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)660 print_list_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
661 {
662 profile_entry_t *pent = ofarg->ofmt_cbarg;
663
664 switch (ofarg->ofmt_id) {
665 case LIST_TYPE:
666 /* ncu:ip or ncu:phys for NCUs; ncp, loc, enm for others */
667 if (pent->p_type == NWAM_OBJECT_TYPE_NCU) {
668 const char *class;
669 if (nwam_uint64_get_value_string(NWAM_NCU_PROP_CLASS,
670 pent->p_ncu_class, &class) != NWAM_SUCCESS)
671 class = ""; /* empty */
672 (void) snprintf(buf, bufsize, "%s:%s",
673 nwam_object_type_to_string(pent->p_type), class);
674 } else {
675 (void) strlcpy(buf,
676 nwam_object_type_to_string(pent->p_type), bufsize);
677 }
678 break;
679 case LIST_PROFILE:
680 (void) strlcpy(buf, pent->p_name, bufsize);
681 break;
682 case LIST_STATE:
683 (void) strlcpy(buf, nwam_state_to_string(pent->p_state),
684 bufsize);
685 break;
686 case LIST_AUXSTATE:
687 (void) strlcpy(buf,
688 nwam_aux_state_to_string(pent->p_aux_state), bufsize);
689 break;
690 default:
691 die("invalid print_list_cb() input: %d", ofarg->ofmt_id);
692 break;
693 }
694 return (B_TRUE);
695 }
696
697 /* returns the state and auxilliary state of the object */
698 static nwam_state_t
determine_object_state(nwam_object_type_t type,void * handle,nwam_aux_state_t * aux_statep)699 determine_object_state(nwam_object_type_t type, void *handle,
700 nwam_aux_state_t *aux_statep)
701 {
702 nwam_state_t state;
703 nwam_aux_state_t astate;
704 nwam_error_t ret;
705
706 switch (type) {
707 case NWAM_OBJECT_TYPE_ENM:
708 ret = nwam_enm_get_state(handle, &state, &astate);
709 break;
710 case NWAM_OBJECT_TYPE_LOC:
711 ret = nwam_loc_get_state(handle, &state, &astate);
712 break;
713 case NWAM_OBJECT_TYPE_NCP:
714 ret = nwam_ncp_get_state(handle, &state, &astate);
715 break;
716 case NWAM_OBJECT_TYPE_NCU:
717 ret = nwam_ncu_get_state(handle, &state, &astate);
718 break;
719 default:
720 /* NOTREACHED */
721 break;
722 }
723
724 if (ret == NWAM_PERMISSION_DENIED) {
725 die_nwamerr(ret, "could not get object state");
726 } else if (ret != NWAM_SUCCESS) {
727 state = NWAM_STATE_UNINITIALIZED;
728 astate = NWAM_AUX_STATE_UNINITIALIZED;
729 }
730
731 if (aux_statep != NULL)
732 *aux_statep = astate;
733 return (state);
734 }
735
736 /* populate profile_entry_t with values for object with given handle */
737 static int
add_to_profile_entry(nwam_object_type_t type,void * handle,profile_entry_t * pent)738 add_to_profile_entry(nwam_object_type_t type, void *handle,
739 profile_entry_t *pent)
740 {
741 char *name;
742 nwam_error_t ret;
743
744 pent->p_type = type;
745 if (type == NWAM_OBJECT_TYPE_NCU) {
746 nwam_ncu_class_t class;
747 if ((ret = nwam_ncu_get_ncu_class(handle, &class))
748 != NWAM_SUCCESS)
749 return (ret);
750 pent->p_ncu_class = class;
751 } else {
752 pent->p_ncu_class = -1;
753 }
754
755 switch (type) {
756 case NWAM_OBJECT_TYPE_ENM:
757 ret = nwam_enm_get_name(handle, &name);
758 break;
759 case NWAM_OBJECT_TYPE_LOC:
760 ret = nwam_loc_get_name(handle, &name);
761 break;
762 case NWAM_OBJECT_TYPE_NCP:
763 ret = nwam_ncp_get_name(handle, &name);
764 break;
765 case NWAM_OBJECT_TYPE_NCU:
766 ret = nwam_ncu_get_name(handle, &name);
767 break;
768 default:
769 /* NOTREACHED */
770 break;
771 }
772 if (ret != NWAM_SUCCESS) {
773 return (ret);
774 }
775 (void) strlcpy(pent->p_name, name, sizeof (pent->p_name));
776 free(name);
777
778 pent->p_state = determine_object_state(type, handle,
779 &pent->p_aux_state);
780
781 return (NWAM_SUCCESS);
782 }
783
784 /* callback functions used by walk */
785
786 static int
list_ncu_cb(nwam_ncu_handle_t ncuh,void * arg)787 list_ncu_cb(nwam_ncu_handle_t ncuh, void *arg)
788 {
789 ofmt_handle_t ofmt = arg;
790 profile_entry_t pent;
791 nwam_error_t ret;
792
793 bzero(&pent, sizeof (profile_entry_t));
794 ret = add_to_profile_entry(NWAM_OBJECT_TYPE_NCU, ncuh, &pent);
795 if (ret != NWAM_SUCCESS)
796 die_nwamerr(ret, "could not add ncu to list");
797 ofmt_print(ofmt, &pent);
798 return (0);
799 }
800
801 static int
list_ncp_cb(nwam_ncp_handle_t ncph,void * arg)802 list_ncp_cb(nwam_ncp_handle_t ncph, void *arg)
803 {
804 ofmt_handle_t ofmt = arg;
805 profile_entry_t pent;
806 nwam_error_t ret;
807 nwam_state_t state;
808
809 bzero(&pent, sizeof (profile_entry_t));
810 ret = add_to_profile_entry(NWAM_OBJECT_TYPE_NCP, ncph, &pent);
811 if (ret != NWAM_SUCCESS)
812 die_nwamerr(ret, "could not add ncp to list");
813 ofmt_print(ofmt, &pent);
814
815 state = determine_object_state(NWAM_OBJECT_TYPE_NCP, ncph, NULL);
816 if (state == NWAM_STATE_ONLINE) {
817 (void) nwam_ncp_walk_ncus(ncph, list_ncu_cb, ofmt,
818 NWAM_FLAG_NCU_TYPE_ALL, NULL);
819 }
820 return (0);
821 }
822
823 static int
list_loc_cb(nwam_loc_handle_t loch,void * arg)824 list_loc_cb(nwam_loc_handle_t loch, void *arg)
825 {
826 ofmt_handle_t ofmt = arg;
827 profile_entry_t pent;
828 nwam_error_t ret;
829
830 bzero(&pent, sizeof (profile_entry_t));
831 ret = add_to_profile_entry(NWAM_OBJECT_TYPE_LOC, loch, &pent);
832 if (ret != NWAM_SUCCESS)
833 die_nwamerr(ret, "could not add loc to list");
834 ofmt_print(ofmt, &pent);
835 return (0);
836 }
837
838 static int
list_enm_cb(nwam_enm_handle_t enmh,void * arg)839 list_enm_cb(nwam_enm_handle_t enmh, void *arg)
840 {
841 ofmt_handle_t ofmt = arg;
842 profile_entry_t pent;
843 nwam_error_t ret;
844
845 bzero(&pent, sizeof (profile_entry_t));
846 ret = add_to_profile_entry(NWAM_OBJECT_TYPE_ENM, enmh, &pent);
847 if (ret != NWAM_SUCCESS)
848 die_nwamerr(ret, "could not add enm to list");
849 ofmt_print(ofmt, &pent);
850 return (0);
851 }
852
853 /*
854 * lists all profiles and their state
855 */
856 static void
list_func(int argc,char * argv[])857 list_func(int argc, char *argv[])
858 {
859 nwam_error_t ret = NWAM_SUCCESS;
860 nwam_object_type_t type = NWAM_OBJECT_TYPE_UNKNOWN;
861 nwam_ncu_type_t ncu_type = NWAM_NCU_TYPE_ANY;
862 nwam_ncu_class_t ncu_class = NWAM_NCU_CLASS_ANY;
863 char *name = NULL;
864
865 ofmt_handle_t ofmt;
866 ofmt_status_t oferr;
867 char *default_fields = "type,profile,state";
868 char *extended_fields = "type,profile,state,auxiliary state";
869 char *fields = NULL;
870
871 /* parse_argv() returns only on success */
872 parse_argv(argc, argv, CMD_LIST, &type, &ncu_type, &ncu_class,
873 (const char **)&name);
874
875 if (extended_list)
876 fields = extended_fields;
877 else
878 fields = default_fields;
879 oferr = ofmt_open(fields, list_fields, 0, 0, &ofmt);
880 if (oferr != OFMT_SUCCESS) {
881 char buf[OFMT_BUFSIZE];
882 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
883 die("ofmt_open() failed: %s", buf);
884 }
885
886 /* object-name given in command-line */
887 if (name != NULL) {
888 boolean_t found = B_FALSE;
889
890 /*
891 * If objects with different types have the same name
892 * (type = UNKNOWN), then try to open handle for each object
893 * and print if successful.
894 */
895 if (type == NWAM_OBJECT_TYPE_NCP ||
896 type == NWAM_OBJECT_TYPE_UNKNOWN) {
897 nwam_ncp_handle_t ncph;
898 if (nwam_ncp_read(name, 0, &ncph) == NWAM_SUCCESS) {
899 found = B_TRUE;
900 (void) list_ncp_cb(ncph, ofmt);
901 nwam_ncp_free(ncph);
902 }
903 }
904 if (type == NWAM_OBJECT_TYPE_NCU ||
905 type == NWAM_OBJECT_TYPE_UNKNOWN) {
906 nwam_ncp_handle_t ncph;
907 nwam_ncu_handle_t ncuh;
908
909 if ((ncph = determine_active_ncp()) != NULL) {
910 ret = nwam_ncu_read(ncph, name, ncu_type, 0,
911 &ncuh);
912 if (ret == NWAM_ENTITY_MULTIPLE_VALUES) {
913 found = B_TRUE;
914 if (nwam_ncu_read(ncph, name,
915 NWAM_NCU_TYPE_LINK, 0, &ncuh)
916 == NWAM_SUCCESS) {
917 (void) list_ncu_cb(ncuh, ofmt);
918 nwam_ncu_free(ncuh);
919 }
920 if (nwam_ncu_read(ncph, name,
921 NWAM_NCU_TYPE_INTERFACE, 0, &ncuh)
922 == NWAM_SUCCESS) {
923 (void) list_ncu_cb(ncuh, ofmt);
924 nwam_ncu_free(ncuh);
925 }
926 } else if (ret == NWAM_SUCCESS) {
927 found = B_TRUE;
928 (void) list_ncu_cb(ncuh, ofmt);
929 nwam_ncu_free(ncuh);
930 }
931 nwam_ncp_free(ncph);
932 }
933 }
934 if (type == NWAM_OBJECT_TYPE_LOC ||
935 type == NWAM_OBJECT_TYPE_UNKNOWN) {
936 nwam_loc_handle_t loch;
937 if (nwam_loc_read(name, 0, &loch) == NWAM_SUCCESS) {
938 found = B_TRUE;
939 (void) list_loc_cb(loch, ofmt);
940 nwam_loc_free(loch);
941 }
942 }
943 if (type == NWAM_OBJECT_TYPE_ENM ||
944 type == NWAM_OBJECT_TYPE_UNKNOWN) {
945 nwam_enm_handle_t enmh;
946 if (nwam_enm_read(name, 0, &enmh) == NWAM_SUCCESS) {
947 found = B_TRUE;
948 (void) list_enm_cb(enmh, ofmt);
949 nwam_enm_free(enmh);
950 }
951 }
952 /* If at least object is found, don't return error */
953 if (found)
954 ret = NWAM_SUCCESS;
955 else
956 ret = NWAM_ENTITY_NOT_FOUND;
957 }
958
959 /* object-name not given in command-line */
960 if (name == NULL) {
961 /*
962 * If type given (type != UNKNOWN), just walk objects in that
963 * type. Otherwise, walk all ncp, ncu, loc and enm.
964 */
965 if (type == NWAM_OBJECT_TYPE_NCP ||
966 type == NWAM_OBJECT_TYPE_UNKNOWN) {
967 ret = nwam_walk_ncps(list_ncp_cb, ofmt, 0, NULL);
968 if (ret != NWAM_SUCCESS)
969 goto done;
970 }
971 /* no UNKNOWN for NCUs. They walked with active NCP above */
972 if (type == NWAM_OBJECT_TYPE_NCU) {
973 nwam_ncp_handle_t ncph;
974 if ((ncph = determine_active_ncp()) != NULL) {
975 ret = nwam_ncp_walk_ncus(ncph, list_ncu_cb,
976 ofmt, nwam_ncu_class_to_flag(ncu_class),
977 NULL);
978 nwam_ncp_free(ncph);
979 if (ret != NWAM_SUCCESS)
980 goto done;
981 }
982 }
983 if (type == NWAM_OBJECT_TYPE_LOC ||
984 type == NWAM_OBJECT_TYPE_UNKNOWN) {
985 ret = nwam_walk_locs(list_loc_cb, ofmt,
986 NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
987 if (ret != NWAM_SUCCESS)
988 goto done;
989 }
990 if (type == NWAM_OBJECT_TYPE_ENM ||
991 type == NWAM_OBJECT_TYPE_UNKNOWN) {
992 ret = nwam_walk_enms(list_enm_cb, ofmt,
993 NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
994 if (ret != NWAM_SUCCESS)
995 goto done;
996 }
997 }
998
999 done:
1000 ofmt_close(ofmt);
1001 if (ret == NWAM_ENTITY_NOT_FOUND && name != NULL)
1002 die("no profile matched '%s'", name);
1003 else if (ret != NWAM_SUCCESS)
1004 die_nwamerr(ret, "list failed during walk");
1005 }
1006
1007 /*
1008 * Print NWAM events.
1009 */
1010 static void
eventhandler(nwam_event_t event)1011 eventhandler(nwam_event_t event)
1012 {
1013 char description[DESCRIPTION_WIDTH];
1014 char statestr[DESCRIPTION_WIDTH];
1015 char objstr[DESCRIPTION_WIDTH];
1016 char *object = NULL;
1017 const char *action = NULL;
1018 char *state = NULL;
1019 boolean_t display = B_TRUE;
1020 int i;
1021 nwam_wlan_t *wlans;
1022
1023 (void) strlcpy(description, "-", sizeof (description));
1024
1025 switch (event->nwe_type) {
1026 case NWAM_EVENT_TYPE_OBJECT_ACTION:
1027 action = nwam_action_to_string
1028 (event->nwe_data.nwe_object_action.nwe_action);
1029 (void) snprintf(objstr, sizeof (objstr), "%s %s",
1030 nwam_object_type_to_string
1031 (event->nwe_data.nwe_object_action.nwe_object_type),
1032 event->nwe_data.nwe_object_action.nwe_name);
1033 object = objstr;
1034 break;
1035
1036 case NWAM_EVENT_TYPE_OBJECT_STATE:
1037 (void) snprintf(statestr, sizeof (statestr), "%s, %s",
1038 nwam_state_to_string
1039 (event->nwe_data.nwe_object_state.nwe_state),
1040 nwam_aux_state_to_string
1041 (event->nwe_data.nwe_object_state.nwe_aux_state));
1042 state = statestr;
1043
1044 (void) snprintf(objstr, sizeof (objstr), "%s %s",
1045 nwam_object_type_to_string
1046 (event->nwe_data.nwe_object_state.nwe_object_type),
1047 event->nwe_data.nwe_object_state.nwe_name);
1048 object = objstr;
1049 break;
1050
1051 case NWAM_EVENT_TYPE_PRIORITY_GROUP:
1052 (void) snprintf(description, DESCRIPTION_WIDTH,
1053 "priority-group: %d",
1054 event->nwe_data.nwe_priority_group_info.nwe_priority);
1055 break;
1056
1057 case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT:
1058 (void) printf("%-*s \n", EVENT_WIDTH,
1059 nwam_event_type_to_string(event->nwe_type));
1060 wlans = event->nwe_data.nwe_wlan_info.nwe_wlans;
1061 for (i = 0;
1062 i < event->nwe_data.nwe_wlan_info.nwe_num_wlans;
1063 i++) {
1064 (void) snprintf(description, DESCRIPTION_WIDTH,
1065 "%d: %c%c ESSID %s BSSID %s", i + 1,
1066 wlans[i].nww_selected ? 'S' : '-',
1067 wlans[i].nww_connected ? 'C' : '-',
1068 wlans[i].nww_essid, wlans[i].nww_bssid);
1069 (void) printf("%-*s %-*s\n", EVENT_WIDTH, "-",
1070 DESCRIPTION_WIDTH, description);
1071 }
1072 display = B_FALSE;
1073 break;
1074
1075 case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE:
1076 (void) printf("%-*s \n", EVENT_WIDTH,
1077 nwam_event_type_to_string(event->nwe_type));
1078 display = B_FALSE;
1079 break;
1080
1081 case NWAM_EVENT_TYPE_WLAN_NEED_KEY:
1082 (void) printf("%-*s \n", EVENT_WIDTH,
1083 nwam_event_type_to_string(event->nwe_type));
1084 display = B_FALSE;
1085 break;
1086
1087 case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT:
1088 (void) snprintf(description, DESCRIPTION_WIDTH,
1089 gettext("connect to WLAN ESSID %s, BSSID %s %s"),
1090 event->nwe_data.nwe_wlan_info.nwe_wlans[0].nww_essid,
1091 event->nwe_data.nwe_wlan_info.nwe_wlans[0].nww_bssid,
1092 event->nwe_data.nwe_wlan_info.nwe_connected ?
1093 "succeeded" : "failed");
1094 break;
1095
1096 case NWAM_EVENT_TYPE_INFO:
1097 (void) snprintf(description, sizeof (description),
1098 "%s", event->nwe_data.nwe_info.nwe_message);
1099 break;
1100
1101 case NWAM_EVENT_TYPE_IF_ACTION:
1102 action = nwam_action_to_string
1103 (event->nwe_data.nwe_if_action.nwe_action);
1104 object = event->nwe_data.nwe_if_action.nwe_name;
1105 break;
1106
1107 case NWAM_EVENT_TYPE_IF_STATE:
1108 object = event->nwe_data.nwe_if_state.nwe_name;
1109 if (event->nwe_data.nwe_if_state.nwe_addr_valid) {
1110 struct sockaddr_storage *address =
1111 &(event->nwe_data.nwe_if_state.nwe_addr);
1112 struct sockaddr_storage *netmask =
1113 &(event->nwe_data.nwe_if_state.nwe_netmask);
1114 struct sockaddr_in *v4addr;
1115 struct sockaddr_in6 *v6addr;
1116 char addrstr[NWAM_MAX_VALUE_LEN];
1117 int plen = mask2plen((struct sockaddr *)netmask);
1118
1119 switch (address->ss_family) {
1120 case AF_INET:
1121 v4addr = (struct sockaddr_in *)address;
1122 (void) inet_ntop(AF_INET, &v4addr->sin_addr,
1123 addrstr, sizeof (addrstr));
1124 break;
1125 case AF_INET6:
1126 v6addr = (struct sockaddr_in6 *)address;
1127 (void) inet_ntop(AF_INET6, &v6addr->sin6_addr,
1128 addrstr, sizeof (addrstr));
1129 break;
1130 }
1131 (void) snprintf(statestr, sizeof (statestr),
1132 "flags %x addr %s/%d",
1133 event->nwe_data.nwe_if_state.nwe_flags,
1134 addrstr, plen);
1135 } else {
1136 (void) snprintf(statestr, sizeof (statestr),
1137 "flags %x", event->nwe_data.nwe_if_state.nwe_flags);
1138 }
1139 state = statestr;
1140 break;
1141
1142 case NWAM_EVENT_TYPE_LINK_ACTION:
1143 action = nwam_action_to_string
1144 (event->nwe_data.nwe_link_action.nwe_action);
1145 object = event->nwe_data.nwe_link_action.nwe_name;
1146 break;
1147
1148 case NWAM_EVENT_TYPE_LINK_STATE:
1149 state = event->nwe_data.nwe_link_state.nwe_link_up ?
1150 "up" : "down";
1151 object = event->nwe_data.nwe_link_state.nwe_name;
1152 break;
1153 }
1154
1155 if (object != NULL && action != NULL) {
1156 (void) snprintf(description, sizeof (description),
1157 "%s -> action %s", object, action);
1158 } else if (object != NULL && state != NULL) {
1159 (void) snprintf(description, sizeof (description),
1160 "%s -> state %s", object, state);
1161 }
1162
1163 if (display) {
1164 (void) printf("%-*s %-*s\n", EVENT_WIDTH,
1165 nwam_event_type_to_string(event->nwe_type),
1166 DESCRIPTION_WIDTH,
1167 description);
1168 }
1169 }
1170
1171 /*
1172 * listens for events and displays them via the eventhandler() function above.
1173 */
1174 /* ARGSUSED */
1175 static void
show_events_func(int argc,char * argv[])1176 show_events_func(int argc, char *argv[])
1177 {
1178 nwam_error_t err;
1179 nwam_event_t event;
1180
1181 err = nwam_events_init();
1182
1183 if (err != NWAM_SUCCESS)
1184 die_nwamerr(err, "could not bind to receive events");
1185
1186 /* print header */
1187 (void) printf("%-*s %-*s\n", EVENT_WIDTH, "EVENT",
1188 DESCRIPTION_WIDTH, "DESCRIPTION");
1189
1190 do {
1191 /*
1192 * Needed for stdout redirection to ensure event output is
1193 * regularly flushed to file.
1194 */
1195 (void) fflush(stdout);
1196 err = nwam_event_wait(&event);
1197 if (err == NWAM_SUCCESS) {
1198 eventhandler(event);
1199 nwam_event_free(event);
1200 }
1201 } while (err == NWAM_SUCCESS);
1202 die_nwamerr(err, "event handling stopped");
1203 }
1204
1205 /* May need to convert case-insensitive link name match to case-sensitive one */
1206 static nwam_error_t
name_to_linkname(char * name,char ** linknamep)1207 name_to_linkname(char *name, char **linknamep)
1208 {
1209 nwam_error_t err;
1210 nwam_ncp_handle_t ncph = NULL;
1211 nwam_ncu_handle_t ncuh = NULL;
1212
1213 if ((ncph = determine_active_ncp()) == NULL)
1214 return (NWAM_ENTITY_NOT_FOUND);
1215
1216 err = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 0, &ncuh);
1217 if (err == NWAM_SUCCESS)
1218 err = nwam_ncu_get_name(ncuh, linknamep);
1219
1220 nwam_ncp_free(ncph);
1221 nwam_ncu_free(ncuh);
1222 return (err);
1223 }
1224
1225 static void
scan_wifi_func(int argc,char * argv[])1226 scan_wifi_func(int argc, char *argv[])
1227 {
1228 nwam_error_t err;
1229 char *linkname = NULL;
1230
1231 if (argc != 1)
1232 die_usage(CMD_SCAN_WIFI);
1233
1234 if ((err = name_to_linkname(argv[0], &linkname)) != NWAM_SUCCESS)
1235 die_nwamerr(err, "scan request failed for %s", argv[0]);
1236
1237 err = nwam_wlan_scan(linkname);
1238
1239 if (err != NWAM_SUCCESS)
1240 die_nwamerr(err, "scan request failed for %s", linkname);
1241
1242 free(linkname);
1243 }
1244
1245 static void
select_wifi_func(int argc,char * argv[])1246 select_wifi_func(int argc, char *argv[])
1247 {
1248 nwam_error_t err;
1249 char *linkname = NULL;
1250 uint_t i, choice, num_wlans = 0;
1251 uint32_t security_mode;
1252 boolean_t have_key = B_FALSE;
1253 nwam_wlan_t *wlans = NULL;
1254 char choicestr[NWAM_MAX_VALUE_LEN];
1255 char modestr[NWAM_MAX_VALUE_LEN];
1256 char essid[NWAM_MAX_VALUE_LEN];
1257 char bssid[NWAM_MAX_VALUE_LEN];
1258
1259 if (argc != 1)
1260 die_usage(CMD_SELECT_WIFI);
1261
1262 if ((err = name_to_linkname(argv[0], &linkname)) != NWAM_SUCCESS) {
1263 die_nwamerr(err, "could not retrieve scan results for %s",
1264 argv[0]);
1265 }
1266 err = nwam_wlan_get_scan_results(linkname, &num_wlans, &wlans);
1267
1268 if (err != NWAM_SUCCESS) {
1269 die_nwamerr(err, "could not retrieve scan results for %s",
1270 linkname);
1271 }
1272 bssid[0] = '\0';
1273
1274 /* Loop until valid selection made */
1275 for (;;) {
1276 (void) printf("\n");
1277 /* Display WLAN choices for user to select from */
1278 for (i = 0; i < num_wlans; i++) {
1279 (void) printf("%d: ESSID %s BSSID %s\n",
1280 i + 1, wlans[i].nww_essid, wlans[i].nww_bssid);
1281 }
1282 (void) printf(gettext("%d: Other\n"), i + 1);
1283
1284 (void) printf(gettext("\nChoose WLAN to connect to [1-%d]: "),
1285 i + 1);
1286
1287 if (fgets(choicestr, sizeof (choicestr), stdin) != NULL &&
1288 (choice = atoi(choicestr)) >= 1 && choice <= (i + 1))
1289 break;
1290 }
1291
1292 if (choice == i + 1 || wlans[choice - 1].nww_essid[0] == '\0') {
1293 nwam_known_wlan_handle_t kwh = NULL;
1294 nwam_value_t keynameval = NULL;
1295
1296 /* If "Other" or a hidden WLAN is selected, ask for ESSID */
1297 do {
1298 (void) printf(gettext("\nEnter WLAN name: "));
1299 while (fgets(essid, sizeof (essid), stdin) == NULL) {}
1300 essid[strlen(essid) - 1] = '\0';
1301 } while (strspn(essid, " \t") == strlen(essid));
1302
1303 /* If "Other" was selected, secmode must be specified. */
1304 if (choice == i + 1) {
1305 for (;;) {
1306 (void) printf(gettext("1: None\n"));
1307 (void) printf(gettext("2: WEP\n"));
1308 (void) printf(gettext("3: WPA\n"));
1309 (void) printf(gettext("Enter security mode: "));
1310 if (fgets(modestr, sizeof (choicestr), stdin)
1311 != NULL &&
1312 (security_mode = atoi(modestr)) >= 1 &&
1313 security_mode <= 3)
1314 break;
1315 }
1316 } else {
1317 security_mode = wlans[choice - 1].nww_security_mode;
1318 have_key = wlans[choice - 1].nww_have_key;
1319 }
1320
1321 /*
1322 * We have to determine if we have a key for this ESSID from
1323 * the known WLAN list, since we cannot determine this from
1324 * the scan results.
1325 */
1326 if (nwam_known_wlan_read(essid, 0, &kwh) == NWAM_SUCCESS &&
1327 nwam_known_wlan_get_prop_value(kwh,
1328 NWAM_KNOWN_WLAN_PROP_KEYNAME, &keynameval) == NWAM_SUCCESS)
1329 have_key = B_TRUE;
1330 else
1331 have_key = B_FALSE;
1332
1333 nwam_value_free(keynameval);
1334 nwam_known_wlan_free(kwh);
1335 } else {
1336 (void) strlcpy(essid, wlans[choice - 1].nww_essid,
1337 sizeof (essid));
1338 (void) strlcpy(bssid, wlans[choice - 1].nww_bssid,
1339 sizeof (bssid));
1340 security_mode = wlans[choice - 1].nww_security_mode;
1341 have_key = wlans[choice - 1].nww_have_key;
1342 }
1343
1344 if (security_mode != DLADM_WLAN_SECMODE_NONE && !have_key) {
1345 uint_t keyslot = 1;
1346 char key[NWAM_MAX_VALUE_LEN];
1347 char slotstr[NWAM_MAX_VALUE_LEN];
1348
1349 do {
1350 (void) printf(gettext("\nEnter WLAN key for "
1351 "ESSID %s: "), essid);
1352 while (fgets(key, sizeof (key), stdin) == NULL) {}
1353 key[strlen(key) - 1] = '\0';
1354 } while (strspn(key, " \t") == strlen(key));
1355
1356 if (security_mode == DLADM_WLAN_SECMODE_WEP) {
1357 for (;;) {
1358 (void) printf(
1359 gettext("\nEnter key slot [1-4]: "));
1360 if (fgets(slotstr, sizeof (slotstr), stdin)
1361 != NULL && (keyslot = atoi(slotstr)) >= 1 &&
1362 keyslot <= 4)
1363 break;
1364 }
1365 }
1366
1367 err = nwam_wlan_set_key(linkname, essid, bssid, security_mode,
1368 keyslot, key);
1369 if (err != NWAM_SUCCESS)
1370 die_nwamerr(err, "could not set WiFi key");
1371 }
1372 err = nwam_wlan_select(linkname, essid, bssid[0] != '\0' ? bssid : NULL,
1373 security_mode, B_TRUE);
1374 if (err != NWAM_SUCCESS)
1375 die_nwamerr(err, "could not select WLAN %s", essid);
1376 free(wlans);
1377 free(linkname);
1378 }
1379
1380 int
main(int argc,char * argv[])1381 main(int argc, char *argv[])
1382 {
1383 int i;
1384 char *state;
1385
1386 (void) setlocale(LC_ALL, "");
1387 (void) textdomain(TEXT_DOMAIN);
1388
1389 if ((execname = strrchr(argv[0], '/')) == NULL)
1390 execname = argv[0];
1391 else
1392 execname++;
1393
1394 if (argc < 2) {
1395 usage(B_FALSE);
1396 exit(EXIT_FAILURE);
1397 }
1398
1399 for (i = CMD_MIN; i <= CMD_MAX; i++) {
1400 if (strcmp(argv[1], cmd_to_str(i)) == 0) {
1401 if (cmdtab[i].cmd_needs_nwamd) {
1402 state = smf_get_state(NWAM_FMRI);
1403 if (state == NULL || strcmp(state,
1404 SCF_STATE_STRING_ONLINE) != 0) {
1405 free(state);
1406 die("enable '%s' to use '%s %s'",
1407 NWAM_FMRI, execname,
1408 cmd_to_str(cmdtab[i].cmd_num));
1409 }
1410 free(state);
1411 }
1412
1413 cmdtab[i].cmd_handler(argc - 2, &(argv[2]));
1414
1415 exit(EXIT_SUCCESS);
1416 }
1417 }
1418
1419 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
1420 execname, argv[1]);
1421 usage(B_FALSE);
1422
1423 return (1);
1424 }
1425