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