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]\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_wep_keys(char *str, dladm_wlan_wepkey_t **keys, uint_t *key_countp) 2028 { 2029 uint_t i; 2030 split_t *sp; 2031 dladm_wlan_wepkey_t *wk; 2032 2033 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_WEPKEYNAME_LEN); 2034 if (sp == NULL) 2035 return (-1); 2036 2037 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_wepkey_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_WEPKEYNAME_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_WEPKEY_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 } 2071 *keys = wk; 2072 *key_countp = i; 2073 splitfree(sp); 2074 return (0); 2075 fail: 2076 free(wk); 2077 splitfree(sp); 2078 return (-1); 2079 } 2080 2081 static void 2082 do_connect_wifi(int argc, char **argv) 2083 { 2084 int option; 2085 dladm_wlan_attr_t attr, *attrp; 2086 dladm_status_t status = DLADM_STATUS_OK; 2087 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 2088 const char *link = NULL; 2089 dladm_wlan_wepkey_t *keys = NULL; 2090 uint_t key_count = 0; 2091 uint_t flags = 0; 2092 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 2093 2094 opterr = 0; 2095 (void) memset(&attr, 0, sizeof (attr)); 2096 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 2097 wifi_longopts, NULL)) != -1) { 2098 switch (option) { 2099 case 'e': 2100 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 2101 if (status != DLADM_STATUS_OK) 2102 die("invalid ESSID '%s'", optarg); 2103 2104 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 2105 /* 2106 * Try to connect without doing a scan. 2107 */ 2108 flags |= DLADM_WLAN_CONNECT_NOSCAN; 2109 break; 2110 case 'i': 2111 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 2112 if (status != DLADM_STATUS_OK) 2113 die("invalid BSSID %s", optarg); 2114 2115 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 2116 break; 2117 case 'a': 2118 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 2119 if (status != DLADM_STATUS_OK) 2120 die("invalid authentication mode '%s'", optarg); 2121 2122 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 2123 break; 2124 case 'm': 2125 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 2126 if (status != DLADM_STATUS_OK) 2127 die("invalid mode '%s'", optarg); 2128 2129 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 2130 break; 2131 case 'b': 2132 if ((status = dladm_wlan_str2bsstype(optarg, 2133 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 2134 die("invalid bsstype '%s'", optarg); 2135 } 2136 2137 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 2138 break; 2139 case 's': 2140 if ((status = dladm_wlan_str2secmode(optarg, 2141 &attr.wa_secmode)) != DLADM_STATUS_OK) { 2142 die("invalid security mode '%s'", optarg); 2143 } 2144 2145 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 2146 break; 2147 case 'k': 2148 if (parse_wep_keys(optarg, &keys, &key_count) < 0) 2149 die("invalid key(s) '%s'", optarg); 2150 2151 keysecmode = DLADM_WLAN_SECMODE_WEP; 2152 break; 2153 case 'T': 2154 if (strcasecmp(optarg, "forever") == 0) { 2155 timeout = -1; 2156 break; 2157 } 2158 if (!str2int(optarg, &timeout) || timeout < 0) 2159 die("invalid timeout value '%s'", optarg); 2160 break; 2161 case 'c': 2162 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 2163 break; 2164 default: 2165 die_opterr(optopt, option); 2166 break; 2167 } 2168 } 2169 2170 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 2171 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 2172 attr.wa_secmode == DLADM_WLAN_SECMODE_WEP) 2173 die("key required for security mode 'wep'"); 2174 } else { 2175 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 2176 attr.wa_secmode != keysecmode) 2177 die("incompatible -s and -k options"); 2178 } 2179 attr.wa_secmode = keysecmode; 2180 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 2181 2182 if (optind == (argc - 1)) 2183 link = argv[optind]; 2184 else if (optind != argc) 2185 usage(); 2186 2187 if (link == NULL) { 2188 wlan_count_attr_t wcattr; 2189 2190 wcattr.wc_link = NULL; 2191 wcattr.wc_count = 0; 2192 (void) dladm_wlan_walk(&wcattr, do_count_wlan); 2193 if (wcattr.wc_count == 0) { 2194 die("no wifi links are available"); 2195 } else if (wcattr.wc_count > 1) { 2196 die("link name is required when more than one wifi " 2197 "link is available"); 2198 } 2199 link = wcattr.wc_link; 2200 } 2201 attrp = (attr.wa_valid == 0) ? NULL : &attr; 2202 again: 2203 if ((status = dladm_wlan_connect(link, attrp, timeout, keys, 2204 key_count, flags)) != DLADM_STATUS_OK) { 2205 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 2206 /* 2207 * Try again with scanning and filtering. 2208 */ 2209 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 2210 goto again; 2211 } 2212 2213 if (status == DLADM_STATUS_NOTFOUND) { 2214 if (attr.wa_valid == 0) { 2215 die("no wifi networks are available"); 2216 } else { 2217 die("no wifi networks with the specified " 2218 "criteria are available"); 2219 } 2220 } 2221 die_dlerr(status, "cannot connect link '%s'", link); 2222 } 2223 free(keys); 2224 } 2225 2226 /* ARGSUSED */ 2227 static boolean_t 2228 do_all_disconnect_wifi(void *arg, const char *link) 2229 { 2230 dladm_status_t status; 2231 2232 status = dladm_wlan_disconnect(link); 2233 if (status != DLADM_STATUS_OK) 2234 warn_dlerr(status, "cannot disconnect link '%s'", link); 2235 2236 return (B_TRUE); 2237 } 2238 2239 static void 2240 do_disconnect_wifi(int argc, char **argv) 2241 { 2242 int option; 2243 const char *link = NULL; 2244 boolean_t all_links = B_FALSE; 2245 dladm_status_t status; 2246 wlan_count_attr_t wcattr; 2247 2248 opterr = 0; 2249 while ((option = getopt_long(argc, argv, ":a", 2250 wifi_longopts, NULL)) != -1) { 2251 switch (option) { 2252 case 'a': 2253 all_links = B_TRUE; 2254 break; 2255 default: 2256 die_opterr(optopt, option); 2257 break; 2258 } 2259 } 2260 2261 if (optind == (argc - 1)) 2262 link = argv[optind]; 2263 else if (optind != argc) 2264 usage(); 2265 2266 if (link == NULL) { 2267 if (!all_links) { 2268 wcattr.wc_link = NULL; 2269 wcattr.wc_count = 0; 2270 (void) dladm_wlan_walk(&wcattr, do_count_wlan); 2271 if (wcattr.wc_count == 0) { 2272 die("no wifi links are available"); 2273 } else if (wcattr.wc_count > 1) { 2274 die("link name is required when more than " 2275 "one wifi link is available"); 2276 } 2277 link = wcattr.wc_link; 2278 } else { 2279 (void) dladm_wlan_walk(&all_links, 2280 do_all_disconnect_wifi); 2281 return; 2282 } 2283 } 2284 status = dladm_wlan_disconnect(link); 2285 if (status != DLADM_STATUS_OK) 2286 die_dlerr(status, "cannot disconnect link '%s'", link); 2287 } 2288 2289 #define MAX_PROPS 32 2290 #define MAX_PROP_VALS 32 2291 #define MAX_PROP_LINE 512 2292 2293 typedef struct prop_info { 2294 char *pi_name; 2295 char *pi_val[MAX_PROP_VALS]; 2296 uint_t pi_count; 2297 } prop_info_t; 2298 2299 typedef struct prop_list { 2300 prop_info_t pl_info[MAX_PROPS]; 2301 uint_t pl_count; 2302 char *pl_buf; 2303 } prop_list_t; 2304 2305 typedef struct show_linkprop_state { 2306 const char *ls_link; 2307 char *ls_line; 2308 char **ls_propvals; 2309 prop_list_t *ls_proplist; 2310 uint32_t ls_parseable : 1, 2311 ls_persist : 1, 2312 ls_header : 1, 2313 ls_pad_bits : 29; 2314 dladm_status_t ls_status; 2315 } show_linkprop_state_t; 2316 2317 static void 2318 free_props(prop_list_t *list) 2319 { 2320 if (list != NULL) { 2321 free(list->pl_buf); 2322 free(list); 2323 } 2324 } 2325 2326 static int 2327 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 2328 { 2329 prop_list_t *list; 2330 prop_info_t *pip; 2331 char *buf, *curr; 2332 int len, i; 2333 2334 list = malloc(sizeof (prop_list_t)); 2335 if (list == NULL) 2336 return (-1); 2337 2338 list->pl_count = 0; 2339 list->pl_buf = buf = strdup(str); 2340 if (buf == NULL) 2341 goto fail; 2342 2343 curr = buf; 2344 len = strlen(buf); 2345 pip = NULL; 2346 for (i = 0; i < len; i++) { 2347 char c = buf[i]; 2348 boolean_t match = (c == '=' || c == ','); 2349 2350 if (!match && i != len - 1) 2351 continue; 2352 2353 if (match) { 2354 buf[i] = '\0'; 2355 if (*curr == '\0') 2356 goto fail; 2357 } 2358 2359 if (pip != NULL && c != '=') { 2360 if (pip->pi_count > MAX_PROP_VALS) 2361 goto fail; 2362 2363 if (novalues) 2364 goto fail; 2365 2366 pip->pi_val[pip->pi_count] = curr; 2367 pip->pi_count++; 2368 } else { 2369 if (list->pl_count > MAX_PROPS) 2370 goto fail; 2371 2372 pip = &list->pl_info[list->pl_count]; 2373 pip->pi_name = curr; 2374 pip->pi_count = 0; 2375 list->pl_count++; 2376 if (c == ',') 2377 pip = NULL; 2378 } 2379 curr = buf + i + 1; 2380 } 2381 *listp = list; 2382 return (0); 2383 2384 fail: 2385 free_props(list); 2386 return (-1); 2387 } 2388 2389 static void 2390 print_linkprop_head(void) 2391 { 2392 (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 2393 "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 2394 } 2395 2396 static void 2397 print_linkprop(show_linkprop_state_t *statep, const char *propname, 2398 dladm_prop_type_t type, const char *typename, const char *format, 2399 char **pptr) 2400 { 2401 int i; 2402 char *ptr, *lim; 2403 char buf[DLADM_STRSIZE]; 2404 char *unknown = "?", *notsup = ""; 2405 char **propvals = statep->ls_propvals; 2406 uint_t valcnt = MAX_PROP_VALS; 2407 dladm_status_t status; 2408 2409 status = dladm_get_prop(statep->ls_link, type, propname, 2410 propvals, &valcnt); 2411 if (status != DLADM_STATUS_OK) { 2412 if (status == DLADM_STATUS_TEMPONLY) { 2413 statep->ls_status = status; 2414 return; 2415 } else if (status == DLADM_STATUS_NOTSUP || 2416 statep->ls_persist) { 2417 valcnt = 1; 2418 if (type == DLADM_PROP_VAL_CURRENT) 2419 propvals = &unknown; 2420 else 2421 propvals = ¬sup; 2422 } else { 2423 statep->ls_status = status; 2424 warn_dlerr(status, 2425 "cannot get link property '%s' for %s", 2426 propname, statep->ls_link); 2427 return; 2428 } 2429 } 2430 2431 ptr = buf; 2432 lim = buf + DLADM_STRSIZE; 2433 for (i = 0; i < valcnt; i++) { 2434 if (propvals[i][0] == '\0' && !statep->ls_parseable) 2435 ptr += snprintf(ptr, lim - ptr, "--,"); 2436 else 2437 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 2438 if (ptr >= lim) 2439 break; 2440 } 2441 if (valcnt > 0) 2442 buf[strlen(buf) - 1] = '\0'; 2443 2444 lim = statep->ls_line + MAX_PROP_LINE; 2445 if (statep->ls_parseable) { 2446 *pptr += snprintf(*pptr, lim - *pptr, 2447 "%s=\"%s\" ", typename, buf); 2448 } else { 2449 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 2450 } 2451 } 2452 2453 static boolean_t 2454 show_linkprop(void *arg, const char *propname) 2455 { 2456 show_linkprop_state_t *statep = arg; 2457 char *ptr = statep->ls_line; 2458 char *lim = ptr + MAX_PROP_LINE; 2459 2460 if (statep->ls_parseable) 2461 ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 2462 statep->ls_link); 2463 else 2464 ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 2465 2466 if (statep->ls_parseable) 2467 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 2468 else 2469 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 2470 2471 print_linkprop(statep, propname, 2472 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 2473 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 2474 2475 /* 2476 * If we failed to query the link property, for example, query 2477 * the persistent value of a non-persistable link property, simply 2478 * skip the output. 2479 */ 2480 if (statep->ls_status != DLADM_STATUS_OK) 2481 return (B_TRUE); 2482 2483 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 2484 "DEFAULT", "%-14s ", &ptr); 2485 if (statep->ls_status != DLADM_STATUS_OK) 2486 return (B_TRUE); 2487 2488 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2489 "POSSIBLE", "%-20s ", &ptr); 2490 if (statep->ls_status != DLADM_STATUS_OK) 2491 return (B_TRUE); 2492 2493 if (statep->ls_header) { 2494 statep->ls_header = B_FALSE; 2495 if (!statep->ls_parseable) 2496 print_linkprop_head(); 2497 } 2498 (void) printf("%s\n", statep->ls_line); 2499 return (B_TRUE); 2500 } 2501 2502 static void 2503 do_show_linkprop(int argc, char **argv) 2504 { 2505 int option; 2506 prop_list_t *proplist = NULL; 2507 show_linkprop_state_t state; 2508 2509 opterr = 0; 2510 state.ls_link = NULL; 2511 state.ls_propvals = NULL; 2512 state.ls_line = NULL; 2513 state.ls_parseable = B_FALSE; 2514 state.ls_persist = B_FALSE; 2515 state.ls_header = B_TRUE; 2516 while ((option = getopt_long(argc, argv, ":p:cP", 2517 prop_longopts, NULL)) != -1) { 2518 switch (option) { 2519 case 'p': 2520 if (parse_props(optarg, &proplist, B_TRUE) < 0) 2521 die("invalid link properties specified"); 2522 break; 2523 case 'c': 2524 state.ls_parseable = B_TRUE; 2525 break; 2526 case 'P': 2527 state.ls_persist = B_TRUE; 2528 break; 2529 default: 2530 die_opterr(optopt, option); 2531 break; 2532 } 2533 } 2534 2535 if (optind == (argc - 1)) 2536 state.ls_link = argv[optind]; 2537 else if (optind != argc) 2538 usage(); 2539 2540 state.ls_proplist = proplist; 2541 state.ls_status = DLADM_STATUS_OK; 2542 2543 if (state.ls_link == NULL) { 2544 (void) dladm_walk(show_linkprop_onelink, &state); 2545 } else { 2546 show_linkprop_onelink(&state, state.ls_link); 2547 } 2548 free_props(proplist); 2549 2550 if (state.ls_status != DLADM_STATUS_OK) 2551 exit(EXIT_FAILURE); 2552 } 2553 2554 static void 2555 show_linkprop_onelink(void *arg, const char *link) 2556 { 2557 int i, fd; 2558 char linkname[MAXPATHLEN]; 2559 char *buf; 2560 dladm_status_t status; 2561 prop_list_t *proplist = NULL; 2562 show_linkprop_state_t *statep; 2563 const char *savep; 2564 2565 statep = (show_linkprop_state_t *)arg; 2566 savep = statep->ls_link; 2567 statep->ls_link = link; 2568 proplist = statep->ls_proplist; 2569 2570 /* 2571 * When some WiFi links are opened for the first time, their hardware 2572 * automatically scans for APs and does other slow operations. Thus, 2573 * if there are no open links, the retrieval of link properties 2574 * (below) will proceed slowly unless we hold the link open. 2575 */ 2576 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 2577 if ((fd = open(linkname, O_RDWR)) < 0) { 2578 warn("cannot open %s: %s", link, strerror(errno)); 2579 statep->ls_status = DLADM_STATUS_NOTFOUND; 2580 return; 2581 } 2582 2583 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 2584 MAX_PROP_LINE); 2585 if (buf == NULL) 2586 die("insufficient memory"); 2587 2588 statep->ls_propvals = (char **)(void *)buf; 2589 for (i = 0; i < MAX_PROP_VALS; i++) { 2590 statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 2591 i * DLADM_PROP_VAL_MAX; 2592 } 2593 statep->ls_line = buf + 2594 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 2595 2596 if (proplist != NULL) { 2597 for (i = 0; i < proplist->pl_count; i++) 2598 (void) show_linkprop(statep, 2599 proplist->pl_info[i].pi_name); 2600 } else { 2601 status = dladm_walk_prop(link, statep, show_linkprop); 2602 if (status != DLADM_STATUS_OK) 2603 warn_dlerr(status, "show-linkprop failed for %s", link); 2604 } 2605 (void) close(fd); 2606 free(buf); 2607 statep->ls_link = savep; 2608 } 2609 2610 static dladm_status_t 2611 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 2612 uint_t val_cnt, boolean_t reset) 2613 { 2614 dladm_status_t status; 2615 char *errprop; 2616 2617 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 2618 DLADM_OPT_PERSIST, &errprop); 2619 2620 if (status != DLADM_STATUS_OK) { 2621 if (reset) { 2622 warn_dlerr(status, "cannot persistently reset link " 2623 "property '%s' on '%s'", errprop, link); 2624 } else { 2625 warn_dlerr(status, "cannot persistently set link " 2626 "property '%s' on '%s'", errprop, link); 2627 } 2628 } 2629 return (status); 2630 } 2631 2632 static void 2633 set_linkprop(int argc, char **argv, boolean_t reset) 2634 { 2635 int i, option; 2636 char errmsg[DLADM_STRSIZE]; 2637 const char *link = NULL; 2638 prop_list_t *proplist = NULL; 2639 boolean_t temp = B_FALSE; 2640 dladm_status_t status = DLADM_STATUS_OK; 2641 2642 opterr = 0; 2643 while ((option = getopt_long(argc, argv, ":p:R:t", 2644 prop_longopts, NULL)) != -1) { 2645 switch (option) { 2646 case 'p': 2647 if (parse_props(optarg, &proplist, reset) < 0) 2648 die("invalid link properties specified"); 2649 break; 2650 case 't': 2651 temp = B_TRUE; 2652 break; 2653 case 'R': 2654 status = dladm_set_rootdir(optarg); 2655 if (status != DLADM_STATUS_OK) { 2656 die_dlerr(status, "invalid directory " 2657 "specified"); 2658 } 2659 break; 2660 default: 2661 die_opterr(optopt, option); 2662 break; 2663 } 2664 } 2665 2666 if (optind == (argc - 1)) 2667 link = argv[optind]; 2668 else if (optind != argc) 2669 usage(); 2670 2671 if (link == NULL) 2672 die("link name must be specified"); 2673 2674 if (proplist == NULL) { 2675 char *errprop; 2676 2677 if (!reset) 2678 die("link property must be specified"); 2679 2680 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP, 2681 &errprop); 2682 if (status != DLADM_STATUS_OK) { 2683 warn_dlerr(status, "cannot reset link property '%s' " 2684 "on '%s'", errprop, link); 2685 } 2686 if (!temp) { 2687 dladm_status_t s; 2688 2689 s = set_linkprop_persist(link, NULL, NULL, 0, reset); 2690 if (s != DLADM_STATUS_OK) 2691 status = s; 2692 } 2693 goto done; 2694 } 2695 2696 for (i = 0; i < proplist->pl_count; i++) { 2697 prop_info_t *pip = &proplist->pl_info[i]; 2698 char **val; 2699 uint_t count; 2700 dladm_status_t s; 2701 2702 if (reset) { 2703 val = NULL; 2704 count = 0; 2705 } else { 2706 val = pip->pi_val; 2707 count = pip->pi_count; 2708 if (count == 0) { 2709 warn("no value specified for '%s'", 2710 pip->pi_name); 2711 status = DLADM_STATUS_BADARG; 2712 continue; 2713 } 2714 } 2715 s = dladm_set_prop(link, pip->pi_name, val, count, 2716 DLADM_OPT_TEMP, NULL); 2717 if (s == DLADM_STATUS_OK) { 2718 if (!temp) { 2719 s = set_linkprop_persist(link, 2720 pip->pi_name, val, count, reset); 2721 if (s != DLADM_STATUS_OK) 2722 status = s; 2723 } 2724 continue; 2725 } 2726 status = s; 2727 switch (s) { 2728 case DLADM_STATUS_NOTFOUND: 2729 warn("invalid link property '%s'", pip->pi_name); 2730 break; 2731 case DLADM_STATUS_BADVAL: { 2732 int j; 2733 char *ptr, *lim; 2734 char **propvals = NULL; 2735 uint_t valcnt = MAX_PROP_VALS; 2736 2737 ptr = malloc((sizeof (char *) + 2738 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 2739 MAX_PROP_LINE); 2740 2741 propvals = (char **)(void *)ptr; 2742 if (propvals == NULL) 2743 die("insufficient memory"); 2744 2745 for (j = 0; j < MAX_PROP_VALS; j++) { 2746 propvals[j] = ptr + sizeof (char *) * 2747 MAX_PROP_VALS + 2748 j * DLADM_PROP_VAL_MAX; 2749 } 2750 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 2751 pip->pi_name, propvals, &valcnt); 2752 2753 ptr = errmsg; 2754 lim = ptr + DLADM_STRSIZE; 2755 *ptr = '\0'; 2756 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 2757 ptr += snprintf(ptr, lim - ptr, "%s,", 2758 propvals[j]); 2759 if (ptr >= lim) 2760 break; 2761 } 2762 if (ptr > errmsg) { 2763 *(ptr - 1) = '\0'; 2764 warn("link property '%s' must be one of: %s", 2765 pip->pi_name, errmsg); 2766 } else 2767 warn("invalid link property '%s'", *val); 2768 free(propvals); 2769 break; 2770 } 2771 default: 2772 if (reset) { 2773 warn_dlerr(status, "cannot reset link property " 2774 "'%s' on '%s'", pip->pi_name, link); 2775 } else { 2776 warn_dlerr(status, "cannot set link property " 2777 "'%s' on '%s'", pip->pi_name, link); 2778 } 2779 break; 2780 } 2781 } 2782 done: 2783 free_props(proplist); 2784 if (status != DLADM_STATUS_OK) 2785 exit(1); 2786 } 2787 2788 static void 2789 do_set_linkprop(int argc, char **argv) 2790 { 2791 set_linkprop(argc, argv, B_FALSE); 2792 } 2793 2794 static void 2795 do_reset_linkprop(int argc, char **argv) 2796 { 2797 set_linkprop(argc, argv, B_TRUE); 2798 } 2799 2800 static int 2801 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 2802 dladm_secobj_class_t class) 2803 { 2804 int error = 0; 2805 2806 if (class != DLADM_SECOBJ_CLASS_WEP) 2807 return (ENOENT); 2808 2809 switch (len) { 2810 case 5: /* ASCII key sizes */ 2811 case 13: 2812 (void) memcpy(obj_val, buf, len); 2813 *obj_lenp = len; 2814 break; 2815 case 10: /* Hex key sizes, not preceded by 0x */ 2816 case 26: 2817 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 2818 break; 2819 case 12: /* Hex key sizes, preceded by 0x */ 2820 case 28: 2821 if (strncmp(buf, "0x", 2) != 0) 2822 return (EINVAL); 2823 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 2824 break; 2825 default: 2826 return (EINVAL); 2827 } 2828 return (error); 2829 } 2830 2831 /* ARGSUSED */ 2832 static void 2833 defersig(int sig) 2834 { 2835 signalled = sig; 2836 } 2837 2838 static int 2839 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 2840 { 2841 uint_t len = 0; 2842 int c; 2843 struct termios stored, current; 2844 void (*sigfunc)(int); 2845 2846 /* 2847 * Turn off echo -- but before we do so, defer SIGINT handling 2848 * so that a ^C doesn't leave the terminal corrupted. 2849 */ 2850 sigfunc = signal(SIGINT, defersig); 2851 (void) fflush(stdin); 2852 (void) tcgetattr(0, &stored); 2853 current = stored; 2854 current.c_lflag &= ~(ICANON|ECHO); 2855 current.c_cc[VTIME] = 0; 2856 current.c_cc[VMIN] = 1; 2857 (void) tcsetattr(0, TCSANOW, ¤t); 2858 again: 2859 if (try == 1) 2860 (void) printf(gettext("provide value for '%s': "), objname); 2861 else 2862 (void) printf(gettext("confirm value for '%s': "), objname); 2863 2864 (void) fflush(stdout); 2865 while (signalled == 0) { 2866 c = getchar(); 2867 if (c == '\n' || c == '\r') { 2868 if (len != 0) 2869 break; 2870 (void) putchar('\n'); 2871 goto again; 2872 } 2873 2874 buf[len++] = c; 2875 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 2876 break; 2877 (void) putchar('*'); 2878 } 2879 2880 (void) putchar('\n'); 2881 (void) fflush(stdin); 2882 2883 /* 2884 * Restore terminal setting and handle deferred signals. 2885 */ 2886 (void) tcsetattr(0, TCSANOW, &stored); 2887 2888 (void) signal(SIGINT, sigfunc); 2889 if (signalled != 0) 2890 (void) kill(getpid(), signalled); 2891 2892 return (len); 2893 } 2894 2895 static int 2896 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 2897 dladm_secobj_class_t class, FILE *filep) 2898 { 2899 int rval; 2900 uint_t len, len2; 2901 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 2902 2903 if (filep == NULL) { 2904 len = get_secobj_from_tty(1, obj_name, buf); 2905 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 2906 if (rval == 0) { 2907 len2 = get_secobj_from_tty(2, obj_name, buf2); 2908 if (len != len2 || memcmp(buf, buf2, len) != 0) 2909 rval = ENOTSUP; 2910 } 2911 return (rval); 2912 } else { 2913 for (;;) { 2914 if (fgets(buf, sizeof (buf), filep) == NULL) 2915 break; 2916 if (isspace(buf[0])) 2917 continue; 2918 2919 len = strlen(buf); 2920 if (buf[len - 1] == '\n') { 2921 buf[len - 1] = '\0'; 2922 len--; 2923 } 2924 break; 2925 } 2926 (void) fclose(filep); 2927 } 2928 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 2929 } 2930 2931 static boolean_t 2932 check_auth(const char *auth) 2933 { 2934 struct passwd *pw; 2935 2936 if ((pw = getpwuid(getuid())) == NULL) 2937 return (B_FALSE); 2938 2939 return (chkauthattr(auth, pw->pw_name) != 0); 2940 } 2941 2942 static void 2943 audit_secobj(char *auth, char *class, char *obj, 2944 boolean_t success, boolean_t create) 2945 { 2946 adt_session_data_t *ah; 2947 adt_event_data_t *event; 2948 au_event_t flag; 2949 char *errstr; 2950 2951 if (create) { 2952 flag = ADT_dladm_create_secobj; 2953 errstr = "ADT_dladm_create_secobj"; 2954 } else { 2955 flag = ADT_dladm_delete_secobj; 2956 errstr = "ADT_dladm_delete_secobj"; 2957 } 2958 2959 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 2960 die("adt_start_session: %s", strerror(errno)); 2961 2962 if ((event = adt_alloc_event(ah, flag)) == NULL) 2963 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 2964 2965 /* fill in audit info */ 2966 if (create) { 2967 event->adt_dladm_create_secobj.auth_used = auth; 2968 event->adt_dladm_create_secobj.obj_class = class; 2969 event->adt_dladm_create_secobj.obj_name = obj; 2970 } else { 2971 event->adt_dladm_delete_secobj.auth_used = auth; 2972 event->adt_dladm_delete_secobj.obj_class = class; 2973 event->adt_dladm_delete_secobj.obj_name = obj; 2974 } 2975 2976 if (success) { 2977 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 2978 die("adt_put_event (%s, success): %s", errstr, 2979 strerror(errno)); 2980 } 2981 } else { 2982 if (adt_put_event(event, ADT_FAILURE, 2983 ADT_FAIL_VALUE_AUTH) != 0) { 2984 die("adt_put_event: (%s, failure): %s", errstr, 2985 strerror(errno)); 2986 } 2987 } 2988 2989 adt_free_event(event); 2990 (void) adt_end_session(ah); 2991 } 2992 2993 #define MAX_SECOBJS 32 2994 #define MAX_SECOBJ_NAMELEN 32 2995 static void 2996 do_create_secobj(int argc, char **argv) 2997 { 2998 int option, rval; 2999 FILE *filep = NULL; 3000 char *obj_name = NULL; 3001 char *class_name = NULL; 3002 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3003 uint_t obj_len; 3004 boolean_t success, temp = B_FALSE; 3005 dladm_status_t status; 3006 dladm_secobj_class_t class = -1; 3007 uid_t euid; 3008 3009 opterr = 0; 3010 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 3011 while ((option = getopt_long(argc, argv, ":f:c:R:t", 3012 wifi_longopts, NULL)) != -1) { 3013 switch (option) { 3014 case 'f': 3015 euid = geteuid(); 3016 (void) seteuid(getuid()); 3017 filep = fopen(optarg, "r"); 3018 if (filep == NULL) { 3019 die("cannot open %s: %s", optarg, 3020 strerror(errno)); 3021 } 3022 (void) seteuid(euid); 3023 break; 3024 case 'c': 3025 class_name = optarg; 3026 status = dladm_str2secobjclass(optarg, &class); 3027 if (status != DLADM_STATUS_OK) { 3028 die("invalid secure object class '%s', " 3029 "valid values are: wep", optarg); 3030 } 3031 break; 3032 case 't': 3033 temp = B_TRUE; 3034 break; 3035 case 'R': 3036 status = dladm_set_rootdir(optarg); 3037 if (status != DLADM_STATUS_OK) { 3038 die_dlerr(status, "invalid directory " 3039 "specified"); 3040 } 3041 break; 3042 default: 3043 die_opterr(optopt, option); 3044 break; 3045 } 3046 } 3047 3048 if (optind == (argc - 1)) 3049 obj_name = argv[optind]; 3050 else if (optind != argc) 3051 usage(); 3052 3053 if (class == -1) 3054 die("secure object class required"); 3055 3056 if (obj_name == NULL) 3057 die("secure object name required"); 3058 3059 success = check_auth(LINK_SEC_AUTH); 3060 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 3061 if (!success) 3062 die("authorization '%s' is required", LINK_SEC_AUTH); 3063 3064 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 3065 if (rval != 0) { 3066 switch (rval) { 3067 case ENOENT: 3068 die("invalid secure object class"); 3069 break; 3070 case EINVAL: 3071 die("invalid secure object value"); 3072 break; 3073 case ENOTSUP: 3074 die("verification failed"); 3075 break; 3076 default: 3077 die("invalid secure object: %s", strerror(rval)); 3078 break; 3079 } 3080 } 3081 3082 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3083 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 3084 if (status != DLADM_STATUS_OK) { 3085 die_dlerr(status, "could not create secure object '%s'", 3086 obj_name); 3087 } 3088 if (temp) 3089 return; 3090 3091 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3092 DLADM_OPT_PERSIST); 3093 if (status != DLADM_STATUS_OK) { 3094 warn_dlerr(status, "could not persistently create secure " 3095 "object '%s'", obj_name); 3096 } 3097 } 3098 3099 static void 3100 do_delete_secobj(int argc, char **argv) 3101 { 3102 int i, option; 3103 boolean_t temp = B_FALSE; 3104 split_t *sp = NULL; 3105 boolean_t success; 3106 dladm_status_t status, pstatus; 3107 3108 opterr = 0; 3109 status = pstatus = DLADM_STATUS_OK; 3110 while ((option = getopt_long(argc, argv, ":R:t", 3111 wifi_longopts, NULL)) != -1) { 3112 switch (option) { 3113 case 't': 3114 temp = B_TRUE; 3115 break; 3116 case 'R': 3117 status = dladm_set_rootdir(optarg); 3118 if (status != DLADM_STATUS_OK) { 3119 die_dlerr(status, "invalid directory " 3120 "specified"); 3121 } 3122 break; 3123 default: 3124 die_opterr(optopt, option); 3125 break; 3126 } 3127 } 3128 3129 if (optind == (argc - 1)) { 3130 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3131 if (sp == NULL) { 3132 die("invalid secure object name(s): '%s'", 3133 argv[optind]); 3134 } 3135 } else if (optind != argc) 3136 usage(); 3137 3138 if (sp == NULL || sp->s_nfields < 1) 3139 die("secure object name required"); 3140 3141 success = check_auth(LINK_SEC_AUTH); 3142 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 3143 if (!success) 3144 die("authorization '%s' is required", LINK_SEC_AUTH); 3145 3146 for (i = 0; i < sp->s_nfields; i++) { 3147 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 3148 if (!temp) { 3149 pstatus = dladm_unset_secobj(sp->s_fields[i], 3150 DLADM_OPT_PERSIST); 3151 } else { 3152 pstatus = DLADM_STATUS_OK; 3153 } 3154 3155 if (status != DLADM_STATUS_OK) { 3156 warn_dlerr(status, "could not delete secure object " 3157 "'%s'", sp->s_fields[i]); 3158 } 3159 if (pstatus != DLADM_STATUS_OK) { 3160 warn_dlerr(pstatus, "could not persistently delete " 3161 "secure object '%s'", sp->s_fields[i]); 3162 } 3163 } 3164 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 3165 exit(1); 3166 } 3167 3168 typedef struct show_secobj_state { 3169 boolean_t ss_persist; 3170 boolean_t ss_parseable; 3171 boolean_t ss_debug; 3172 boolean_t ss_header; 3173 } show_secobj_state_t; 3174 3175 static void 3176 print_secobj_head(show_secobj_state_t *statep) 3177 { 3178 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 3179 if (statep->ss_debug) 3180 (void) printf("%-30s", "VALUE"); 3181 (void) putchar('\n'); 3182 } 3183 3184 static boolean_t 3185 show_secobj(void *arg, const char *obj_name) 3186 { 3187 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 3188 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3189 char buf[DLADM_STRSIZE]; 3190 uint_t flags = 0; 3191 dladm_secobj_class_t class; 3192 show_secobj_state_t *statep = arg; 3193 dladm_status_t status; 3194 3195 if (statep->ss_persist) 3196 flags |= DLADM_OPT_PERSIST; 3197 3198 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 3199 if (status != DLADM_STATUS_OK) 3200 die_dlerr(status, "cannot get secure object '%s'", obj_name); 3201 3202 if (statep->ss_header) { 3203 statep->ss_header = B_FALSE; 3204 if (!statep->ss_parseable) 3205 print_secobj_head(statep); 3206 } 3207 3208 if (statep->ss_parseable) { 3209 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 3210 dladm_secobjclass2str(class, buf)); 3211 } else { 3212 (void) printf("%-20s %-20s ", obj_name, 3213 dladm_secobjclass2str(class, buf)); 3214 } 3215 3216 if (statep->ss_debug) { 3217 char val[DLADM_SECOBJ_VAL_MAX * 2]; 3218 uint_t len = sizeof (val); 3219 3220 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 3221 if (statep->ss_parseable) 3222 (void) printf("VALUE=\"0x%s\"", val); 3223 else 3224 (void) printf("0x%-30s", val); 3225 } 3226 } 3227 (void) putchar('\n'); 3228 return (B_TRUE); 3229 } 3230 3231 static void 3232 do_show_secobj(int argc, char **argv) 3233 { 3234 int option; 3235 show_secobj_state_t state; 3236 dladm_status_t status; 3237 uint_t i; 3238 split_t *sp; 3239 uint_t flags; 3240 3241 opterr = 0; 3242 state.ss_persist = B_FALSE; 3243 state.ss_parseable = B_FALSE; 3244 state.ss_debug = B_FALSE; 3245 state.ss_header = B_TRUE; 3246 while ((option = getopt_long(argc, argv, ":pPd", 3247 wifi_longopts, NULL)) != -1) { 3248 switch (option) { 3249 case 'p': 3250 state.ss_parseable = B_TRUE; 3251 break; 3252 case 'P': 3253 state.ss_persist = B_TRUE; 3254 break; 3255 case 'd': 3256 if (getuid() != 0) 3257 die("insufficient privileges"); 3258 state.ss_debug = B_TRUE; 3259 break; 3260 default: 3261 die_opterr(optopt, option); 3262 break; 3263 } 3264 } 3265 3266 if (optind == (argc - 1)) { 3267 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3268 if (sp == NULL) { 3269 die("invalid secure object name(s): '%s'", 3270 argv[optind]); 3271 } 3272 for (i = 0; i < sp->s_nfields; i++) { 3273 if (!show_secobj(&state, sp->s_fields[i])) 3274 break; 3275 } 3276 splitfree(sp); 3277 return; 3278 } else if (optind != argc) 3279 usage(); 3280 3281 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 3282 status = dladm_walk_secobj(&state, show_secobj, flags); 3283 if (status != DLADM_STATUS_OK) 3284 die_dlerr(status, "show-secobj"); 3285 } 3286 3287 /* ARGSUSED */ 3288 static void 3289 do_init_linkprop(int argc, char **argv) 3290 { 3291 dladm_status_t status; 3292 3293 status = dladm_init_linkprop(); 3294 if (status != DLADM_STATUS_OK) 3295 die_dlerr(status, "link property initialization failed"); 3296 } 3297 3298 /* ARGSUSED */ 3299 static void 3300 do_init_secobj(int argc, char **argv) 3301 { 3302 dladm_status_t status; 3303 3304 status = dladm_init_secobj(); 3305 if (status != DLADM_STATUS_OK) 3306 die_dlerr(status, "secure object initialization failed"); 3307 } 3308 3309 static boolean_t 3310 str2int(const char *str, int *valp) 3311 { 3312 int val; 3313 char *endp = NULL; 3314 3315 errno = 0; 3316 val = strtol(str, &endp, 10); 3317 if (errno != 0 || *endp != '\0') 3318 return (B_FALSE); 3319 3320 *valp = val; 3321 return (B_TRUE); 3322 } 3323 3324 /* PRINTFLIKE1 */ 3325 static void 3326 warn(const char *format, ...) 3327 { 3328 va_list alist; 3329 3330 format = gettext(format); 3331 (void) fprintf(stderr, "%s: warning: ", progname); 3332 3333 va_start(alist, format); 3334 (void) vfprintf(stderr, format, alist); 3335 va_end(alist); 3336 3337 (void) putchar('\n'); 3338 } 3339 3340 /* PRINTFLIKE2 */ 3341 static void 3342 warn_dlerr(dladm_status_t err, const char *format, ...) 3343 { 3344 va_list alist; 3345 char errmsg[DLADM_STRSIZE]; 3346 3347 format = gettext(format); 3348 (void) fprintf(stderr, gettext("%s: warning: "), progname); 3349 3350 va_start(alist, format); 3351 (void) vfprintf(stderr, format, alist); 3352 va_end(alist); 3353 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3354 } 3355 3356 /* PRINTFLIKE2 */ 3357 static void 3358 die_dlerr(dladm_status_t err, const char *format, ...) 3359 { 3360 va_list alist; 3361 char errmsg[DLADM_STRSIZE]; 3362 3363 format = gettext(format); 3364 (void) fprintf(stderr, "%s: ", progname); 3365 3366 va_start(alist, format); 3367 (void) vfprintf(stderr, format, alist); 3368 va_end(alist); 3369 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3370 3371 exit(EXIT_FAILURE); 3372 } 3373 3374 /* PRINTFLIKE1 */ 3375 static void 3376 die(const char *format, ...) 3377 { 3378 va_list alist; 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 3387 (void) putchar('\n'); 3388 exit(EXIT_FAILURE); 3389 } 3390 3391 static void 3392 die_optdup(int opt) 3393 { 3394 die("the option -%c cannot be specified more than once", opt); 3395 } 3396 3397 static void 3398 die_opterr(int opt, int opterr) 3399 { 3400 switch (opterr) { 3401 case ':': 3402 die("option '-%c' requires a value", opt); 3403 break; 3404 case '?': 3405 default: 3406 die("unrecognized option '-%c'", opt); 3407 break; 3408 } 3409 } 3410