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