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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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