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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <ctype.h> 30 #include <locale.h> 31 #include <signal.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <stropts.h> 37 #include <errno.h> 38 #include <kstat.h> 39 #include <strings.h> 40 #include <getopt.h> 41 #include <unistd.h> 42 #include <priv.h> 43 #include <termios.h> 44 #include <pwd.h> 45 #include <auth_attr.h> 46 #include <auth_list.h> 47 #include <libintl.h> 48 #include <libdlpi.h> 49 #include <libdladm.h> 50 #include <liblaadm.h> 51 #include <libmacadm.h> 52 #include <libwladm.h> 53 #include <libinetutil.h> 54 #include <bsm/adt.h> 55 #include <bsm/adt_event.h> 56 57 #define AGGR_DRV "aggr" 58 #define MAXPORT 256 59 #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 60 "%-5s %-4s %-4s %-9s %-7s\n" 61 62 typedef struct pktsum_s { 63 uint64_t ipackets; 64 uint64_t opackets; 65 uint64_t rbytes; 66 uint64_t obytes; 67 uint32_t ierrors; 68 uint32_t oerrors; 69 } pktsum_t; 70 71 typedef struct show_link_state { 72 boolean_t ls_firstonly; 73 boolean_t ls_donefirst; 74 boolean_t ls_stats; 75 pktsum_t ls_prevstats; 76 boolean_t ls_parseable; 77 } show_link_state_t; 78 79 typedef struct show_grp_state { 80 uint32_t gs_key; 81 boolean_t gs_lacp; 82 boolean_t gs_found; 83 boolean_t gs_stats; 84 boolean_t gs_firstonly; 85 pktsum_t gs_prevstats[MAXPORT]; 86 boolean_t gs_parseable; 87 } show_grp_state_t; 88 89 typedef struct show_mac_state { 90 boolean_t ms_firstonly; 91 boolean_t ms_donefirst; 92 pktsum_t ms_prevstats; 93 boolean_t ms_parseable; 94 } show_mac_state_t; 95 96 typedef struct port_state { 97 char *state_name; 98 aggr_port_state_t state_num; 99 } port_state_t; 100 101 static port_state_t port_states[] = { 102 {"standby", AGGR_PORT_STATE_STANDBY }, 103 {"attached", AGGR_PORT_STATE_ATTACHED } 104 }; 105 106 #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 107 108 typedef void cmdfunc_t(int, char **); 109 110 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 111 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 112 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 113 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 114 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 115 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 116 static cmdfunc_t do_init_linkprop, do_init_secobj; 117 118 static void link_stats(const char *, uint32_t); 119 static void aggr_stats(uint16_t, uint32_t); 120 static void dev_stats(const char *dev, uint32_t); 121 122 static void get_mac_stats(const char *, pktsum_t *); 123 static void get_link_stats(const char *, pktsum_t *); 124 static uint64_t mac_ifspeed(const char *); 125 static char *mac_link_state(const char *); 126 static char *mac_link_duplex(const char *); 127 static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 128 static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 129 130 typedef struct cmd { 131 char *c_name; 132 cmdfunc_t *c_fn; 133 } cmd_t; 134 135 static cmd_t cmds[] = { 136 { "show-link", do_show_link }, 137 { "show-dev", do_show_dev }, 138 { "create-aggr", do_create_aggr }, 139 { "delete-aggr", do_delete_aggr }, 140 { "add-aggr", do_add_aggr }, 141 { "remove-aggr", do_remove_aggr }, 142 { "modify-aggr", do_modify_aggr }, 143 { "show-aggr", do_show_aggr }, 144 { "up-aggr", do_up_aggr }, 145 { "down-aggr", do_down_aggr }, 146 { "scan-wifi", do_scan_wifi }, 147 { "connect-wifi", do_connect_wifi }, 148 { "disconnect-wifi", do_disconnect_wifi }, 149 { "show-wifi", do_show_wifi }, 150 { "show-linkprop", do_show_linkprop }, 151 { "set-linkprop", do_set_linkprop }, 152 { "reset-linkprop", do_reset_linkprop }, 153 { "create-secobj", do_create_secobj }, 154 { "delete-secobj", do_delete_secobj }, 155 { "show-secobj", do_show_secobj }, 156 { "init-linkprop", do_init_linkprop }, 157 { "init-secobj", do_init_secobj } 158 }; 159 160 static const struct option longopts[] = { 161 {"vlan-id", required_argument, 0, 'v' }, 162 {"dev", required_argument, 0, 'd' }, 163 {"policy", required_argument, 0, 'P' }, 164 {"lacp-mode", required_argument, 0, 'l' }, 165 {"lacp-timer", required_argument, 0, 'T' }, 166 {"unicast", required_argument, 0, 'u' }, 167 {"statistics", no_argument, 0, 's' }, 168 {"interval", required_argument, 0, 'i' }, 169 {"lacp", no_argument, 0, 'L' }, 170 {"temporary", no_argument, 0, 't' }, 171 {"root-dir", required_argument, 0, 'r' }, 172 {"parseable", no_argument, 0, 'p' }, 173 { 0, 0, 0, 0 } 174 }; 175 176 static const struct option prop_longopts[] = { 177 {"temporary", no_argument, 0, 't' }, 178 {"root-dir", required_argument, 0, 'R' }, 179 {"prop", required_argument, 0, 'p' }, 180 {"parseable", no_argument, 0, 'c' }, 181 {"persistent", no_argument, 0, 'P' }, 182 { 0, 0, 0, 0 } 183 }; 184 185 static const struct option wifi_longopts[] = { 186 {"parseable", no_argument, 0, 'p' }, 187 {"output", required_argument, 0, 'o' }, 188 {"essid", required_argument, 0, 'e' }, 189 {"bsstype", required_argument, 0, 'b' }, 190 {"mode", required_argument, 0, 'm' }, 191 {"key", required_argument, 0, 'k' }, 192 {"sec", required_argument, 0, 's' }, 193 {"auth", required_argument, 0, 'a' }, 194 {"create-ibss", required_argument, 0, 'c' }, 195 {"timeout", required_argument, 0, 'T' }, 196 {"all-links", no_argument, 0, 'a' }, 197 {"temporary", no_argument, 0, 't' }, 198 {"root-dir", required_argument, 0, 'R' }, 199 {"persistent", no_argument, 0, 'P' }, 200 {"file", required_argument, 0, 'f' }, 201 { 0, 0, 0, 0 } 202 }; 203 204 static char *progname; 205 static sig_atomic_t signalled; 206 207 #define PRINT_ERR_DIAG(s, diag, func) { \ 208 (void) fprintf(stderr, gettext(s), progname, strerror(errno)); \ 209 if (diag != 0) \ 210 (void) fprintf(stderr, " (%s)", func(diag)); \ 211 (void) fprintf(stderr, "\n"); \ 212 } 213 214 static void 215 usage(void) 216 { 217 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 218 "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 219 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 220 "\n" 221 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 222 "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 223 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 224 "\t [-T <time>] [-u <address>] <key>\n" 225 "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 226 "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 227 "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 228 "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 229 "\n" 230 "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 231 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 232 " [-s wep]\n" 233 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 234 "\t [-T <time>] [<name>]\n" 235 "\tdisconnect-wifi [-a] [<name>]\n" 236 "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 237 "\n" 238 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 239 " <name>\n" 240 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 241 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 242 "\n" 243 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 244 " <secobj>\n" 245 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 246 "\tshow-secobj [-pP][<secobj>,...]\n")); 247 exit(1); 248 } 249 250 int 251 main(int argc, char *argv[]) 252 { 253 int i; 254 cmd_t *cmdp; 255 256 (void) setlocale(LC_ALL, ""); 257 #if !defined(TEXT_DOMAIN) 258 #define TEXT_DOMAIN "SYS_TEST" 259 #endif 260 (void) textdomain(TEXT_DOMAIN); 261 262 progname = argv[0]; 263 264 if (argc < 2) 265 usage(); 266 267 if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 268 !priv_ineffect(PRIV_NET_RAWACCESS)) { 269 (void) fprintf(stderr, 270 gettext("%s: insufficient privileges\n"), progname); 271 exit(1); 272 } 273 274 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 275 cmdp = &cmds[i]; 276 if (strcmp(argv[1], cmdp->c_name) == 0) { 277 cmdp->c_fn(argc - 1, &argv[1]); 278 exit(0); 279 } 280 } 281 282 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 283 progname, argv[1]); 284 usage(); 285 286 return (0); 287 } 288 289 290 static void 291 do_create_aggr(int argc, char *argv[]) 292 { 293 char option; 294 uint16_t key; 295 uint32_t policy = AGGR_POLICY_L4; 296 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 297 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 298 laadm_port_attr_db_t port[MAXPORT]; 299 uint_t nport = 0; 300 uint8_t mac_addr[ETHERADDRL]; 301 boolean_t mac_addr_fixed = B_FALSE; 302 boolean_t P_arg = B_FALSE; 303 boolean_t l_arg = B_FALSE; 304 boolean_t t_arg = B_FALSE; 305 boolean_t u_arg = B_FALSE; 306 boolean_t T_arg = B_FALSE; 307 char *altroot = NULL; 308 char *endp = NULL; 309 laadm_diag_t diag = 0; 310 311 opterr = 0; 312 while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 313 longopts, NULL)) != -1) { 314 switch (option) { 315 case 'd': 316 if (nport >= MAXPORT) { 317 (void) fprintf(stderr, 318 gettext("%s: too many <dev> arguments\n"), 319 progname); 320 exit(1); 321 } 322 323 if (strlcpy(port[nport].lp_devname, optarg, 324 MAXNAMELEN) >= MAXNAMELEN) { 325 (void) fprintf(stderr, 326 gettext("%s: device name too long\n"), 327 progname); 328 exit(1); 329 } 330 331 nport++; 332 break; 333 case 'P': 334 if (P_arg) { 335 (void) fprintf(stderr, gettext( 336 "%s: the option -P cannot be specified " 337 "more than once\n"), progname); 338 usage(); 339 } 340 341 P_arg = B_TRUE; 342 343 if (!laadm_str_to_policy(optarg, &policy)) { 344 (void) fprintf(stderr, 345 gettext("%s: invalid policy '%s'\n"), 346 progname, optarg); 347 exit(1); 348 } 349 break; 350 case 'u': 351 if (u_arg) { 352 (void) fprintf(stderr, gettext( 353 "%s: the option -u cannot be specified " 354 "more than once\n"), progname); 355 usage(); 356 } 357 358 u_arg = B_TRUE; 359 360 if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 361 mac_addr)) { 362 (void) fprintf(stderr, 363 gettext("%s: invalid MAC address '%s'\n"), 364 progname, optarg); 365 exit(1); 366 } 367 368 break; 369 case 'l': 370 if (l_arg) { 371 (void) fprintf(stderr, gettext( 372 "%s: the option -l cannot be specified " 373 "more than once\n"), progname); 374 usage(); 375 } 376 377 l_arg = B_TRUE; 378 379 if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) { 380 (void) fprintf(stderr, 381 gettext("%s: invalid LACP mode '%s'\n"), 382 progname, optarg); 383 exit(1); 384 } 385 386 break; 387 case 'T': 388 if (T_arg) { 389 (void) fprintf(stderr, gettext( 390 "%s: the option -T cannot be specified " 391 "more than once\n"), progname); 392 usage(); 393 } 394 395 T_arg = B_TRUE; 396 397 if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) { 398 (void) fprintf(stderr, 399 gettext("%s: invalid LACP timer value" 400 " '%s'\n"), 401 progname, optarg); 402 exit(1); 403 } 404 405 break; 406 case 't': 407 t_arg = B_TRUE; 408 break; 409 case 'R': 410 altroot = optarg; 411 break; 412 case ':': 413 (void) fprintf(stderr, 414 gettext("%s: option requires a value '-%c'\n"), 415 progname, optopt); 416 exit(1); 417 /*NOTREACHED*/ 418 case '?': 419 default: 420 (void) fprintf(stderr, 421 gettext("%s: unrecognized option '-%c'\n"), 422 progname, optopt); 423 exit(1); 424 } 425 } 426 427 if (nport == 0) 428 usage(); 429 430 /* get key value (required last argument) */ 431 if (optind != (argc-1)) 432 usage(); 433 434 errno = 0; 435 key = (int)strtol(argv[optind], &endp, 10); 436 if (errno != 0 || key < 1 || *endp != '\0') { 437 (void) fprintf(stderr, 438 gettext("%s: illegal key value '%d'\n"), 439 progname, key); 440 exit(1); 441 } 442 443 if (laadm_create(key, nport, port, policy, mac_addr_fixed, 444 mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) { 445 PRINT_ERR_DIAG("%s: create operation failed: %s", diag, 446 laadm_diag); 447 exit(1); 448 } 449 } 450 451 static void 452 do_delete_aggr(int argc, char *argv[]) 453 { 454 uint16_t key; 455 char option; 456 boolean_t t_arg = B_FALSE; 457 char *altroot = NULL; 458 char *endp = NULL; 459 laadm_diag_t diag = 0; 460 461 opterr = 0; 462 while ((option = getopt_long(argc, argv, ":R:t", longopts, 463 NULL)) != -1) { 464 switch (option) { 465 466 case 't': 467 t_arg = B_TRUE; 468 break; 469 case 'R': 470 altroot = optarg; 471 break; 472 case ':': 473 (void) fprintf(stderr, 474 gettext("%s: option requires a value '-%c'\n"), 475 progname, optopt); 476 exit(1); 477 break; 478 case '?': 479 default: 480 (void) fprintf(stderr, 481 gettext("%s: unrecognized option '-%c'\n"), 482 progname, optopt); 483 exit(1); 484 break; 485 } 486 } 487 488 /* get key value (required last argument) */ 489 if (optind != (argc-1)) 490 usage(); 491 492 errno = 0; 493 key = (int)strtol(argv[optind], &endp, 10); 494 if (errno != 0 || key < 1 || *endp != '\0') { 495 (void) fprintf(stderr, 496 gettext("%s: illegal key value '%d'\n"), 497 progname, key); 498 exit(1); 499 } 500 501 if (laadm_delete(key, t_arg, altroot, &diag) < 0) { 502 PRINT_ERR_DIAG("%s: delete operation failed: %s", diag, 503 laadm_diag); 504 exit(1); 505 } 506 } 507 508 static void 509 do_add_aggr(int argc, char *argv[]) 510 { 511 char option; 512 uint16_t key; 513 laadm_port_attr_db_t port[MAXPORT]; 514 uint_t nport = 0; 515 boolean_t t_arg = B_FALSE; 516 char *altroot = NULL; 517 char *endp = NULL; 518 laadm_diag_t diag = 0; 519 520 opterr = 0; 521 while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 522 NULL)) != -1) { 523 switch (option) { 524 case 'd': 525 if (nport >= MAXPORT) { 526 (void) fprintf(stderr, 527 gettext("%s: too many <dev> arguments\n"), 528 progname); 529 exit(1); 530 } 531 532 if (strlcpy(port[nport].lp_devname, optarg, 533 MAXNAMELEN) >= MAXNAMELEN) { 534 (void) fprintf(stderr, 535 gettext("%s: device name too long\n"), 536 progname); 537 exit(1); 538 } 539 nport++; 540 break; 541 case 't': 542 t_arg = B_TRUE; 543 break; 544 case 'R': 545 altroot = optarg; 546 break; 547 case ':': 548 (void) fprintf(stderr, 549 gettext("%s: option requires a value '-%c'\n"), 550 progname, optopt); 551 exit(1); 552 /*NOTREACHED*/ 553 case '?': 554 default: 555 (void) fprintf(stderr, 556 gettext("%s: unrecognized option '-%c'\n"), 557 progname, optopt); 558 exit(1); 559 } 560 } 561 562 if (nport == 0) 563 usage(); 564 565 /* get key value (required last argument) */ 566 if (optind != (argc-1)) 567 usage(); 568 569 errno = 0; 570 key = (int)strtol(argv[optind], &endp, 10); 571 if (errno != 0 || key < 1 || *endp != '\0') { 572 (void) fprintf(stderr, 573 gettext("%s: illegal key value '%d'\n"), 574 progname, key); 575 exit(1); 576 } 577 578 if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 579 /* 580 * checking ENOTSUP is a temporary workaround 581 * and should be removed once 6399681 is fixed. 582 */ 583 if (errno == ENOTSUP) { 584 (void) fprintf(stderr, 585 gettext("%s: add operation failed: %s\n"), 586 progname, 587 gettext("device capabilities don't match")); 588 exit(ENOTSUP); 589 } 590 PRINT_ERR_DIAG("%s: add operation failed: %s", diag, 591 laadm_diag); 592 exit(1); 593 } 594 } 595 596 static void 597 do_remove_aggr(int argc, char *argv[]) 598 { 599 char option; 600 uint16_t key; 601 laadm_port_attr_db_t port[MAXPORT]; 602 uint_t nport = 0; 603 boolean_t t_arg = B_FALSE; 604 char *altroot = NULL; 605 char *endp = NULL; 606 laadm_diag_t diag = 0; 607 608 opterr = 0; 609 while ((option = getopt_long(argc, argv, ":d:R:t", 610 longopts, NULL)) != -1) { 611 switch (option) { 612 case 'd': 613 if (nport >= MAXPORT) { 614 (void) fprintf(stderr, 615 gettext("%s: too many <dev> arguments\n"), 616 progname); 617 exit(1); 618 } 619 620 if (strlcpy(port[nport].lp_devname, optarg, 621 MAXNAMELEN) >= MAXNAMELEN) { 622 (void) fprintf(stderr, 623 gettext("%s: device name too long\n"), 624 progname); 625 exit(1); 626 } 627 nport++; 628 break; 629 case 't': 630 t_arg = B_TRUE; 631 break; 632 case 'R': 633 altroot = optarg; 634 break; 635 case ':': 636 (void) fprintf(stderr, 637 gettext("%s: option requires a value '-%c'\n"), 638 progname, optopt); 639 exit(1); 640 /*NOTREACHED*/ 641 case '?': 642 default: 643 (void) fprintf(stderr, 644 gettext("%s: unrecognized option '-%c'\n"), 645 progname, optopt); 646 exit(1); 647 } 648 } 649 650 if (nport == 0) 651 usage(); 652 653 /* get key value (required last argument) */ 654 if (optind != (argc-1)) 655 usage(); 656 657 errno = 0; 658 key = (int)strtol(argv[optind], &endp, 10); 659 if (errno != 0 || key < 1 || *endp != '\0') { 660 (void) fprintf(stderr, 661 gettext("%s: illegal key value '%d'\n"), 662 progname, key); 663 exit(1); 664 } 665 666 if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) { 667 PRINT_ERR_DIAG("%s: remove operation failed: %s", diag, 668 laadm_diag); 669 exit(1); 670 } 671 } 672 673 static void 674 do_modify_aggr(int argc, char *argv[]) 675 { 676 char option; 677 uint16_t key; 678 uint32_t policy = AGGR_POLICY_L4; 679 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 680 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 681 uint8_t mac_addr[ETHERADDRL]; 682 boolean_t mac_addr_fixed = B_FALSE; 683 uint8_t modify_mask = 0; 684 boolean_t t_arg = B_FALSE; 685 char *altroot = NULL; 686 char *endp = NULL; 687 laadm_diag_t diag = 0; 688 689 opterr = 0; 690 while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 691 NULL)) != -1) { 692 switch (option) { 693 case 'P': 694 if (modify_mask & LAADM_MODIFY_POLICY) { 695 (void) fprintf(stderr, gettext( 696 "%s: the option -P cannot be specified " 697 "more than once\n"), progname); 698 usage(); 699 } 700 701 modify_mask |= LAADM_MODIFY_POLICY; 702 703 if (!laadm_str_to_policy(optarg, &policy)) { 704 (void) fprintf(stderr, 705 gettext("%s: invalid policy '%s'\n"), 706 progname, optarg); 707 exit(1); 708 } 709 break; 710 case 'u': 711 if (modify_mask & LAADM_MODIFY_MAC) { 712 (void) fprintf(stderr, gettext( 713 "%s: the option -u cannot be specified " 714 "more than once\n"), progname); 715 usage(); 716 } 717 718 modify_mask |= LAADM_MODIFY_MAC; 719 720 if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 721 mac_addr)) { 722 (void) fprintf(stderr, 723 gettext("%s: invalid MAC address '%s'\n"), 724 progname, optarg); 725 exit(1); 726 } 727 728 break; 729 case 'l': 730 if (modify_mask & LAADM_MODIFY_LACP_MODE) { 731 (void) fprintf(stderr, gettext( 732 "%s: the option -l cannot be specified " 733 "more than once\n"), progname); 734 usage(); 735 } 736 737 modify_mask |= LAADM_MODIFY_LACP_MODE; 738 739 if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) { 740 (void) fprintf(stderr, 741 gettext("%s: invalid LACP mode '%s'\n"), 742 progname, optarg); 743 exit(1); 744 } 745 746 break; 747 case 'T': 748 if (modify_mask & LAADM_MODIFY_LACP_TIMER) { 749 (void) fprintf(stderr, gettext( 750 "%s: the option -T cannot be specified " 751 "more than once\n"), progname); 752 usage(); 753 } 754 755 modify_mask |= LAADM_MODIFY_LACP_TIMER; 756 757 if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) { 758 (void) fprintf(stderr, 759 gettext("%s: invalid LACP timer value" 760 " '%s'\n"), 761 progname, optarg); 762 exit(1); 763 } 764 765 break; 766 case 't': 767 t_arg = B_TRUE; 768 break; 769 case 'R': 770 altroot = optarg; 771 break; 772 case ':': 773 (void) fprintf(stderr, 774 gettext("%s: option requires a value '-%c'\n"), 775 progname, optopt); 776 exit(1); 777 /*NOTREACHED*/ 778 case '?': 779 default: 780 (void) fprintf(stderr, 781 gettext("%s: unrecognized option '-%c'\n"), 782 progname, optopt); 783 exit(1); 784 } 785 } 786 787 if (modify_mask == 0) { 788 (void) fprintf(stderr, gettext("%s: at least one of the " 789 "-PulT options must be specified\n"), progname); 790 usage(); 791 } 792 793 /* get key value (required last argument) */ 794 if (optind != (argc-1)) 795 usage(); 796 797 errno = 0; 798 key = (int)strtol(argv[optind], &endp, 10); 799 if (errno != 0 || key < 1 || *endp != '\0') { 800 (void) fprintf(stderr, 801 gettext("%s: illegal key value '%d'\n"), 802 progname, key); 803 exit(1); 804 } 805 806 807 if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 808 lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) { 809 PRINT_ERR_DIAG("%s: modify operation failed: %s", diag, 810 laadm_diag); 811 exit(1); 812 } 813 } 814 815 static void 816 do_up_aggr(int argc, char *argv[]) 817 { 818 uint16_t key = 0; 819 char *endp = NULL; 820 laadm_diag_t diag = 0; 821 822 /* get aggregation key (optional last argument) */ 823 if (argc == 2) { 824 errno = 0; 825 key = (int)strtol(argv[1], &endp, 10); 826 if (errno != 0 || key < 1 || *endp != '\0') { 827 (void) fprintf(stderr, 828 gettext("%s: illegal key value '%d'\n"), 829 progname, key); 830 exit(1); 831 } 832 } else if (argc > 2) { 833 usage(); 834 } 835 836 if (laadm_up(key, NULL, &diag) < 0) { 837 if (key != 0) { 838 (void) fprintf(stderr, 839 gettext("%s: could not bring up aggregation" 840 " '%u' : %s"), progname, key, strerror(errno)); 841 if (diag != 0) 842 (void) fprintf(stderr, " (%s)", 843 laadm_diag(diag)); 844 (void) fprintf(stderr, "\n"); 845 } else { 846 PRINT_ERR_DIAG( 847 "%s: could not bring aggregations up: %s", 848 diag, laadm_diag); 849 } 850 exit(1); 851 } 852 } 853 854 static void 855 do_down_aggr(int argc, char *argv[]) 856 { 857 uint16_t key = 0; 858 char *endp = NULL; 859 860 /* get aggregation key (optional last argument) */ 861 if (argc == 2) { 862 errno = 0; 863 key = (int)strtol(argv[1], &endp, 10); 864 if (errno != 0 || key < 1 || *endp != '\0') { 865 (void) fprintf(stderr, 866 gettext("%s: illegal key value '%d'\n"), 867 progname, key); 868 exit(1); 869 } 870 } else if (argc > 2) { 871 usage(); 872 } 873 874 if (laadm_down(key) < 0) { 875 if (key != 0) { 876 (void) fprintf(stderr, 877 gettext("%s: could not bring aggregation" 878 " down '%u' : %s"), 879 progname, key, strerror(errno)); 880 (void) fprintf(stderr, "\n"); 881 } else { 882 (void) fprintf(stderr, 883 gettext("%s: could not bring aggregations" 884 " down: %s"), progname, strerror(errno)); 885 } 886 exit(1); 887 } 888 } 889 890 #define TYPE_WIDTH 10 891 892 static void 893 print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 894 { 895 char type[TYPE_WIDTH]; 896 897 if (!legacy) { 898 char drv[LIFNAMSIZ]; 899 int instance; 900 901 if (dap->da_vid != 0) { 902 (void) snprintf(type, TYPE_WIDTH, "vlan %u", 903 dap->da_vid); 904 } else { 905 (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 906 } 907 if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 908 return; 909 if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 910 (void) printf("%s type=%s mtu=%d key=%u\n", 911 name, type, dap->da_max_sdu, instance); 912 } else { 913 (void) printf("%s type=%s mtu=%d device=%s\n", 914 name, type, dap->da_max_sdu, dap->da_dev); 915 } 916 } else { 917 (void) printf("%s type=legacy mtu=%d device=%s\n", 918 name, dap->da_max_sdu, name); 919 } 920 } 921 922 static void 923 print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 924 { 925 char type[TYPE_WIDTH]; 926 927 if (!legacy) { 928 char drv[LIFNAMSIZ]; 929 int instance; 930 931 if (dap->da_vid != 0) { 932 (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 933 dap->da_vid); 934 } else { 935 (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 936 } 937 if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 938 return; 939 if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 940 (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 941 "\taggregation: key %u\n"), name, type, 942 dap->da_max_sdu, instance); 943 } else { 944 (void) printf(gettext("%-9s\ttype: %s\tmtu: " 945 "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 946 dap->da_dev); 947 } 948 } else { 949 (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 950 "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 951 } 952 } 953 954 static int 955 get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 956 { 957 int err; 958 959 if ((err = dladm_info(name, dlattrp)) == 0) { 960 *legacy = B_FALSE; 961 } else if (err < 0 && errno == ENODEV) { 962 int fd; 963 dlpi_if_attr_t dia; 964 dl_info_ack_t dlia; 965 966 /* 967 * A return value of ENODEV means that the specified 968 * device is not gldv3. 969 */ 970 if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && 971 dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, 972 NULL, NULL) != -1) { 973 (void) dlpi_close(fd); 974 975 *legacy = B_TRUE; 976 bzero(dlattrp, sizeof (*dlattrp)); 977 dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; 978 } else { 979 errno = ENOENT; 980 return (-1); 981 } 982 } else { 983 /* 984 * If the return value is not ENODEV, this means that 985 * user is either passing in a bogus interface name 986 * or a vlan interface name that doesn't exist yet. 987 */ 988 errno = ENOENT; 989 return (-1); 990 } 991 return (0); 992 } 993 994 /* ARGSUSED */ 995 static void 996 show_link(void *arg, const char *name) 997 { 998 dladm_attr_t dlattr; 999 boolean_t legacy = B_TRUE; 1000 show_link_state_t *state = (show_link_state_t *)arg; 1001 1002 if (get_if_info(name, &dlattr, &legacy) < 0) { 1003 (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), 1004 progname, name); 1005 exit(1); 1006 } 1007 1008 if (state->ls_parseable) { 1009 print_link_parseable(name, &dlattr, legacy); 1010 } else { 1011 print_link(name, &dlattr, legacy); 1012 } 1013 } 1014 1015 static void 1016 show_link_stats(void *arg, const char *name) 1017 { 1018 show_link_state_t *state = (show_link_state_t *)arg; 1019 pktsum_t stats, diff_stats; 1020 1021 if (state->ls_firstonly) { 1022 if (state->ls_donefirst) 1023 return; 1024 state->ls_donefirst = B_TRUE; 1025 } else { 1026 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 1027 } 1028 1029 get_link_stats(name, &stats); 1030 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 1031 1032 (void) printf("%s", name); 1033 (void) printf("\t\t%-10llu", diff_stats.ipackets); 1034 (void) printf("%-12llu", diff_stats.rbytes); 1035 (void) printf("%-8u", diff_stats.ierrors); 1036 (void) printf("%-10llu", diff_stats.opackets); 1037 (void) printf("%-12llu", diff_stats.obytes); 1038 (void) printf("%-8u\n", diff_stats.oerrors); 1039 1040 state->ls_prevstats = stats; 1041 } 1042 1043 static void 1044 dump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 1045 { 1046 char policy_str[LAADM_POLICY_STR_LEN]; 1047 char addr_str[ETHERADDRL * 3]; 1048 1049 if (!parseable) { 1050 (void) printf(gettext("key: %d (0x%04x)"), 1051 grp->lg_key, grp->lg_key); 1052 1053 (void) printf(gettext("\tpolicy: %s"), 1054 laadm_policy_to_str(grp->lg_policy, policy_str)); 1055 1056 (void) printf(gettext("\taddress: %s (%s)\n"), 1057 laadm_mac_addr_to_str(grp->lg_mac, addr_str), 1058 (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 1059 } else { 1060 (void) printf("aggr key=%d", grp->lg_key); 1061 1062 (void) printf(" policy=%s", 1063 laadm_policy_to_str(grp->lg_policy, policy_str)); 1064 1065 (void) printf(" address=%s", 1066 laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 1067 1068 (void) printf(" address-type=%s\n", 1069 (grp->lg_mac_fixed) ? "fixed" : "auto"); 1070 } 1071 } 1072 1073 static void 1074 dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 1075 { 1076 const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 1077 const char *lacp_timer_str = 1078 laadm_lacp_timer_to_str(grp->lg_lacp_timer); 1079 1080 if (!parseable) { 1081 (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 1082 (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 1083 } else { 1084 (void) printf(" lacp-mode=%s", lacp_mode_str); 1085 (void) printf(" lacp-timer=%s\n", lacp_timer_str); 1086 } 1087 } 1088 1089 static void 1090 dump_grp_stats(laadm_grp_attr_sys_t *grp) 1091 { 1092 (void) printf("key: %d", grp->lg_key); 1093 (void) printf("\tipackets rbytes opackets obytes "); 1094 (void) printf("%%ipkts %%opkts\n"); 1095 } 1096 1097 static void 1098 dump_ports_lacp_head(void) 1099 { 1100 (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 1101 gettext("timeout"), gettext("aggregatable"), gettext("sync"), 1102 gettext("coll"), gettext("dist"), gettext("defaulted"), 1103 gettext("expired")); 1104 } 1105 1106 static void 1107 dump_ports_head(void) 1108 { 1109 (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 1110 "state\n")); 1111 } 1112 1113 static char * 1114 port_state_to_str(aggr_port_state_t state_num) 1115 { 1116 int i; 1117 port_state_t *state; 1118 1119 for (i = 0; i < NPORTSTATES; i++) { 1120 state = &port_states[i]; 1121 if (state->state_num == state_num) 1122 return (state->state_name); 1123 } 1124 1125 return ("unknown"); 1126 } 1127 1128 static void 1129 dump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 1130 { 1131 char *dev = port->lp_devname; 1132 char buf[ETHERADDRL * 3]; 1133 1134 if (!parseable) { 1135 (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 1136 port->lp_mac, buf)); 1137 (void) printf("\t %-5u Mbps", (int)(mac_ifspeed(dev) / 1138 1000000ull)); 1139 (void) printf("\t%s", mac_link_duplex(dev)); 1140 (void) printf("\t%s", mac_link_state(dev)); 1141 (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 1142 1143 } else { 1144 (void) printf(" device=%s address=%s", dev, 1145 laadm_mac_addr_to_str(port->lp_mac, buf)); 1146 (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 1147 1000000ull)); 1148 (void) printf(" duplex=%s", mac_link_duplex(dev)); 1149 (void) printf(" link=%s", mac_link_state(dev)); 1150 (void) printf(" port=%s", port_state_to_str(port->lp_state)); 1151 } 1152 } 1153 1154 static void 1155 dump_port_lacp(laadm_port_attr_sys_t *port) 1156 { 1157 aggr_lacp_state_t *state = &port->lp_lacp_state; 1158 1159 (void) printf(DUMP_LACP_FORMAT, 1160 port->lp_devname, state->bit.activity ? "active" : "passive", 1161 state->bit.timeout ? "short" : "long", 1162 state->bit.aggregation ? "yes" : "no", 1163 state->bit.sync ? "yes" : "no", 1164 state->bit.collecting ? "yes" : "no", 1165 state->bit.distributing ? "yes" : "no", 1166 state->bit.defaulted ? "yes" : "no", 1167 state->bit.expired ? "yes" : "no"); 1168 } 1169 1170 static void 1171 dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 1172 pktsum_t *tot_stats) 1173 { 1174 pktsum_t diff_stats; 1175 pktsum_t *old_stats = &state->gs_prevstats[index]; 1176 1177 stats_diff(&diff_stats, port_stats, old_stats); 1178 1179 (void) printf("\t%-10llu", diff_stats.ipackets); 1180 (void) printf("%-12llu", diff_stats.rbytes); 1181 (void) printf("%-10llu", diff_stats.opackets); 1182 (void) printf("%-12llu", diff_stats.obytes); 1183 1184 if (tot_stats->ipackets == 0) 1185 (void) printf("\t-"); 1186 else 1187 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 1188 (double)tot_stats->ipackets * 100); 1189 1190 if (tot_stats->opackets == 0) 1191 (void) printf("\t-"); 1192 else 1193 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 1194 (double)tot_stats->opackets * 100); 1195 1196 (void) printf("\n"); 1197 1198 *old_stats = *port_stats; 1199 } 1200 1201 static int 1202 show_key(void *arg, laadm_grp_attr_sys_t *grp) 1203 { 1204 show_grp_state_t *state = (show_grp_state_t *)arg; 1205 int i; 1206 pktsum_t pktsumtot, port_stat; 1207 1208 if (state->gs_key != 0 && state->gs_key != grp->lg_key) 1209 return (0); 1210 if (state->gs_firstonly) { 1211 if (state->gs_found) 1212 return (0); 1213 } else { 1214 bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 1215 } 1216 1217 state->gs_found = B_TRUE; 1218 1219 if (state->gs_stats) { 1220 /* show statistics */ 1221 dump_grp_stats(grp); 1222 1223 /* sum the ports statistics */ 1224 bzero(&pktsumtot, sizeof (pktsumtot)); 1225 for (i = 0; i < grp->lg_nports; i++) { 1226 get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1227 stats_total(&pktsumtot, &port_stat, 1228 &state->gs_prevstats[i]); 1229 } 1230 1231 (void) printf(" Total"); 1232 (void) printf("\t%-10llu", pktsumtot.ipackets); 1233 (void) printf("%-12llu", pktsumtot.rbytes); 1234 (void) printf("%-10llu", pktsumtot.opackets); 1235 (void) printf("%-12llu\n", pktsumtot.obytes); 1236 1237 for (i = 0; i < grp->lg_nports; i++) { 1238 get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1239 (void) printf(" %s", grp->lg_ports[i].lp_devname); 1240 dump_port_stat(i, state, &port_stat, &pktsumtot); 1241 } 1242 } else if (state->gs_lacp) { 1243 /* show LACP info */ 1244 dump_grp(grp, state->gs_parseable); 1245 dump_grp_lacp(grp, state->gs_parseable); 1246 dump_ports_lacp_head(); 1247 for (i = 0; i < grp->lg_nports; i++) 1248 dump_port_lacp(&grp->lg_ports[i]); 1249 } else { 1250 dump_grp(grp, state->gs_parseable); 1251 if (!state->gs_parseable) 1252 dump_ports_head(); 1253 for (i = 0; i < grp->lg_nports; i++) { 1254 if (state->gs_parseable) 1255 (void) printf("dev key=%d", grp->lg_key); 1256 dump_port(&grp->lg_ports[i], state->gs_parseable); 1257 if (state->gs_parseable) 1258 (void) printf("\n"); 1259 } 1260 } 1261 1262 return (0); 1263 } 1264 1265 static int 1266 kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 1267 { 1268 kstat_named_t *knp; 1269 1270 if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 1271 return (-1); 1272 1273 if (knp->data_type != type) 1274 return (-1); 1275 1276 switch (type) { 1277 case KSTAT_DATA_UINT64: 1278 *(uint64_t *)buf = knp->value.ui64; 1279 break; 1280 case KSTAT_DATA_UINT32: 1281 *(uint32_t *)buf = knp->value.ui32; 1282 break; 1283 default: 1284 return (-1); 1285 } 1286 1287 return (0); 1288 } 1289 1290 static void 1291 show_dev(void *arg, const char *dev) 1292 { 1293 show_mac_state_t *state = (show_mac_state_t *)arg; 1294 1295 (void) printf("%s", dev); 1296 1297 if (!state->ms_parseable) { 1298 (void) printf(gettext("\t\tlink: %s"), 1299 mac_link_state(dev)); 1300 (void) printf(gettext("\tspeed: %-5u Mbps"), 1301 (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1302 (void) printf(gettext("\tduplex: %s\n"), 1303 mac_link_duplex(dev)); 1304 } else { 1305 (void) printf(" link=%s", mac_link_state(dev)); 1306 (void) printf(" speed=%u", 1307 (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1308 (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 1309 } 1310 } 1311 1312 /*ARGSUSED*/ 1313 static void 1314 show_dev_stats(void *arg, const char *dev) 1315 { 1316 show_mac_state_t *state = (show_mac_state_t *)arg; 1317 pktsum_t stats, diff_stats; 1318 1319 if (state->ms_firstonly) { 1320 if (state->ms_donefirst) 1321 return; 1322 state->ms_donefirst = B_TRUE; 1323 } else { 1324 bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 1325 } 1326 1327 get_mac_stats(dev, &stats); 1328 stats_diff(&diff_stats, &stats, &state->ms_prevstats); 1329 1330 (void) printf("%s", dev); 1331 (void) printf("\t\t%-10llu", diff_stats.ipackets); 1332 (void) printf("%-12llu", diff_stats.rbytes); 1333 (void) printf("%-8u", diff_stats.ierrors); 1334 (void) printf("%-10llu", diff_stats.opackets); 1335 (void) printf("%-12llu", diff_stats.obytes); 1336 (void) printf("%-8u\n", diff_stats.oerrors); 1337 1338 state->ms_prevstats = stats; 1339 } 1340 1341 static void 1342 do_show_link(int argc, char *argv[]) 1343 { 1344 char *name = NULL; 1345 int option; 1346 boolean_t s_arg = B_FALSE; 1347 boolean_t i_arg = B_FALSE; 1348 uint32_t interval = 0; 1349 show_link_state_t state; 1350 char *endp = NULL; 1351 1352 state.ls_stats = B_FALSE; 1353 state.ls_parseable = B_FALSE; 1354 1355 opterr = 0; 1356 while ((option = getopt_long(argc, argv, ":psi:", 1357 longopts, NULL)) != -1) { 1358 switch (option) { 1359 case 'p': 1360 state.ls_parseable = B_TRUE; 1361 break; 1362 case 's': 1363 if (s_arg) { 1364 (void) fprintf(stderr, gettext( 1365 "%s: the option -s cannot be specified " 1366 "more than once\n"), progname); 1367 usage(); 1368 } 1369 1370 s_arg = B_TRUE; 1371 break; 1372 case 'i': 1373 if (i_arg) { 1374 (void) fprintf(stderr, gettext( 1375 "%s: the option -i cannot be specified " 1376 "more than once\n"), progname); 1377 usage(); 1378 } 1379 1380 i_arg = B_TRUE; 1381 1382 errno = 0; 1383 interval = (int)strtol(optarg, &endp, 10); 1384 if (errno != 0 || interval == 0 || *endp != '\0') { 1385 (void) fprintf(stderr, 1386 gettext("%s: invalid interval value" 1387 " '%d'\n"), 1388 progname, interval); 1389 exit(1); 1390 } 1391 break; 1392 case ':': 1393 (void) fprintf(stderr, 1394 gettext("%s: option requires a value '-%c'\n"), 1395 progname, optopt); 1396 exit(1); 1397 /*NOTREACHED*/ 1398 case '?': 1399 default: 1400 (void) fprintf(stderr, 1401 gettext("%s: unrecognized option '-%c'\n"), 1402 progname, optopt); 1403 exit(1); 1404 } 1405 } 1406 1407 if (i_arg && !s_arg) { 1408 (void) fprintf(stderr, gettext("%s: the option -i " 1409 "can be used only with -s\n"), progname); 1410 usage(); 1411 } 1412 1413 1414 /* get link name (optional last argument) */ 1415 if (optind == (argc-1)) 1416 name = argv[optind]; 1417 else if (optind != argc) 1418 usage(); 1419 1420 if (s_arg) { 1421 link_stats(name, interval); 1422 return; 1423 } 1424 1425 if (name == NULL) { 1426 (void) dladm_walk(show_link, &state); 1427 } else { 1428 show_link(&state, name); 1429 } 1430 } 1431 1432 static void 1433 do_show_aggr(int argc, char *argv[]) 1434 { 1435 int option; 1436 uint16_t key = 0; 1437 boolean_t L_arg = B_FALSE; 1438 boolean_t s_arg = B_FALSE; 1439 boolean_t i_arg = B_FALSE; 1440 show_grp_state_t state; 1441 uint32_t interval = 0; 1442 char *endp = NULL; 1443 1444 state.gs_stats = B_FALSE; 1445 state.gs_lacp = B_FALSE; 1446 state.gs_parseable = B_FALSE; 1447 1448 opterr = 0; 1449 while ((option = getopt_long(argc, argv, ":Lpsi:", 1450 longopts, NULL)) != -1) { 1451 switch (option) { 1452 case 'L': 1453 if (L_arg) { 1454 (void) fprintf(stderr, gettext( 1455 "%s: the option -L cannot be specified " 1456 "more than once\n"), progname); 1457 usage(); 1458 } 1459 1460 if (s_arg || i_arg) { 1461 (void) fprintf(stderr, gettext( 1462 "%s: the option -L cannot be used with " 1463 "any of -is\n"), progname); 1464 usage(); 1465 } 1466 1467 L_arg = B_TRUE; 1468 1469 state.gs_lacp = B_TRUE; 1470 break; 1471 case 'p': 1472 state.gs_parseable = B_TRUE; 1473 break; 1474 case 's': 1475 if (s_arg) { 1476 (void) fprintf(stderr, gettext( 1477 "%s: the option -s cannot be specified " 1478 "more than once\n"), progname); 1479 usage(); 1480 } 1481 1482 if (L_arg) { 1483 (void) fprintf(stderr, gettext( 1484 "%s: the option -L cannot be used " 1485 "with -k\n"), progname); 1486 usage(); 1487 } 1488 1489 s_arg = B_TRUE; 1490 break; 1491 case 'i': 1492 if (i_arg) { 1493 (void) fprintf(stderr, gettext( 1494 "%s: the option -i cannot be specified " 1495 "more than once\n"), progname); 1496 usage(); 1497 } 1498 1499 if (L_arg) { 1500 (void) fprintf(stderr, gettext( 1501 "%s: the option -i cannot be used " 1502 "with -L\n"), progname); 1503 usage(); 1504 } 1505 1506 i_arg = B_TRUE; 1507 1508 errno = 0; 1509 interval = (int)strtol(optarg, &endp, 10); 1510 if (errno != 0 || interval == 0 || *endp != '\0') { 1511 (void) fprintf(stderr, 1512 gettext("%s: invalid interval value" 1513 " '%d'\n"), 1514 progname, interval); 1515 exit(1); 1516 } 1517 break; 1518 case ':': 1519 (void) fprintf(stderr, 1520 gettext("%s: option requires a value '-%c'\n"), 1521 progname, optopt); 1522 exit(1); 1523 /*NOTREACHED*/ 1524 case '?': 1525 default: 1526 (void) fprintf(stderr, 1527 gettext("%s: unrecognized option '-%c'\n"), 1528 progname, optopt); 1529 exit(1); 1530 } 1531 } 1532 1533 if (i_arg && !s_arg) { 1534 (void) fprintf(stderr, gettext("%s: the option -i " 1535 "can be used only with -s\n"), progname); 1536 usage(); 1537 } 1538 1539 /* get aggregation key (optional last argument) */ 1540 if (optind == (argc-1)) { 1541 errno = 0; 1542 key = (int)strtol(argv[optind], &endp, 10); 1543 if (errno != 0 || key < 1 || *endp != '\0') { 1544 (void) fprintf(stderr, 1545 gettext("%s: illegal key value '%d'\n"), 1546 progname, key); 1547 exit(1); 1548 } 1549 } else if (optind != argc) { 1550 usage(); 1551 } 1552 1553 if (s_arg) { 1554 aggr_stats(key, interval); 1555 return; 1556 } 1557 1558 state.gs_key = key; 1559 state.gs_found = B_FALSE; 1560 1561 (void) laadm_walk_sys(show_key, &state); 1562 1563 if (key != 0 && !state.gs_found) { 1564 (void) fprintf(stderr, 1565 gettext("%s: non-existent aggregation key '%u'\n"), 1566 progname, key); 1567 exit(1); 1568 } 1569 } 1570 1571 static void 1572 do_show_dev(int argc, char *argv[]) 1573 { 1574 int option; 1575 char *dev = NULL; 1576 boolean_t s_arg = B_FALSE; 1577 boolean_t i_arg = B_FALSE; 1578 uint32_t interval = 0; 1579 show_mac_state_t state; 1580 char *endp = NULL; 1581 1582 state.ms_parseable = B_FALSE; 1583 1584 opterr = 0; 1585 while ((option = getopt_long(argc, argv, ":psi:", 1586 longopts, NULL)) != -1) { 1587 switch (option) { 1588 case 'p': 1589 state.ms_parseable = B_TRUE; 1590 break; 1591 case 's': 1592 if (s_arg) { 1593 (void) fprintf(stderr, gettext( 1594 "%s: the option -s cannot be specified " 1595 "more than once\n"), progname); 1596 usage(); 1597 } 1598 1599 s_arg = B_TRUE; 1600 break; 1601 case 'i': 1602 if (i_arg) { 1603 (void) fprintf(stderr, gettext( 1604 "%s: the option -i cannot be specified " 1605 "more than once\n"), progname); 1606 usage(); 1607 } 1608 1609 i_arg = B_TRUE; 1610 1611 errno = 0; 1612 interval = (int)strtol(optarg, &endp, 10); 1613 if (errno != 0 || interval == 0 || *endp != '\0') { 1614 (void) fprintf(stderr, 1615 gettext("%s: invalid interval value" 1616 " '%d'\n"), 1617 progname, interval); 1618 exit(1); 1619 } 1620 break; 1621 case ':': 1622 (void) fprintf(stderr, 1623 gettext("%s: option requires a value '-%c'\n"), 1624 progname, optopt); 1625 exit(1); 1626 /*NOTREACHED*/ 1627 case '?': 1628 default: 1629 (void) fprintf(stderr, 1630 gettext("%s: unrecognized option '-%c'\n"), 1631 progname, optopt); 1632 exit(1); 1633 } 1634 } 1635 1636 if (i_arg && !s_arg) { 1637 (void) fprintf(stderr, gettext("%s: the option -i " 1638 "can be used only with -s\n"), progname); 1639 usage(); 1640 } 1641 1642 /* get dev name (optional last argument) */ 1643 if (optind == (argc-1)) 1644 dev = argv[optind]; 1645 else if (optind != argc) 1646 usage(); 1647 1648 if (dev != NULL) { 1649 int index; 1650 char drv[LIFNAMSIZ]; 1651 dladm_attr_t dlattr; 1652 boolean_t legacy; 1653 1654 /* 1655 * Check for invalid devices. 1656 * aggregations and vlans are not considered devices. 1657 */ 1658 if (strncmp(dev, "aggr", 4) == 0 || 1659 dlpi_if_parse(dev, drv, &index) < 0 || 1660 index >= 1000 || 1661 get_if_info(dev, &dlattr, &legacy) < 0) { 1662 (void) fprintf(stderr, 1663 gettext("%s: invalid device '%s'\n"), 1664 progname, dev); 1665 exit(1); 1666 } 1667 } 1668 1669 if (s_arg) { 1670 dev_stats(dev, interval); 1671 return; 1672 } 1673 1674 if (dev == NULL) 1675 (void) macadm_walk(show_dev, &state, B_TRUE); 1676 else 1677 show_dev(&state, dev); 1678 } 1679 1680 /* ARGSUSED */ 1681 static void 1682 link_stats(const char *link, uint32_t interval) 1683 { 1684 dladm_attr_t dlattr; 1685 boolean_t legacy; 1686 show_link_state_t state; 1687 1688 if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) { 1689 (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), 1690 progname, link); 1691 exit(1); 1692 } 1693 bzero(&state, sizeof (state)); 1694 1695 /* 1696 * If an interval is specified, continuously show the stats 1697 * only for the first MAC port. 1698 */ 1699 state.ls_firstonly = (interval != 0); 1700 1701 for (;;) { 1702 (void) printf("\t\tipackets rbytes ierrors "); 1703 (void) printf("opackets obytes oerrors\n"); 1704 1705 state.ls_donefirst = B_FALSE; 1706 if (link == NULL) 1707 (void) dladm_walk(show_link_stats, &state); 1708 else 1709 show_link_stats(&state, link); 1710 1711 if (interval == 0) 1712 break; 1713 1714 (void) sleep(interval); 1715 } 1716 } 1717 1718 /* ARGSUSED */ 1719 static void 1720 aggr_stats(uint16_t key, uint32_t interval) 1721 { 1722 show_grp_state_t state; 1723 1724 bzero(&state, sizeof (state)); 1725 state.gs_stats = B_TRUE; 1726 state.gs_key = key; 1727 1728 /* 1729 * If an interval is specified, continuously show the stats 1730 * only for the first group. 1731 */ 1732 state.gs_firstonly = (interval != 0); 1733 1734 for (;;) { 1735 state.gs_found = B_FALSE; 1736 (void) laadm_walk_sys(show_key, &state); 1737 if (state.gs_key != 0 && !state.gs_found) { 1738 (void) fprintf(stderr, 1739 gettext("%s: non-existent aggregation key '%u'\n"), 1740 progname, key); 1741 exit(1); 1742 } 1743 1744 if (interval == 0) 1745 break; 1746 1747 (void) sleep(interval); 1748 } 1749 } 1750 1751 /* ARGSUSED */ 1752 static void 1753 dev_stats(const char *dev, uint32_t interval) 1754 { 1755 show_mac_state_t state; 1756 1757 bzero(&state, sizeof (state)); 1758 1759 /* 1760 * If an interval is specified, continuously show the stats 1761 * only for the first MAC port. 1762 */ 1763 state.ms_firstonly = (interval != 0); 1764 1765 for (;;) { 1766 1767 (void) printf("\t\tipackets rbytes ierrors "); 1768 (void) printf("opackets obytes oerrors\n"); 1769 1770 state.ms_donefirst = B_FALSE; 1771 if (dev == NULL) 1772 (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1773 else 1774 show_dev_stats(&state, dev); 1775 1776 if (interval == 0) 1777 break; 1778 1779 (void) sleep(interval); 1780 } 1781 } 1782 1783 /* accumulate stats (s1 += (s2 - s3)) */ 1784 static void 1785 stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1786 { 1787 s1->ipackets += (s2->ipackets - s3->ipackets); 1788 s1->opackets += (s2->opackets - s3->opackets); 1789 s1->rbytes += (s2->rbytes - s3->rbytes); 1790 s1->obytes += (s2->obytes - s3->obytes); 1791 s1->ierrors += (s2->ierrors - s3->ierrors); 1792 s1->oerrors += (s2->oerrors - s3->oerrors); 1793 } 1794 1795 /* compute stats differences (s1 = s2 - s3) */ 1796 static void 1797 stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1798 { 1799 s1->ipackets = s2->ipackets - s3->ipackets; 1800 s1->opackets = s2->opackets - s3->opackets; 1801 s1->rbytes = s2->rbytes - s3->rbytes; 1802 s1->obytes = s2->obytes - s3->obytes; 1803 s1->ierrors = s2->ierrors - s3->ierrors; 1804 s1->oerrors = s2->oerrors - s3->oerrors; 1805 } 1806 1807 /* 1808 * In the following routines, we do the first kstat_lookup() assuming that 1809 * the device is gldv3-based and that the kstat name is the one passed in 1810 * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1811 * omitting the kstat name. This second lookup is needed for getting kstats 1812 * from legacy devices. This can fail too if the device is not attached or 1813 * the device is legacy and doesn't export the kstats we need. 1814 */ 1815 static void 1816 get_stats(char *module, int instance, char *name, pktsum_t *stats) 1817 { 1818 kstat_ctl_t *kcp; 1819 kstat_t *ksp; 1820 1821 if ((kcp = kstat_open()) == NULL) { 1822 (void) fprintf(stderr, 1823 gettext("%s: kstat open operation failed\n"), 1824 progname); 1825 return; 1826 } 1827 1828 if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1829 (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1830 /* 1831 * The kstat query could fail if the underlying MAC 1832 * driver was already detached. 1833 */ 1834 (void) kstat_close(kcp); 1835 return; 1836 } 1837 1838 if (kstat_read(kcp, ksp, NULL) == -1) 1839 goto bail; 1840 1841 if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 1842 &stats->ipackets) < 0) 1843 goto bail; 1844 1845 if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 1846 &stats->opackets) < 0) 1847 goto bail; 1848 1849 if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 1850 &stats->rbytes) < 0) 1851 goto bail; 1852 1853 if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 1854 &stats->obytes) < 0) 1855 goto bail; 1856 1857 if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 1858 &stats->ierrors) < 0) 1859 goto bail; 1860 1861 if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 1862 &stats->oerrors) < 0) 1863 goto bail; 1864 1865 (void) kstat_close(kcp); 1866 return; 1867 1868 bail: 1869 (void) kstat_close(kcp); 1870 } 1871 1872 static void 1873 get_mac_stats(const char *dev, pktsum_t *stats) 1874 { 1875 char module[LIFNAMSIZ]; 1876 int instance; 1877 1878 if (dlpi_if_parse(dev, module, &instance) != 0) 1879 return; 1880 bzero(stats, sizeof (*stats)); 1881 get_stats(module, instance, "mac", stats); 1882 } 1883 1884 static void 1885 get_link_stats(const char *link, pktsum_t *stats) 1886 { 1887 char module[LIFNAMSIZ]; 1888 int instance; 1889 1890 if (dlpi_if_parse(link, module, &instance) != 0) 1891 return; 1892 bzero(stats, sizeof (*stats)); 1893 get_stats(module, instance, (char *)link, stats); 1894 } 1895 1896 static int 1897 get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1898 void *val) 1899 { 1900 char module[LIFNAMSIZ]; 1901 int instance; 1902 kstat_ctl_t *kcp; 1903 kstat_t *ksp; 1904 1905 if ((kcp = kstat_open()) == NULL) { 1906 (void) fprintf(stderr, 1907 gettext("%s: kstat open operation failed\n"), 1908 progname); 1909 return (-1); 1910 } 1911 1912 if (dlpi_if_parse(dev, module, &instance) != 0) 1913 return (-1); 1914 if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1915 (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1916 /* 1917 * The kstat query could fail if the underlying MAC 1918 * driver was already detached. 1919 */ 1920 goto bail; 1921 } 1922 1923 if (kstat_read(kcp, ksp, NULL) == -1) { 1924 (void) fprintf(stderr, 1925 gettext("%s: kstat read failed\n"), 1926 progname); 1927 goto bail; 1928 } 1929 1930 if (kstat_value(ksp, name, type, val) < 0) 1931 goto bail; 1932 1933 (void) kstat_close(kcp); 1934 return (0); 1935 1936 bail: 1937 (void) kstat_close(kcp); 1938 return (-1); 1939 } 1940 1941 static uint64_t 1942 mac_ifspeed(const char *dev) 1943 { 1944 uint64_t ifspeed = 0; 1945 1946 (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 1947 return (ifspeed); 1948 } 1949 1950 static char * 1951 mac_link_state(const char *dev) 1952 { 1953 link_state_t link_state; 1954 char *state_str = "unknown"; 1955 1956 if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1957 &link_state) != 0) { 1958 return (state_str); 1959 } 1960 1961 switch (link_state) { 1962 case LINK_STATE_UP: 1963 state_str = "up"; 1964 break; 1965 case LINK_STATE_DOWN: 1966 state_str = "down"; 1967 break; 1968 default: 1969 break; 1970 } 1971 1972 return (state_str); 1973 } 1974 1975 1976 static char * 1977 mac_link_duplex(const char *dev) 1978 { 1979 link_duplex_t link_duplex; 1980 char *duplex_str = "unknown"; 1981 1982 if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1983 &link_duplex) != 0) { 1984 return (duplex_str); 1985 } 1986 1987 switch (link_duplex) { 1988 case LINK_DUPLEX_FULL: 1989 duplex_str = "full"; 1990 break; 1991 case LINK_DUPLEX_HALF: 1992 duplex_str = "half"; 1993 break; 1994 default: 1995 break; 1996 } 1997 1998 return (duplex_str); 1999 } 2000 2001 #define WIFI_CMD_SCAN 0x00000001 2002 #define WIFI_CMD_SHOW 0x00000002 2003 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 2004 typedef struct wifi_field { 2005 const char *wf_name; 2006 const char *wf_header; 2007 uint_t wf_width; 2008 uint_t wf_mask; 2009 uint_t wf_cmdtype; 2010 } wifi_field_t; 2011 2012 static wifi_field_t wifi_fields[] = { 2013 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 2014 { "essid", "ESSID", 19, WLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 2015 { "bssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 2016 { "ibssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 2017 { "mode", "MODE", 6, WLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 2018 { "speed", "SPEED", 6, WLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 2019 { "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_ALL}, 2020 { "bsstype", "BSSTYPE", 8, WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 2021 { "sec", "SEC", 6, WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 2022 { "status", "STATUS", 17, WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW}, 2023 { "strength", "STRENGTH", 10, WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 2024 ; 2025 2026 static char *all_scan_wifi_fields = 2027 "link,essid,bssid,sec,strength,mode,speed,auth,bsstype"; 2028 static char *all_show_wifi_fields = 2029 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 2030 static char *def_scan_wifi_fields = 2031 "link,essid,bssid,sec,strength,mode,speed"; 2032 static char *def_show_wifi_fields = 2033 "link,status,essid,sec,strength,mode,speed"; 2034 2035 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 2036 #define WIFI_MAX_FIELD_LEN 32 2037 2038 typedef struct { 2039 char *s_buf; 2040 char **s_fields; /* array of pointer to the fields in s_buf */ 2041 uint_t s_nfields; /* the number of fields in s_buf */ 2042 } split_t; 2043 2044 /* 2045 * Free the split_t structure pointed to by `sp'. 2046 */ 2047 static void 2048 splitfree(split_t *sp) 2049 { 2050 free(sp->s_buf); 2051 free(sp->s_fields); 2052 free(sp); 2053 } 2054 2055 /* 2056 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 2057 * length. Return a pointer to a split_t containing the split fields, or NULL 2058 * on failure. 2059 */ 2060 static split_t * 2061 split(const char *str, uint_t maxfields, uint_t maxlen) 2062 { 2063 char *field, *token, *lasts = NULL; 2064 split_t *sp; 2065 2066 if (*str == '\0' || maxfields == 0 || maxlen == 0) 2067 return (NULL); 2068 2069 sp = calloc(sizeof (split_t), 1); 2070 if (sp == NULL) 2071 return (NULL); 2072 2073 sp->s_buf = strdup(str); 2074 sp->s_fields = malloc(sizeof (char *) * maxfields); 2075 if (sp->s_buf == NULL || sp->s_fields == NULL) 2076 goto fail; 2077 2078 token = sp->s_buf; 2079 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 2080 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 2081 goto fail; 2082 token = NULL; 2083 sp->s_fields[sp->s_nfields++] = field; 2084 } 2085 return (sp); 2086 fail: 2087 splitfree(sp); 2088 return (NULL); 2089 } 2090 2091 static int 2092 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 2093 uint_t cmdtype) 2094 { 2095 uint_t i, j; 2096 wifi_field_t **wf = NULL; 2097 split_t *sp; 2098 boolean_t good_match = B_FALSE; 2099 2100 if (cmdtype == WIFI_CMD_SCAN) { 2101 if (str == NULL) 2102 str = def_scan_wifi_fields; 2103 if (strcasecmp(str, "all") == 0) 2104 str = all_scan_wifi_fields; 2105 } else if (cmdtype == WIFI_CMD_SHOW) { 2106 if (str == NULL) 2107 str = def_show_wifi_fields; 2108 if (strcasecmp(str, "all") == 0) 2109 str = all_show_wifi_fields; 2110 } else { 2111 return (-1); 2112 } 2113 2114 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 2115 if (sp == NULL) 2116 return (-1); 2117 2118 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 2119 if (wf == NULL) 2120 goto fail; 2121 2122 for (i = 0; i < sp->s_nfields; i++) { 2123 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 2124 if (strcasecmp(sp->s_fields[i], 2125 wifi_fields[j].wf_name) == 0) { 2126 good_match = wifi_fields[i]. 2127 wf_cmdtype & cmdtype; 2128 break; 2129 } 2130 } 2131 if (!good_match) 2132 goto fail; 2133 2134 good_match = B_FALSE; 2135 wf[i] = &wifi_fields[j]; 2136 } 2137 *countp = i; 2138 *fields = wf; 2139 splitfree(sp); 2140 return (0); 2141 fail: 2142 free(wf); 2143 splitfree(sp); 2144 return (-1); 2145 } 2146 2147 typedef struct print_wifi_state { 2148 const char *ws_link; 2149 boolean_t ws_parseable; 2150 boolean_t ws_header; 2151 wifi_field_t **ws_fields; 2152 uint_t ws_nfields; 2153 boolean_t ws_lastfield; 2154 uint_t ws_overflow; 2155 } print_wifi_state_t; 2156 2157 static void 2158 print_wifi_head(print_wifi_state_t *statep) 2159 { 2160 int i; 2161 wifi_field_t *wfp; 2162 2163 for (i = 0; i < statep->ws_nfields; i++) { 2164 wfp = statep->ws_fields[i]; 2165 if (i + 1 < statep->ws_nfields) 2166 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 2167 else 2168 (void) printf("%s", wfp->wf_header); 2169 } 2170 (void) printf("\n"); 2171 } 2172 2173 static void 2174 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 2175 const char *value) 2176 { 2177 uint_t width = wfp->wf_width; 2178 uint_t valwidth = strlen(value); 2179 uint_t compress; 2180 2181 if (statep->ws_parseable) { 2182 (void) printf("%s=\"%s\"", wfp->wf_header, value); 2183 } else { 2184 if (value[0] == '\0') 2185 value = "--"; 2186 if (statep->ws_lastfield) { 2187 (void) printf("%s", value); 2188 return; 2189 } 2190 2191 if (valwidth > width) { 2192 statep->ws_overflow += valwidth - width; 2193 } else if (valwidth < width && statep->ws_overflow > 0) { 2194 compress = min(statep->ws_overflow, width - valwidth); 2195 statep->ws_overflow -= compress; 2196 width -= compress; 2197 } 2198 (void) printf("%-*s", width, value); 2199 } 2200 2201 if (!statep->ws_lastfield) 2202 (void) putchar(' '); 2203 } 2204 2205 static void 2206 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 2207 wladm_wlan_attr_t *attrp) 2208 { 2209 char buf[WLADM_STRSIZE]; 2210 const char *str = ""; 2211 2212 if (wfp->wf_mask == 0) { 2213 print_wifi_field(statep, wfp, statep->ws_link); 2214 return; 2215 } 2216 2217 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 2218 print_wifi_field(statep, wfp, ""); 2219 return; 2220 } 2221 2222 switch (wfp->wf_mask) { 2223 case WLADM_WLAN_ATTR_ESSID: 2224 str = wladm_essid2str(&attrp->wa_essid, buf); 2225 break; 2226 case WLADM_WLAN_ATTR_BSSID: 2227 str = wladm_bssid2str(&attrp->wa_bssid, buf); 2228 break; 2229 case WLADM_WLAN_ATTR_SECMODE: 2230 str = wladm_secmode2str(&attrp->wa_secmode, buf); 2231 break; 2232 case WLADM_WLAN_ATTR_STRENGTH: 2233 str = wladm_strength2str(&attrp->wa_strength, buf); 2234 break; 2235 case WLADM_WLAN_ATTR_MODE: 2236 str = wladm_mode2str(&attrp->wa_mode, buf); 2237 break; 2238 case WLADM_WLAN_ATTR_SPEED: 2239 str = wladm_speed2str(&attrp->wa_speed, buf); 2240 (void) strlcat(buf, "Mb", sizeof (buf)); 2241 break; 2242 case WLADM_WLAN_ATTR_AUTH: 2243 str = wladm_auth2str(&attrp->wa_auth, buf); 2244 break; 2245 case WLADM_WLAN_ATTR_BSSTYPE: 2246 str = wladm_bsstype2str(&attrp->wa_bsstype, buf); 2247 break; 2248 } 2249 2250 print_wifi_field(statep, wfp, str); 2251 } 2252 2253 static boolean_t 2254 print_scan_results(void *arg, wladm_wlan_attr_t *attrp) 2255 { 2256 print_wifi_state_t *statep = arg; 2257 int i; 2258 2259 if (statep->ws_header) { 2260 statep->ws_header = B_FALSE; 2261 if (!statep->ws_parseable) 2262 print_wifi_head(statep); 2263 } 2264 2265 statep->ws_overflow = 0; 2266 for (i = 0; i < statep->ws_nfields; i++) { 2267 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 2268 print_wlan_attr(statep, statep->ws_fields[i], attrp); 2269 } 2270 (void) putchar('\n'); 2271 return (B_TRUE); 2272 } 2273 2274 static boolean_t 2275 scan_wifi(void *arg, const char *link) 2276 { 2277 char errmsg[WLADM_STRSIZE]; 2278 print_wifi_state_t *statep = arg; 2279 wladm_status_t status; 2280 2281 statep->ws_link = link; 2282 status = wladm_scan(link, statep, print_scan_results); 2283 if (status != WLADM_STATUS_OK) { 2284 (void) fprintf(stderr, gettext( 2285 "%s: cannot scan link '%s': %s\n"), 2286 progname, link, wladm_status2str(status, errmsg)); 2287 exit(1); 2288 } 2289 return (B_TRUE); 2290 } 2291 2292 static void 2293 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 2294 wladm_link_attr_t *attrp) 2295 { 2296 char buf[WLADM_STRSIZE]; 2297 const char *str = ""; 2298 2299 if (strcmp(wfp->wf_name, "status") == 0) { 2300 if ((wfp->wf_mask & attrp->la_valid) != 0) 2301 str = wladm_linkstatus2str(&attrp->la_status, buf); 2302 print_wifi_field(statep, wfp, str); 2303 return; 2304 } 2305 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 2306 } 2307 2308 static boolean_t 2309 show_wifi(void *arg, const char *link) 2310 { 2311 int i; 2312 char buf[WLADM_STRSIZE]; 2313 print_wifi_state_t *statep = arg; 2314 wladm_link_attr_t attr; 2315 wladm_status_t status; 2316 2317 status = wladm_get_link_attr(link, &attr); 2318 if (status != WLADM_STATUS_OK) { 2319 (void) fprintf(stderr, gettext("%s: cannot get link " 2320 "attributes for '%s': %s\n"), progname, link, 2321 wladm_status2str(status, buf)); 2322 exit(1); 2323 } 2324 2325 if (statep->ws_header) { 2326 statep->ws_header = B_FALSE; 2327 if (!statep->ws_parseable) 2328 print_wifi_head(statep); 2329 } 2330 2331 statep->ws_link = link; 2332 statep->ws_overflow = 0; 2333 for (i = 0; i < statep->ws_nfields; i++) { 2334 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 2335 print_link_attr(statep, statep->ws_fields[i], &attr); 2336 } 2337 (void) putchar('\n'); 2338 return (B_TRUE); 2339 } 2340 2341 static void 2342 do_display_wifi(int argc, char **argv, int cmd) 2343 { 2344 int option; 2345 char errmsg[WLADM_STRSIZE]; 2346 char *fields_str = NULL; 2347 wifi_field_t **fields; 2348 boolean_t (*callback)(void *, const char *); 2349 uint_t nfields; 2350 print_wifi_state_t state; 2351 wladm_status_t status; 2352 2353 if (cmd == WIFI_CMD_SCAN) 2354 callback = scan_wifi; 2355 else if (cmd == WIFI_CMD_SHOW) 2356 callback = show_wifi; 2357 else 2358 return; 2359 2360 state.ws_link = NULL; 2361 state.ws_parseable = B_FALSE; 2362 state.ws_header = B_TRUE; 2363 opterr = 0; 2364 while ((option = getopt_long(argc, argv, ":o:p", 2365 wifi_longopts, NULL)) != -1) { 2366 switch (option) { 2367 case 'o': 2368 fields_str = optarg; 2369 break; 2370 case 'p': 2371 state.ws_parseable = B_TRUE; 2372 if (fields_str == NULL) 2373 fields_str = "all"; 2374 break; 2375 case ':': 2376 (void) fprintf(stderr, 2377 gettext("%s: option requires a value '-%c'\n"), 2378 progname, optopt); 2379 exit(1); 2380 break; 2381 case '?': 2382 default: 2383 (void) fprintf(stderr, 2384 gettext("%s: unrecognized option '-%c'\n"), 2385 progname, optopt); 2386 exit(1); 2387 break; 2388 } 2389 } 2390 2391 if (optind == (argc - 1)) 2392 state.ws_link = argv[optind]; 2393 else if (optind != argc) 2394 usage(); 2395 2396 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) { 2397 (void) fprintf(stderr, 2398 gettext("%s: invalid field(s) specified\n"), 2399 progname); 2400 exit(1); 2401 } 2402 state.ws_fields = fields; 2403 state.ws_nfields = nfields; 2404 2405 if (state.ws_link == NULL) { 2406 status = wladm_walk(&state, callback); 2407 if (status != WLADM_STATUS_OK) { 2408 (void) fprintf(stderr, gettext("%s: %s\n"), 2409 progname, wladm_status2str(status, errmsg)); 2410 exit(1); 2411 } 2412 } else { 2413 (void) (*callback)(&state, state.ws_link); 2414 } 2415 free(fields); 2416 } 2417 2418 static void 2419 do_scan_wifi(int argc, char **argv) 2420 { 2421 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 2422 } 2423 2424 static void 2425 do_show_wifi(int argc, char **argv) 2426 { 2427 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 2428 } 2429 2430 typedef struct wlan_count_attr { 2431 uint_t wc_count; 2432 const char *wc_link; 2433 } wlan_count_attr_t; 2434 2435 static boolean_t 2436 do_count_wlan(void *arg, const char *link) 2437 { 2438 wlan_count_attr_t *cp = (wlan_count_attr_t *)arg; 2439 2440 if (cp->wc_count == 0) 2441 cp->wc_link = strdup(link); 2442 cp->wc_count++; 2443 return (B_TRUE); 2444 } 2445 2446 static int 2447 parse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp) 2448 { 2449 uint_t i; 2450 split_t *sp; 2451 wladm_wep_key_t *wk; 2452 2453 sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN); 2454 if (sp == NULL) 2455 return (-1); 2456 2457 wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t)); 2458 if (wk == NULL) 2459 goto fail; 2460 2461 for (i = 0; i < sp->s_nfields; i++) { 2462 char *s; 2463 dladm_secobj_class_t class; 2464 dladm_status_t status; 2465 2466 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 2467 WLADM_MAX_WEPKEYNAME_LEN); 2468 2469 wk[i].wk_idx = 1; 2470 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 2471 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 2472 goto fail; 2473 2474 wk[i].wk_idx = (uint_t)(s[1] - '0'); 2475 *s = '\0'; 2476 } 2477 wk[i].wk_len = WLADM_MAX_WEPKEY_LEN; 2478 2479 status = dladm_get_secobj(wk[i].wk_name, &class, 2480 wk[i].wk_val, &wk[i].wk_len, 0); 2481 if (status != DLADM_STATUS_OK) { 2482 if (status == DLADM_STATUS_NOTFOUND) { 2483 status = dladm_get_secobj(wk[i].wk_name, 2484 &class, wk[i].wk_val, &wk[i].wk_len, 2485 DLADM_OPT_PERSIST); 2486 } 2487 if (status != DLADM_STATUS_OK) 2488 goto fail; 2489 } 2490 } 2491 *keys = wk; 2492 *key_countp = i; 2493 splitfree(sp); 2494 return (0); 2495 fail: 2496 free(wk); 2497 splitfree(sp); 2498 return (-1); 2499 } 2500 2501 static void 2502 do_connect_wifi(int argc, char **argv) 2503 { 2504 int option; 2505 wladm_wlan_attr_t attr, *attrp; 2506 wladm_status_t status = WLADM_STATUS_OK; 2507 int timeout = WLADM_CONNECT_TIMEOUT_DEFAULT; 2508 char errmsg[WLADM_STRSIZE]; 2509 const char *link = NULL; 2510 char *endp = NULL; 2511 wladm_wep_key_t *keys = NULL; 2512 uint_t key_count = 0; 2513 uint_t flags = 0; 2514 wladm_secmode_t keysecmode = WLADM_SECMODE_NONE; 2515 2516 opterr = 0; 2517 (void) memset(&attr, 0, sizeof (attr)); 2518 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 2519 wifi_longopts, NULL)) != -1) { 2520 switch (option) { 2521 case 'e': 2522 status = wladm_str2essid(optarg, &attr.wa_essid); 2523 if (status != WLADM_STATUS_OK) { 2524 (void) fprintf(stderr, 2525 gettext("%s: invalid ESSID '%s'\n"), 2526 progname, optarg); 2527 exit(1); 2528 } 2529 attr.wa_valid |= WLADM_WLAN_ATTR_ESSID; 2530 /* 2531 * Try to connect without doing a scan. 2532 */ 2533 flags |= WLADM_OPT_NOSCAN; 2534 break; 2535 case 'i': 2536 status = wladm_str2bssid(optarg, &attr.wa_bssid); 2537 if (status != WLADM_STATUS_OK) { 2538 (void) fprintf(stderr, 2539 gettext("%s: invalid BSSID %s\n"), 2540 progname, optarg); 2541 exit(1); 2542 } 2543 attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 2544 break; 2545 case 'a': 2546 status = wladm_str2auth(optarg, &attr.wa_auth); 2547 if (status != WLADM_STATUS_OK) { 2548 (void) fprintf(stderr, 2549 gettext("%s: invalid authentication " 2550 "mode '%s'\n"), progname, optarg); 2551 exit(1); 2552 } 2553 attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 2554 break; 2555 case 'm': 2556 status = wladm_str2mode(optarg, &attr.wa_mode); 2557 if (status != WLADM_STATUS_OK) { 2558 (void) fprintf(stderr, 2559 gettext("%s: invalid mode '%s'\n"), 2560 progname, optarg); 2561 exit(1); 2562 } 2563 attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 2564 break; 2565 case 'b': 2566 status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 2567 if (status != WLADM_STATUS_OK) { 2568 (void) fprintf(stderr, 2569 gettext("%s: invalid bsstype '%s'\n"), 2570 progname, optarg); 2571 exit(1); 2572 } 2573 attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 2574 break; 2575 case 's': 2576 status = wladm_str2secmode(optarg, &attr.wa_secmode); 2577 if (status != WLADM_STATUS_OK) { 2578 (void) fprintf(stderr, 2579 gettext("%s: invalid security mode '%s'\n"), 2580 progname, optarg); 2581 exit(1); 2582 } 2583 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 2584 break; 2585 case 'k': 2586 if (parse_wep_keys(optarg, &keys, &key_count) < 0) { 2587 (void) fprintf(stderr, 2588 gettext("%s: invalid key(s) '%s'\n"), 2589 progname, optarg); 2590 exit(1); 2591 } 2592 keysecmode = WLADM_SECMODE_WEP; 2593 break; 2594 case 'T': 2595 if (strcasecmp(optarg, "forever") == 0) { 2596 timeout = -1; 2597 break; 2598 } 2599 errno = 0; 2600 timeout = (int)strtol(optarg, &endp, 10); 2601 if (timeout < 0 || errno != 0 || *endp != '\0') { 2602 (void) fprintf(stderr, 2603 gettext("%s: invalid timeout value '%s'\n"), 2604 progname, optarg); 2605 exit(1); 2606 } 2607 break; 2608 case 'c': 2609 flags |= WLADM_OPT_CREATEIBSS; 2610 break; 2611 case ':': 2612 (void) fprintf(stderr, 2613 gettext("%s: option requires a value '-%c'\n"), 2614 progname, optopt); 2615 exit(1); 2616 break; 2617 case '?': 2618 default: 2619 (void) fprintf(stderr, 2620 gettext("%s: unrecognized option '-%c'\n"), 2621 progname, optopt); 2622 exit(1); 2623 break; 2624 } 2625 } 2626 2627 if (keysecmode == WLADM_SECMODE_NONE) { 2628 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 2629 attr.wa_secmode == WLADM_SECMODE_WEP) { 2630 (void) fprintf(stderr, 2631 gettext("%s: key required for security mode " 2632 "'wep'\n"), progname); 2633 exit(1); 2634 } 2635 } else { 2636 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 2637 attr.wa_secmode != keysecmode) { 2638 (void) fprintf(stderr, 2639 gettext("%s: incompatible -s and -k options\n"), 2640 progname); 2641 exit(1); 2642 } 2643 } 2644 attr.wa_secmode = keysecmode; 2645 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 2646 2647 if (optind == (argc - 1)) 2648 link = argv[optind]; 2649 else if (optind != argc) 2650 usage(); 2651 2652 if (link == NULL) { 2653 wlan_count_attr_t wcattr; 2654 2655 wcattr.wc_link = NULL; 2656 wcattr.wc_count = 0; 2657 (void) wladm_walk(&wcattr, do_count_wlan); 2658 if (wcattr.wc_count == 0) { 2659 (void) fprintf(stderr, gettext( 2660 "%s: no wifi links are available\n"), progname); 2661 exit(1); 2662 } else if (wcattr.wc_count > 1) { 2663 (void) fprintf(stderr, gettext( 2664 "%s: link name is required when more than " 2665 "one link is available\n"), progname); 2666 exit(1); 2667 } 2668 link = wcattr.wc_link; 2669 } 2670 attrp = (attr.wa_valid == 0) ? NULL : &attr; 2671 2672 status = wladm_connect(link, attrp, timeout, keys, key_count, flags); 2673 if (status != WLADM_STATUS_OK) { 2674 if ((flags & WLADM_OPT_NOSCAN) != 0) { 2675 /* 2676 * Redo the connect. This time with scanning 2677 * and filtering. 2678 */ 2679 flags &= ~WLADM_OPT_NOSCAN; 2680 status = wladm_connect(link, attrp, timeout, keys, 2681 key_count, flags); 2682 if (status == WLADM_STATUS_OK) { 2683 free(keys); 2684 return; 2685 } 2686 } 2687 if (status == WLADM_STATUS_NOTFOUND) { 2688 if (attr.wa_valid == 0) { 2689 (void) fprintf(stderr, gettext( 2690 "%s: no wifi networks are available\n"), 2691 progname); 2692 } else { 2693 (void) fprintf(stderr, gettext("%s: no wifi " 2694 "networks with the specified criteria " 2695 "are available\n"), progname); 2696 } 2697 } else { 2698 (void) fprintf(stderr, gettext("%s: cannot connect: %s" 2699 "\n"), progname, wladm_status2str(status, errmsg)); 2700 } 2701 exit(1); 2702 } 2703 free(keys); 2704 } 2705 2706 /* ARGSUSED */ 2707 static boolean_t 2708 do_all_disconnect_wifi(void *arg, const char *link) 2709 { 2710 wladm_status_t status; 2711 char errmsg[WLADM_STRSIZE]; 2712 2713 status = wladm_disconnect(link); 2714 if (status != WLADM_STATUS_OK) { 2715 (void) fprintf(stderr, 2716 gettext("%s: cannot disconnect link '%s': %s\n"), 2717 progname, link, wladm_status2str(status, errmsg)); 2718 } 2719 return (B_TRUE); 2720 } 2721 2722 static void 2723 do_disconnect_wifi(int argc, char **argv) 2724 { 2725 int option; 2726 const char *link = NULL; 2727 char errmsg[WLADM_STRSIZE]; 2728 boolean_t all_links = B_FALSE; 2729 wladm_status_t status; 2730 wlan_count_attr_t wcattr; 2731 2732 opterr = 0; 2733 while ((option = getopt_long(argc, argv, ":a", 2734 wifi_longopts, NULL)) != -1) { 2735 switch (option) { 2736 case 'a': 2737 all_links = B_TRUE; 2738 break; 2739 case ':': 2740 (void) fprintf(stderr, 2741 gettext("%s: option requires a value '-%c'\n"), 2742 progname, optopt); 2743 exit(1); 2744 break; 2745 case '?': 2746 default: 2747 (void) fprintf(stderr, 2748 gettext("%s: unrecognized option '-%c'\n"), 2749 progname, optopt); 2750 exit(1); 2751 break; 2752 } 2753 } 2754 2755 if (optind == (argc - 1)) 2756 link = argv[optind]; 2757 else if (optind != argc) 2758 usage(); 2759 2760 if (link == NULL) { 2761 if (!all_links) { 2762 wcattr.wc_link = NULL; 2763 wcattr.wc_count = 0; 2764 (void) wladm_walk(&wcattr, do_count_wlan); 2765 if (wcattr.wc_count == 0) { 2766 (void) fprintf(stderr, gettext( 2767 "%s: no wifi links are available\n"), 2768 progname); 2769 exit(1); 2770 } else if (wcattr.wc_count > 1) { 2771 (void) fprintf(stderr, gettext( 2772 "%s: link name is required when more than " 2773 "one link is available\n"), progname); 2774 exit(1); 2775 } 2776 link = wcattr.wc_link; 2777 } else { 2778 (void) wladm_walk(&all_links, do_all_disconnect_wifi); 2779 return; 2780 } 2781 } 2782 status = wladm_disconnect(link); 2783 if (status != WLADM_STATUS_OK) { 2784 (void) fprintf(stderr, gettext("%s: cannot disconnect: %s\n"), 2785 progname, wladm_status2str(status, errmsg)); 2786 exit(1); 2787 } 2788 } 2789 2790 #define MAX_PROPS 32 2791 #define MAX_PROP_VALS 32 2792 #define MAX_PROP_LINE 512 2793 2794 typedef struct prop_info { 2795 char *pi_name; 2796 char *pi_val[MAX_PROP_VALS]; 2797 uint_t pi_count; 2798 } prop_info_t; 2799 2800 typedef struct prop_list { 2801 prop_info_t pl_info[MAX_PROPS]; 2802 uint_t pl_count; 2803 char *pl_buf; 2804 } prop_list_t; 2805 2806 typedef struct show_linkprop_state { 2807 const char *ls_link; 2808 char *ls_line; 2809 char **ls_propvals; 2810 boolean_t ls_parseable; 2811 boolean_t ls_persist; 2812 boolean_t ls_header; 2813 } show_linkprop_state_t; 2814 2815 static void 2816 free_props(prop_list_t *list) 2817 { 2818 if (list != NULL) { 2819 free(list->pl_buf); 2820 free(list); 2821 } 2822 } 2823 2824 static int 2825 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 2826 { 2827 prop_list_t *list; 2828 prop_info_t *pip; 2829 char *buf, *curr; 2830 int len, i; 2831 2832 list = malloc(sizeof (prop_list_t)); 2833 if (list == NULL) 2834 return (-1); 2835 2836 list->pl_count = 0; 2837 list->pl_buf = buf = strdup(str); 2838 if (buf == NULL) 2839 goto fail; 2840 2841 curr = buf; 2842 len = strlen(buf); 2843 pip = NULL; 2844 for (i = 0; i < len; i++) { 2845 char c = buf[i]; 2846 boolean_t match = (c == '=' || c == ','); 2847 2848 if (!match && i != len - 1) 2849 continue; 2850 2851 if (match) { 2852 buf[i] = '\0'; 2853 if (*curr == '\0') 2854 goto fail; 2855 } 2856 2857 if (pip != NULL && c != '=') { 2858 if (pip->pi_count > MAX_PROP_VALS) 2859 goto fail; 2860 2861 if (novalues) 2862 goto fail; 2863 2864 pip->pi_val[pip->pi_count] = curr; 2865 pip->pi_count++; 2866 } else { 2867 if (list->pl_count > MAX_PROPS) 2868 goto fail; 2869 2870 pip = &list->pl_info[list->pl_count]; 2871 pip->pi_name = curr; 2872 pip->pi_count = 0; 2873 list->pl_count++; 2874 if (c == ',') 2875 pip = NULL; 2876 } 2877 curr = buf + i + 1; 2878 } 2879 *listp = list; 2880 return (0); 2881 2882 fail: 2883 free_props(list); 2884 return (-1); 2885 } 2886 2887 static void 2888 print_linkprop_head(void) 2889 { 2890 (void) printf("%-15s %-14s %-14s %-30s \n", 2891 "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 2892 } 2893 2894 static void 2895 print_linkprop(show_linkprop_state_t *statep, const char *propname, 2896 dladm_prop_type_t type, const char *typename, const char *format, 2897 char **pptr) 2898 { 2899 int i; 2900 char *ptr, *lim; 2901 char buf[DLADM_STRSIZE]; 2902 char *unknown = "?", *notsup = ""; 2903 char **propvals = statep->ls_propvals; 2904 uint_t valcnt = MAX_PROP_VALS; 2905 dladm_status_t status; 2906 2907 status = dladm_get_prop(statep->ls_link, type, propname, 2908 propvals, &valcnt); 2909 if (status != DLADM_STATUS_OK) { 2910 if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) { 2911 valcnt = 1; 2912 if (type == DLADM_PROP_VAL_CURRENT) 2913 propvals = &unknown; 2914 else 2915 propvals = ¬sup; 2916 } else { 2917 (void) fprintf(stderr, gettext( 2918 "%s: cannot get link property '%s': %s\n"), 2919 progname, propname, dladm_status2str(status, buf)); 2920 exit(1); 2921 } 2922 } 2923 2924 ptr = buf; 2925 lim = buf + DLADM_STRSIZE; 2926 for (i = 0; i < valcnt; i++) { 2927 if (propvals[i][0] == '\0' && !statep->ls_parseable) 2928 ptr += snprintf(ptr, lim - ptr, "--,"); 2929 else 2930 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 2931 if (ptr >= lim) 2932 break; 2933 } 2934 if (valcnt > 0) 2935 buf[strlen(buf) - 1] = '\0'; 2936 2937 lim = statep->ls_line + MAX_PROP_LINE; 2938 if (statep->ls_parseable) { 2939 *pptr += snprintf(*pptr, lim - *pptr, 2940 "%s=\"%s\" ", typename, buf); 2941 } else { 2942 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 2943 } 2944 } 2945 2946 static boolean_t 2947 show_linkprop(void *arg, const char *propname) 2948 { 2949 show_linkprop_state_t *statep = arg; 2950 char *ptr = statep->ls_line; 2951 char *lim = ptr + MAX_PROP_LINE; 2952 2953 if (statep->ls_parseable) 2954 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 2955 else 2956 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 2957 2958 print_linkprop(statep, propname, 2959 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 2960 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 2961 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 2962 "DEFAULT", "%-14s ", &ptr); 2963 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2964 "POSSIBLE", "%-30s ", &ptr); 2965 2966 if (statep->ls_header) { 2967 statep->ls_header = B_FALSE; 2968 if (!statep->ls_parseable) 2969 print_linkprop_head(); 2970 } 2971 (void) printf("%s\n", statep->ls_line); 2972 return (B_TRUE); 2973 } 2974 2975 static void 2976 do_show_linkprop(int argc, char **argv) 2977 { 2978 int i, option, fd; 2979 char errmsg[DLADM_STRSIZE]; 2980 char linkname[MAXPATHLEN]; 2981 prop_list_t *proplist = NULL; 2982 char *buf; 2983 dladm_status_t status; 2984 show_linkprop_state_t state; 2985 2986 opterr = 0; 2987 state.ls_link = NULL; 2988 state.ls_propvals = NULL; 2989 state.ls_line = NULL; 2990 state.ls_parseable = B_FALSE; 2991 state.ls_persist = B_FALSE; 2992 state.ls_header = B_TRUE; 2993 while ((option = getopt_long(argc, argv, ":p:cP", 2994 prop_longopts, NULL)) != -1) { 2995 switch (option) { 2996 case 'p': 2997 if (parse_props(optarg, &proplist, B_TRUE) < 0) { 2998 (void) fprintf(stderr, 2999 gettext("%s: invalid field(s) specified\n"), 3000 progname); 3001 exit(1); 3002 } 3003 break; 3004 case 'c': 3005 state.ls_parseable = B_TRUE; 3006 break; 3007 case 'P': 3008 state.ls_persist = B_TRUE; 3009 break; 3010 case ':': 3011 (void) fprintf(stderr, 3012 gettext("%s: option requires a value '-%c'\n"), 3013 progname, optopt); 3014 exit(1); 3015 break; 3016 case '?': 3017 default: 3018 (void) fprintf(stderr, 3019 gettext("%s: unrecognized option '-%c'\n"), 3020 progname, optopt); 3021 exit(1); 3022 break; 3023 } 3024 } 3025 3026 if (optind == (argc - 1)) 3027 state.ls_link = argv[optind]; 3028 else if (optind != argc) 3029 usage(); 3030 3031 if (state.ls_link == NULL) { 3032 (void) fprintf(stderr, 3033 gettext("%s: link name must be specified\n"), progname); 3034 exit(1); 3035 } 3036 3037 /* 3038 * When some WiFi links are opened for the first time, their hardware 3039 * automatically scans for APs and does other slow operations. Thus, 3040 * if there are no open links, the retrieval of link properties 3041 * (below) will proceed slowly unless we hold the link open. 3042 */ 3043 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", state.ls_link); 3044 if ((fd = open(linkname, O_RDWR)) < 0) { 3045 (void) fprintf(stderr, 3046 gettext("%s: cannot open %s\n"), progname, state.ls_link); 3047 exit(1); 3048 } 3049 3050 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 3051 MAX_PROP_LINE); 3052 if (buf == NULL) { 3053 (void) fprintf(stderr, 3054 gettext("%s: insufficient memory\n"), progname); 3055 exit(1); 3056 } 3057 state.ls_propvals = (char **)(void *)buf; 3058 for (i = 0; i < MAX_PROP_VALS; i++) { 3059 state.ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 3060 i * DLADM_PROP_VAL_MAX; 3061 } 3062 state.ls_line = buf + 3063 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 3064 3065 if (proplist != NULL) { 3066 for (i = 0; i < proplist->pl_count; i++) { 3067 if (!show_linkprop(&state, 3068 proplist->pl_info[i].pi_name)) 3069 break; 3070 } 3071 } else { 3072 status = dladm_walk_prop(state.ls_link, &state, show_linkprop); 3073 if (status != DLADM_STATUS_OK) { 3074 (void) fprintf(stderr, 3075 gettext("%s: show-linkprop: %s\n"), progname, 3076 dladm_status2str(status, errmsg)); 3077 exit(1); 3078 } 3079 } 3080 (void) close(fd); 3081 free(buf); 3082 free_props(proplist); 3083 } 3084 3085 static dladm_status_t 3086 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 3087 uint_t val_cnt, boolean_t reset) 3088 { 3089 dladm_status_t status; 3090 char errmsg[DLADM_STRSIZE]; 3091 3092 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 3093 DLADM_OPT_PERSIST); 3094 3095 if (status != DLADM_STATUS_OK) { 3096 if (reset) { 3097 (void) fprintf(stderr, gettext("%s: warning: cannot " 3098 "persistently reset link property '%s' on '%s': " 3099 "%s\n"), progname, prop_name, link, 3100 dladm_status2str(status, errmsg)); 3101 } else { 3102 (void) fprintf(stderr, gettext("%s: warning: cannot " 3103 "persistently set link property '%s' on '%s': " 3104 "%s\n"), progname, prop_name, link, 3105 dladm_status2str(status, errmsg)); 3106 } 3107 } 3108 return (status); 3109 } 3110 3111 static void 3112 set_linkprop(int argc, char **argv, boolean_t reset) 3113 { 3114 int i, option; 3115 char errmsg[DLADM_STRSIZE]; 3116 const char *link = NULL; 3117 prop_list_t *proplist = NULL; 3118 boolean_t temp = B_FALSE; 3119 dladm_status_t status = DLADM_STATUS_OK; 3120 3121 opterr = 0; 3122 while ((option = getopt_long(argc, argv, ":p:R:t", 3123 prop_longopts, NULL)) != -1) { 3124 switch (option) { 3125 case 'p': 3126 if (parse_props(optarg, &proplist, reset) < 0) { 3127 (void) fprintf(stderr, gettext( 3128 "%s: invalid link properties specified\n"), 3129 progname); 3130 exit(1); 3131 } 3132 break; 3133 case 't': 3134 temp = B_TRUE; 3135 break; 3136 case 'R': 3137 status = dladm_set_rootdir(optarg); 3138 if (status != DLADM_STATUS_OK) { 3139 (void) fprintf(stderr, gettext( 3140 "%s: invalid directory specified: %s\n"), 3141 progname, dladm_status2str(status, errmsg)); 3142 exit(1); 3143 } 3144 break; 3145 case ':': 3146 (void) fprintf(stderr, 3147 gettext("%s: option requires a value '-%c'\n"), 3148 progname, optopt); 3149 exit(1); 3150 break; 3151 case '?': 3152 default: 3153 (void) fprintf(stderr, 3154 gettext("%s: unrecognized option '-%c'\n"), 3155 progname, optopt); 3156 exit(1); 3157 break; 3158 } 3159 } 3160 3161 if (optind == (argc - 1)) 3162 link = argv[optind]; 3163 else if (optind != argc) 3164 usage(); 3165 3166 if (link == NULL) { 3167 (void) fprintf(stderr, 3168 gettext("%s: link name must be specified\n"), 3169 progname); 3170 exit(1); 3171 } 3172 3173 if (proplist == NULL) { 3174 if (!reset) { 3175 (void) fprintf(stderr, 3176 gettext("%s: link property must be specified\n"), 3177 progname); 3178 exit(1); 3179 } 3180 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP); 3181 if (status != DLADM_STATUS_OK) { 3182 (void) fprintf(stderr, gettext( 3183 "%s: warning: cannot reset link " 3184 "properties on '%s': %s\n"), 3185 progname, link, dladm_status2str(status, errmsg)); 3186 } 3187 if (!temp) { 3188 status = set_linkprop_persist(link, NULL, NULL, 0, 3189 reset); 3190 } 3191 goto done; 3192 } 3193 3194 for (i = 0; i < proplist->pl_count; i++) { 3195 prop_info_t *pip = &proplist->pl_info[i]; 3196 char **val; 3197 uint_t count; 3198 dladm_status_t s; 3199 3200 if (reset) { 3201 val = NULL; 3202 count = 0; 3203 } else { 3204 val = pip->pi_val; 3205 count = pip->pi_count; 3206 if (count == 0) { 3207 (void) fprintf(stderr, gettext( 3208 "%s: value(s) for '%s' not specified\n"), 3209 progname, pip->pi_name); 3210 status = DLADM_STATUS_BADARG; 3211 continue; 3212 } 3213 } 3214 s = dladm_set_prop(link, pip->pi_name, val, count, 3215 DLADM_OPT_TEMP); 3216 if (s == DLADM_STATUS_OK) { 3217 if (!temp) { 3218 s = set_linkprop_persist(link, 3219 pip->pi_name, val, count, reset); 3220 if (s != DLADM_STATUS_OK) 3221 status = s; 3222 } 3223 continue; 3224 } 3225 status = s; 3226 switch (s) { 3227 case DLADM_STATUS_NOTFOUND: 3228 (void) fprintf(stderr, 3229 gettext("%s: invalid link property '%s'\n"), 3230 progname, pip->pi_name); 3231 break; 3232 case DLADM_STATUS_BADVAL: { 3233 int j; 3234 char *ptr, *lim; 3235 char **propvals = NULL; 3236 uint_t valcnt = MAX_PROP_VALS; 3237 3238 ptr = malloc((sizeof (char *) + 3239 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 3240 MAX_PROP_LINE); 3241 3242 propvals = (char **)(void *)ptr; 3243 if (propvals == NULL) { 3244 (void) fprintf(stderr, gettext( 3245 "%s: insufficient memory\n"), progname); 3246 exit(1); 3247 } 3248 for (j = 0; j < MAX_PROP_VALS; j++) { 3249 propvals[j] = ptr + sizeof (char *) * 3250 MAX_PROP_VALS + 3251 j * DLADM_PROP_VAL_MAX; 3252 } 3253 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 3254 pip->pi_name, propvals, &valcnt); 3255 3256 ptr = errmsg; 3257 lim = ptr + DLADM_STRSIZE; 3258 *ptr = '\0'; 3259 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 3260 ptr += snprintf(ptr, lim - ptr, "%s,", 3261 propvals[j]); 3262 if (ptr >= lim) 3263 break; 3264 } 3265 if (ptr > errmsg) 3266 *(ptr - 1) = '\0'; 3267 (void) fprintf(stderr, gettext( 3268 "%s: link property '%s' must be one of: %s\n"), 3269 progname, pip->pi_name, errmsg); 3270 free(propvals); 3271 break; 3272 } 3273 default: 3274 if (reset) { 3275 (void) fprintf(stderr, gettext( 3276 "%s: cannot reset link property '%s' on " 3277 "'%s': %s\n"), progname, pip->pi_name, link, 3278 dladm_status2str(s, errmsg)); 3279 } else { 3280 (void) fprintf(stderr, gettext( 3281 "%s: cannot set link property '%s' on " 3282 "'%s': %s\n"), progname, pip->pi_name, link, 3283 dladm_status2str(s, errmsg)); 3284 } 3285 break; 3286 } 3287 } 3288 done: 3289 free_props(proplist); 3290 if (status != DLADM_STATUS_OK) 3291 exit(1); 3292 } 3293 3294 static void 3295 do_set_linkprop(int argc, char **argv) 3296 { 3297 set_linkprop(argc, argv, B_FALSE); 3298 } 3299 3300 static void 3301 do_reset_linkprop(int argc, char **argv) 3302 { 3303 set_linkprop(argc, argv, B_TRUE); 3304 } 3305 3306 static int 3307 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 3308 dladm_secobj_class_t class) 3309 { 3310 int error = 0; 3311 3312 if (class != DLADM_SECOBJ_CLASS_WEP) 3313 return (ENOENT); 3314 3315 switch (len) { 3316 case 5: /* ASCII key sizes */ 3317 case 13: 3318 (void) memcpy(obj_val, buf, len); 3319 *obj_lenp = len; 3320 break; 3321 case 10: /* Hex key sizes, not preceded by 0x */ 3322 case 26: 3323 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 3324 break; 3325 case 12: /* Hex key sizes, preceded by 0x */ 3326 case 28: 3327 if (strncmp(buf, "0x", 2) != 0) 3328 return (EINVAL); 3329 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 3330 break; 3331 default: 3332 return (EINVAL); 3333 } 3334 return (error); 3335 } 3336 3337 /* ARGSUSED */ 3338 static void 3339 defersig(int sig) 3340 { 3341 signalled = sig; 3342 } 3343 3344 static int 3345 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 3346 { 3347 uint_t len = 0; 3348 int c; 3349 struct termios stored, current; 3350 void (*sigfunc)(int); 3351 3352 /* 3353 * Turn off echo -- but before we do so, defer SIGINT handling 3354 * so that a ^C doesn't leave the terminal corrupted. 3355 */ 3356 sigfunc = signal(SIGINT, defersig); 3357 (void) fflush(stdin); 3358 (void) tcgetattr(0, &stored); 3359 current = stored; 3360 current.c_lflag &= ~(ICANON|ECHO); 3361 current.c_cc[VTIME] = 0; 3362 current.c_cc[VMIN] = 1; 3363 (void) tcsetattr(0, TCSANOW, ¤t); 3364 again: 3365 if (try == 1) 3366 (void) printf(gettext("provide value for '%s': "), objname); 3367 else 3368 (void) printf(gettext("confirm value for '%s': "), objname); 3369 3370 (void) fflush(stdout); 3371 while (signalled == 0) { 3372 c = getchar(); 3373 if (c == '\n' || c == '\r') { 3374 if (len != 0) 3375 break; 3376 (void) putchar('\n'); 3377 goto again; 3378 } 3379 3380 buf[len++] = c; 3381 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 3382 break; 3383 (void) putchar('*'); 3384 } 3385 3386 (void) putchar('\n'); 3387 (void) fflush(stdin); 3388 3389 /* 3390 * Restore terminal setting and handle deferred signals. 3391 */ 3392 (void) tcsetattr(0, TCSANOW, &stored); 3393 3394 (void) signal(SIGINT, sigfunc); 3395 if (signalled != 0) 3396 (void) kill(getpid(), signalled); 3397 3398 return (len); 3399 } 3400 3401 static int 3402 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 3403 dladm_secobj_class_t class, FILE *filep) 3404 { 3405 int rval; 3406 uint_t len, len2; 3407 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 3408 3409 if (filep == NULL) { 3410 len = get_secobj_from_tty(1, obj_name, buf); 3411 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 3412 if (rval == 0) { 3413 len2 = get_secobj_from_tty(2, obj_name, buf2); 3414 if (len != len2 || memcmp(buf, buf2, len) != 0) 3415 rval = ENOTSUP; 3416 } 3417 return (rval); 3418 } else { 3419 for (;;) { 3420 if (fgets(buf, sizeof (buf), filep) == NULL) 3421 break; 3422 if (isspace(buf[0])) 3423 continue; 3424 3425 len = strlen(buf); 3426 if (buf[len - 1] == '\n') { 3427 buf[len - 1] = '\0'; 3428 len--; 3429 } 3430 break; 3431 } 3432 (void) fclose(filep); 3433 } 3434 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 3435 } 3436 3437 static boolean_t 3438 check_auth(const char *auth) 3439 { 3440 struct passwd *pw; 3441 3442 if ((pw = getpwuid(getuid())) == NULL) 3443 return (B_FALSE); 3444 3445 return (chkauthattr(auth, pw->pw_name) != 0); 3446 } 3447 3448 static void 3449 audit_secobj(char *auth, char *class, char *obj, 3450 boolean_t success, boolean_t create) 3451 { 3452 adt_session_data_t *ah; 3453 adt_event_data_t *event; 3454 au_event_t flag; 3455 char *errstr; 3456 3457 if (create) { 3458 flag = ADT_dladm_create_secobj; 3459 errstr = "ADT_dladm_create_secobj"; 3460 } else { 3461 flag = ADT_dladm_delete_secobj; 3462 errstr = "ADT_dladm_delete_secobj"; 3463 } 3464 3465 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { 3466 (void) fprintf(stderr, "%s: adt_start_session: %s\n", 3467 progname, strerror(errno)); 3468 exit(1); 3469 } 3470 3471 if ((event = adt_alloc_event(ah, flag)) == NULL) { 3472 (void) fprintf(stderr, "%s: adt_alloc_event" 3473 "(%s): %s\n", progname, errstr, 3474 strerror(errno)); 3475 exit(1); 3476 } 3477 3478 /* fill in audit info */ 3479 if (create) { 3480 event->adt_dladm_create_secobj.auth_used = auth; 3481 event->adt_dladm_create_secobj.obj_class = class; 3482 event->adt_dladm_create_secobj.obj_name = obj; 3483 } else { 3484 event->adt_dladm_delete_secobj.auth_used = auth; 3485 event->adt_dladm_delete_secobj.obj_class = class; 3486 event->adt_dladm_delete_secobj.obj_name = obj; 3487 } 3488 3489 if (success) { 3490 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 3491 (void) fprintf(stderr, "%s: adt_put_event" 3492 "(%s, success): %s\n", 3493 progname, errstr, strerror(errno)); 3494 exit(1); 3495 } 3496 } else { 3497 if (adt_put_event(event, ADT_FAILURE, 3498 ADT_FAIL_VALUE_AUTH) != 0) { 3499 (void) fprintf(stderr, "%s: adt_put_event" 3500 "(%s, failure): %s\n", 3501 progname, errstr, strerror(errno)); 3502 exit(1); 3503 } 3504 } 3505 3506 adt_free_event(event); 3507 (void) adt_end_session(ah); 3508 } 3509 3510 #define MAX_SECOBJS 32 3511 #define MAX_SECOBJ_NAMELEN 32 3512 static void 3513 do_create_secobj(int argc, char **argv) 3514 { 3515 int option, rval; 3516 char errmsg[DLADM_STRSIZE]; 3517 FILE *filep = NULL; 3518 char *obj_name = NULL; 3519 char *class_name = NULL; 3520 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3521 uint_t obj_len; 3522 boolean_t success, temp = B_FALSE; 3523 dladm_status_t status; 3524 dladm_secobj_class_t class = -1; 3525 uid_t euid; 3526 3527 opterr = 0; 3528 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 3529 while ((option = getopt_long(argc, argv, ":f:c:R:t", 3530 wifi_longopts, NULL)) != -1) { 3531 switch (option) { 3532 case 'f': 3533 euid = geteuid(); 3534 (void) seteuid(getuid()); 3535 filep = fopen(optarg, "r"); 3536 if (filep == NULL) { 3537 (void) fprintf(stderr, 3538 gettext("%s: cannot open %s: %s\n"), 3539 progname, optarg, strerror(errno)); 3540 exit(1); 3541 } 3542 (void) seteuid(euid); 3543 break; 3544 case 'c': 3545 class_name = optarg; 3546 status = dladm_str2secobjclass(optarg, &class); 3547 if (status != DLADM_STATUS_OK) { 3548 (void) fprintf(stderr, gettext( 3549 "%s: invalid secure object class '%s', " 3550 "valid values are: wep\n"), 3551 progname, optarg); 3552 exit(1); 3553 } 3554 break; 3555 case 't': 3556 temp = B_TRUE; 3557 break; 3558 case 'R': 3559 status = dladm_set_rootdir(optarg); 3560 if (status != DLADM_STATUS_OK) { 3561 (void) fprintf(stderr, gettext( 3562 "%s: invalid directory specified: %s\n"), 3563 progname, dladm_status2str(status, errmsg)); 3564 exit(1); 3565 } 3566 break; 3567 case ':': 3568 (void) fprintf(stderr, 3569 gettext("%s: option requires a value '-%c'\n"), 3570 progname, optopt); 3571 exit(1); 3572 break; 3573 case '?': 3574 default: 3575 (void) fprintf(stderr, 3576 gettext("%s: unrecognized option '-%c'\n"), 3577 progname, optopt); 3578 exit(1); 3579 break; 3580 } 3581 } 3582 3583 if (optind == (argc - 1)) 3584 obj_name = argv[optind]; 3585 else if (optind != argc) 3586 usage(); 3587 3588 if (class == -1) { 3589 (void) fprintf(stderr, 3590 gettext("%s: secure object class required\n"), 3591 progname); 3592 exit(1); 3593 } 3594 3595 if (obj_name == NULL) { 3596 (void) fprintf(stderr, 3597 gettext("%s: secure object name required\n"), 3598 progname); 3599 exit(1); 3600 } 3601 3602 success = check_auth(LINK_SEC_AUTH); 3603 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 3604 if (!success) { 3605 (void) fprintf(stderr, 3606 gettext("%s: authorization '%s' is required\n"), 3607 progname, LINK_SEC_AUTH); 3608 exit(1); 3609 } 3610 3611 if ((rval = get_secobj_val(obj_name, obj_val, &obj_len, 3612 class, filep)) != 0) { 3613 switch (rval) { 3614 case ENOENT: 3615 (void) fprintf(stderr, 3616 gettext("%s: invalid secure object class\n"), 3617 progname); 3618 break; 3619 case EINVAL: 3620 (void) fprintf(stderr, 3621 gettext("%s: invalid secure object value\n"), 3622 progname); 3623 break; 3624 case ENOTSUP: 3625 (void) fprintf(stderr, gettext( 3626 "%s: verification failed\n"), progname); 3627 break; 3628 default: 3629 (void) fprintf(stderr, gettext( 3630 "%s: invalid secure object: %s\n"), 3631 progname, strerror(rval)); 3632 break; 3633 } 3634 exit(1); 3635 } 3636 3637 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3638 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 3639 if (status != DLADM_STATUS_OK) { 3640 (void) fprintf(stderr, 3641 gettext("%s: could not create secure object '%s': %s\n"), 3642 progname, obj_name, dladm_status2str(status, errmsg)); 3643 exit(1); 3644 } 3645 if (temp) 3646 return; 3647 3648 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3649 DLADM_OPT_PERSIST); 3650 if (status != DLADM_STATUS_OK) { 3651 (void) fprintf(stderr, 3652 gettext("%s: warning: could not persistently create " 3653 "secure object '%s': %s\n"), progname, obj_name, 3654 dladm_status2str(status, errmsg)); 3655 exit(1); 3656 } 3657 } 3658 3659 static void 3660 do_delete_secobj(int argc, char **argv) 3661 { 3662 int i, option; 3663 char errmsg[DLADM_STRSIZE]; 3664 boolean_t temp = B_FALSE; 3665 split_t *sp = NULL; 3666 boolean_t success; 3667 dladm_status_t status, pstatus; 3668 3669 opterr = 0; 3670 status = pstatus = DLADM_STATUS_OK; 3671 while ((option = getopt_long(argc, argv, "R:t", 3672 wifi_longopts, NULL)) != -1) { 3673 switch (option) { 3674 case 't': 3675 temp = B_TRUE; 3676 break; 3677 case 'R': 3678 status = dladm_set_rootdir(optarg); 3679 if (status != DLADM_STATUS_OK) { 3680 (void) fprintf(stderr, gettext( 3681 "%s: invalid directory specified: %s\n"), 3682 progname, dladm_status2str(status, errmsg)); 3683 exit(1); 3684 } 3685 break; 3686 case ':': 3687 (void) fprintf(stderr, 3688 gettext("%s: option requires a value '-%c'\n"), 3689 progname, optopt); 3690 exit(1); 3691 break; 3692 case '?': 3693 default: 3694 (void) fprintf(stderr, 3695 gettext("%s: unrecognized option '-%c'\n"), 3696 progname, optopt); 3697 exit(1); 3698 break; 3699 } 3700 } 3701 3702 if (optind == (argc - 1)) { 3703 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3704 if (sp == NULL) { 3705 (void) fprintf(stderr, gettext( 3706 "%s: invalid secure object name(s): '%s'\n"), 3707 progname, argv[optind]); 3708 exit(1); 3709 } 3710 } else if (optind != argc) 3711 usage(); 3712 3713 if (sp == NULL || sp->s_nfields < 1) { 3714 (void) fprintf(stderr, 3715 gettext("%s: secure object name required\n"), 3716 progname); 3717 exit(1); 3718 } 3719 3720 success = check_auth(LINK_SEC_AUTH); 3721 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 3722 if (!success) { 3723 (void) fprintf(stderr, 3724 gettext("%s: authorization '%s' is required\n"), 3725 progname, LINK_SEC_AUTH); 3726 exit(1); 3727 } 3728 3729 for (i = 0; i < sp->s_nfields; i++) { 3730 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 3731 if (!temp) { 3732 pstatus = dladm_unset_secobj(sp->s_fields[i], 3733 DLADM_OPT_PERSIST); 3734 } else { 3735 pstatus = DLADM_STATUS_OK; 3736 } 3737 3738 if (status != DLADM_STATUS_OK) { 3739 (void) fprintf(stderr, gettext( 3740 "%s: could not delete secure object '%s': %s\n"), 3741 progname, sp->s_fields[i], 3742 dladm_status2str(status, errmsg)); 3743 } 3744 if (pstatus != DLADM_STATUS_OK) { 3745 (void) fprintf(stderr, gettext("%s: warning: could not " 3746 "persistently delete secure object '%s': %s\n"), 3747 progname, sp->s_fields[i], 3748 dladm_status2str(pstatus, errmsg)); 3749 } 3750 } 3751 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 3752 exit(1); 3753 } 3754 3755 typedef struct show_secobj_state { 3756 boolean_t ss_persist; 3757 boolean_t ss_parseable; 3758 boolean_t ss_debug; 3759 boolean_t ss_header; 3760 } show_secobj_state_t; 3761 3762 static void 3763 print_secobj_head(show_secobj_state_t *statep) 3764 { 3765 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 3766 if (statep->ss_debug) 3767 (void) printf("%-30s", "VALUE"); 3768 (void) putchar('\n'); 3769 } 3770 3771 static boolean_t 3772 show_secobj(void *arg, const char *obj_name) 3773 { 3774 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 3775 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3776 char buf[DLADM_STRSIZE]; 3777 uint_t flags = 0; 3778 dladm_secobj_class_t class; 3779 show_secobj_state_t *statep = arg; 3780 dladm_status_t status; 3781 3782 if (statep->ss_persist) 3783 flags |= DLADM_OPT_PERSIST; 3784 3785 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 3786 if (status != DLADM_STATUS_OK) { 3787 (void) fprintf(stderr, gettext( 3788 "%s: cannot get secure object '%s': %s\n"), progname, 3789 obj_name, dladm_status2str(status, buf)); 3790 exit(1); 3791 } 3792 3793 if (statep->ss_header) { 3794 statep->ss_header = B_FALSE; 3795 if (!statep->ss_parseable) 3796 print_secobj_head(statep); 3797 } 3798 3799 if (statep->ss_parseable) { 3800 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 3801 dladm_secobjclass2str(class, buf)); 3802 } else { 3803 (void) printf("%-20s %-20s ", obj_name, 3804 dladm_secobjclass2str(class, buf)); 3805 } 3806 3807 if (statep->ss_debug) { 3808 char val[DLADM_SECOBJ_VAL_MAX * 2]; 3809 uint_t len = sizeof (val); 3810 3811 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 3812 if (statep->ss_parseable) 3813 (void) printf("VALUE=\"0x%s\"", val); 3814 else 3815 (void) printf("0x%-30s", val); 3816 } 3817 } 3818 (void) putchar('\n'); 3819 return (B_TRUE); 3820 } 3821 3822 static void 3823 do_show_secobj(int argc, char **argv) 3824 { 3825 int option; 3826 show_secobj_state_t state; 3827 dladm_status_t status; 3828 uint_t i; 3829 char errmsg[DLADM_STRSIZE]; 3830 split_t *sp; 3831 uint_t flags; 3832 3833 opterr = 0; 3834 state.ss_persist = B_FALSE; 3835 state.ss_parseable = B_FALSE; 3836 state.ss_debug = B_FALSE; 3837 state.ss_header = B_TRUE; 3838 while ((option = getopt_long(argc, argv, ":pPd", 3839 wifi_longopts, NULL)) != -1) { 3840 switch (option) { 3841 case 'p': 3842 state.ss_parseable = B_TRUE; 3843 break; 3844 case 'P': 3845 state.ss_persist = B_TRUE; 3846 break; 3847 case 'd': 3848 if (getuid() != 0) { 3849 (void) fprintf(stderr, 3850 gettext("%s: insufficient privileges\n"), 3851 progname); 3852 exit(1); 3853 } 3854 state.ss_debug = B_TRUE; 3855 break; 3856 case ':': 3857 (void) fprintf(stderr, 3858 gettext("%s: option requires a value '-%c'\n"), 3859 progname, optopt); 3860 exit(1); 3861 break; 3862 case '?': 3863 default: 3864 (void) fprintf(stderr, 3865 gettext("%s: unrecognized option '-%c'\n"), 3866 progname, optopt); 3867 exit(1); 3868 break; 3869 } 3870 } 3871 3872 if (optind == (argc - 1)) { 3873 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3874 if (sp == NULL) { 3875 (void) fprintf(stderr, gettext( 3876 "%s: invalid secure object name(s): '%s'\n"), 3877 progname, argv[optind]); 3878 exit(1); 3879 } 3880 for (i = 0; i < sp->s_nfields; i++) { 3881 if (!show_secobj(&state, sp->s_fields[i])) 3882 break; 3883 } 3884 splitfree(sp); 3885 return; 3886 } else if (optind != argc) 3887 usage(); 3888 3889 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 3890 status = dladm_walk_secobj(&state, show_secobj, flags); 3891 if (status != DLADM_STATUS_OK) { 3892 (void) fprintf(stderr, gettext("%s: show-secobj: %s\n"), 3893 progname, dladm_status2str(status, errmsg)); 3894 exit(1); 3895 } 3896 } 3897 3898 /* ARGSUSED */ 3899 static void 3900 do_init_linkprop(int argc, char **argv) 3901 { 3902 char errmsg[DLADM_STRSIZE]; 3903 dladm_status_t status; 3904 3905 status = dladm_init_linkprop(); 3906 if (status != DLADM_STATUS_OK) { 3907 (void) fprintf(stderr, 3908 gettext("%s: link property initialization failed: %s\n"), 3909 progname, dladm_status2str(status, errmsg)); 3910 exit(1); 3911 } 3912 } 3913 3914 /* ARGSUSED */ 3915 static void 3916 do_init_secobj(int argc, char **argv) 3917 { 3918 char errmsg[DLADM_STRSIZE]; 3919 dladm_status_t status; 3920 3921 status = dladm_init_secobj(); 3922 if (status != DLADM_STATUS_OK) { 3923 (void) fprintf(stderr, 3924 gettext("%s: secure object initialization failed: %s\n"), 3925 progname, dladm_status2str(status, errmsg)); 3926 exit(1); 3927 } 3928 } 3929