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