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