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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <ctype.h> 30 #include <locale.h> 31 #include <signal.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <stropts.h> 37 #include <sys/stat.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 <libdevinfo.h> 50 #include <libdlpi.h> 51 #include <libdllink.h> 52 #include <libdlaggr.h> 53 #include <libdlwlan.h> 54 #include <libdlvlan.h> 55 #include <libdlvnic.h> 56 #include <libinetutil.h> 57 #include <bsm/adt.h> 58 #include <bsm/adt_event.h> 59 60 #define AGGR_DRV "aggr" 61 #define MAXPORT 256 62 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 63 #define MAXLINELEN 1024 64 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 65 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 66 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 67 68 typedef struct pktsum_s { 69 uint64_t ipackets; 70 uint64_t opackets; 71 uint64_t rbytes; 72 uint64_t obytes; 73 uint32_t ierrors; 74 uint32_t oerrors; 75 } pktsum_t; 76 77 typedef struct show_state { 78 boolean_t ls_firstonly; 79 boolean_t ls_donefirst; 80 pktsum_t ls_prevstats; 81 boolean_t ls_parseable; 82 uint32_t ls_flags; 83 dladm_status_t ls_status; 84 } show_state_t; 85 86 typedef struct show_grp_state { 87 boolean_t gs_lacp; 88 boolean_t gs_extended; 89 boolean_t gs_stats; 90 boolean_t gs_firstonly; 91 boolean_t gs_donefirst; 92 pktsum_t gs_prevstats[MAXPORT]; 93 boolean_t gs_parseable; 94 uint32_t gs_flags; 95 dladm_status_t gs_status; 96 } show_grp_state_t; 97 98 typedef void cmdfunc_t(int, char **); 99 100 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi, do_show_phys; 101 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 102 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 103 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 104 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 105 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 106 static cmdfunc_t do_init_linkprop, do_init_secobj; 107 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 108 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 109 static cmdfunc_t do_show_linkmap; 110 111 static void altroot_cmd(char *, int, char **); 112 static int show_linkprop_onelink(datalink_id_t, void *); 113 114 static void link_stats(datalink_id_t, uint_t); 115 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 116 static void dev_stats(const char *dev, uint32_t); 117 118 static int get_one_kstat(const char *, const char *, uint8_t, 119 void *, boolean_t); 120 static void get_mac_stats(const char *, pktsum_t *); 121 static void get_link_stats(const char *, pktsum_t *); 122 static uint64_t get_ifspeed(const char *, boolean_t); 123 static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 124 static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 125 static const char *get_linkstate(const char *, boolean_t, char *); 126 static const char *get_linkduplex(const char *, boolean_t, char *); 127 128 static boolean_t str2int(const char *, int *); 129 static void die(const char *, ...); 130 static void die_optdup(int); 131 static void die_opterr(int, int); 132 static void die_dlerr(dladm_status_t, const char *, ...); 133 static void warn(const char *, ...); 134 static void warn_dlerr(dladm_status_t, const char *, ...); 135 136 typedef struct cmd { 137 char *c_name; 138 cmdfunc_t *c_fn; 139 } cmd_t; 140 141 static cmd_t cmds[] = { 142 { "show-link", do_show_link }, 143 { "show-dev", do_show_dev }, 144 { "create-aggr", do_create_aggr }, 145 { "delete-aggr", do_delete_aggr }, 146 { "add-aggr", do_add_aggr }, 147 { "remove-aggr", do_remove_aggr }, 148 { "modify-aggr", do_modify_aggr }, 149 { "show-aggr", do_show_aggr }, 150 { "up-aggr", do_up_aggr }, 151 { "scan-wifi", do_scan_wifi }, 152 { "connect-wifi", do_connect_wifi }, 153 { "disconnect-wifi", do_disconnect_wifi }, 154 { "show-wifi", do_show_wifi }, 155 { "show-linkprop", do_show_linkprop }, 156 { "set-linkprop", do_set_linkprop }, 157 { "reset-linkprop", do_reset_linkprop }, 158 { "create-secobj", do_create_secobj }, 159 { "delete-secobj", do_delete_secobj }, 160 { "show-secobj", do_show_secobj }, 161 { "init-linkprop", do_init_linkprop }, 162 { "init-secobj", do_init_secobj }, 163 { "create-vlan", do_create_vlan }, 164 { "delete-vlan", do_delete_vlan }, 165 { "show-vlan", do_show_vlan }, 166 { "up-vlan", do_up_vlan }, 167 { "rename-link", do_rename_link }, 168 { "delete-phys", do_delete_phys }, 169 { "show-phys", do_show_phys }, 170 { "init-phys", do_init_phys }, 171 { "show-linkmap", do_show_linkmap } 172 }; 173 174 static const struct option lopts[] = { 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 {"temporary", no_argument, 0, 't'}, 182 {"root-dir", required_argument, 0, 'R'}, 183 {"link", required_argument, 0, 'l'}, 184 {"forcible", no_argument, 0, 'f'}, 185 { 0, 0, 0, 0 } 186 }; 187 188 static const struct option show_lopts[] = { 189 {"statistics", no_argument, 0, 's'}, 190 {"interval", required_argument, 0, 'i'}, 191 {"parseable", no_argument, 0, 'p'}, 192 {"extended", no_argument, 0, 'x'}, 193 {"persistent", no_argument, 0, 'P'}, 194 {"lacp", no_argument, 0, 'L'}, 195 { 0, 0, 0, 0 } 196 }; 197 198 static const struct option prop_longopts[] = { 199 {"temporary", no_argument, 0, 't' }, 200 {"root-dir", required_argument, 0, 'R' }, 201 {"prop", required_argument, 0, 'p' }, 202 {"parseable", no_argument, 0, 'c' }, 203 {"persistent", no_argument, 0, 'P' }, 204 { 0, 0, 0, 0 } 205 }; 206 207 static const struct option wifi_longopts[] = { 208 {"parseable", no_argument, 0, 'p' }, 209 {"output", required_argument, 0, 'o' }, 210 {"essid", required_argument, 0, 'e' }, 211 {"bsstype", required_argument, 0, 'b' }, 212 {"mode", required_argument, 0, 'm' }, 213 {"key", required_argument, 0, 'k' }, 214 {"sec", required_argument, 0, 's' }, 215 {"auth", required_argument, 0, 'a' }, 216 {"create-ibss", required_argument, 0, 'c' }, 217 {"timeout", required_argument, 0, 'T' }, 218 {"all-links", no_argument, 0, 'a' }, 219 {"temporary", no_argument, 0, 't' }, 220 {"root-dir", required_argument, 0, 'R' }, 221 {"persistent", no_argument, 0, 'P' }, 222 {"file", required_argument, 0, 'f' }, 223 { 0, 0, 0, 0 } 224 }; 225 226 static char *progname; 227 static sig_atomic_t signalled; 228 229 static void 230 usage(void) 231 { 232 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 233 "\tshow-link [-pP] [-s [-i <interval>]] [<link>]\n" 234 "\trename-link [-R <root-dir>] <oldlink> <newlink>\n" 235 "\n" 236 "\tdelete-phys <link>\n" 237 "\tshow-phys [-pP] [<link>]\n" 238 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 239 "\n" 240 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 241 "\t [-T <time>] [-u <address>] [-l <link>] ... <link>\n" 242 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 243 "\t [-T <time>] [-u <address>] <link>\n" 244 "\tdelete-aggr [-t] [-R <root-dir>] <link>\n" 245 "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" 246 "\tremove-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>" 247 "\n\tshow-aggr [-pPLx][-s [-i <interval>]] [<link>]\n" 248 "\n" 249 "\tcreate-vlan [-ft] [-R <root-dir>] -l <link> -v <vid> [link]" 250 "\n\tdelete-vlan [-t] [-R <root-dir>] <link>\n" 251 "\tshow-vlan [-pP] [<link>]\n" 252 "\n" 253 "\tscan-wifi [-p] [-o <field>,...] [<link>]\n" 254 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 255 " [-s wep|wpa]\n" 256 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 257 "\t [-T <time>] [<link>]\n" 258 "\tdisconnect-wifi [-a] [<link>]\n" 259 "\tshow-wifi [-p] [-o <field>,...] [<link>]\n" 260 "\n" 261 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 262 " <name>\n" 263 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 264 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 265 "\n" 266 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 267 " <secobj>\n" 268 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 269 "\tshow-secobj [-pP][<secobj>,...]\n")); 270 exit(1); 271 } 272 273 int 274 main(int argc, char *argv[]) 275 { 276 int i; 277 cmd_t *cmdp; 278 279 (void) setlocale(LC_ALL, ""); 280 #if !defined(TEXT_DOMAIN) 281 #define TEXT_DOMAIN "SYS_TEST" 282 #endif 283 (void) textdomain(TEXT_DOMAIN); 284 285 progname = argv[0]; 286 287 if (argc < 2) 288 usage(); 289 290 if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 291 !priv_ineffect(PRIV_NET_RAWACCESS)) 292 die("insufficient privileges"); 293 294 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 295 cmdp = &cmds[i]; 296 if (strcmp(argv[1], cmdp->c_name) == 0) { 297 cmdp->c_fn(argc - 1, &argv[1]); 298 exit(0); 299 } 300 } 301 302 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 303 progname, argv[1]); 304 usage(); 305 306 return (0); 307 } 308 309 static void 310 do_create_aggr(int argc, char *argv[]) 311 { 312 char option; 313 int key = 0; 314 uint32_t policy = AGGR_POLICY_L4; 315 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 316 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 317 dladm_aggr_port_attr_db_t port[MAXPORT]; 318 uint_t n, ndev, nlink; 319 uint8_t mac_addr[ETHERADDRL]; 320 boolean_t mac_addr_fixed = B_FALSE; 321 boolean_t P_arg = B_FALSE; 322 boolean_t l_arg = B_FALSE; 323 boolean_t u_arg = B_FALSE; 324 boolean_t T_arg = B_FALSE; 325 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 326 char *altroot = NULL; 327 char name[MAXLINKNAMELEN]; 328 char *devs[MAXPORT]; 329 char *links[MAXPORT]; 330 dladm_status_t status; 331 332 ndev = nlink = opterr = 0; 333 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:", 334 lopts, NULL)) != -1) { 335 switch (option) { 336 case 'd': 337 if (ndev + nlink >= MAXPORT) 338 die("too many ports specified"); 339 340 devs[ndev++] = optarg; 341 break; 342 case 'P': 343 if (P_arg) 344 die_optdup(option); 345 346 P_arg = B_TRUE; 347 if (!dladm_aggr_str2policy(optarg, &policy)) 348 die("invalid policy '%s'", optarg); 349 break; 350 case 'u': 351 if (u_arg) 352 die_optdup(option); 353 354 u_arg = B_TRUE; 355 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 356 mac_addr)) 357 die("invalid MAC address '%s'", optarg); 358 break; 359 case 'l': 360 if (isdigit(optarg[strlen(optarg) - 1])) { 361 362 /* 363 * Ended with digit, possibly a link name. 364 */ 365 if (ndev + nlink >= MAXPORT) 366 die("too many ports specified"); 367 368 links[nlink++] = optarg; 369 break; 370 } 371 /* FALLTHROUGH */ 372 case 'L': 373 if (l_arg) 374 die_optdup(option); 375 376 l_arg = B_TRUE; 377 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 378 die("invalid LACP mode '%s'", optarg); 379 break; 380 case 'T': 381 if (T_arg) 382 die_optdup(option); 383 384 T_arg = B_TRUE; 385 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 386 die("invalid LACP timer value '%s'", optarg); 387 break; 388 case 't': 389 flags &= ~DLADM_OPT_PERSIST; 390 break; 391 case 'f': 392 flags |= DLADM_OPT_FORCE; 393 break; 394 case 'R': 395 altroot = optarg; 396 break; 397 default: 398 die_opterr(optopt, option); 399 break; 400 } 401 } 402 403 if (ndev + nlink == 0) 404 usage(); 405 406 /* get key value or the aggregation name (required last argument) */ 407 if (optind != (argc-1)) 408 usage(); 409 410 if (!str2int(argv[optind], &key)) { 411 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 412 MAXLINKNAMELEN) { 413 die("link name too long '%s'", argv[optind]); 414 } 415 416 if (!dladm_valid_linkname(name)) 417 die("invalid link name '%s'", argv[optind]); 418 } else { 419 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 420 } 421 422 if (altroot != NULL) 423 altroot_cmd(altroot, argc, argv); 424 425 for (n = 0; n < ndev; n++) { 426 if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) != 427 DLADM_STATUS_OK) { 428 die("invalid dev name '%s'", devs[n]); 429 } 430 } 431 432 for (n = 0; n < nlink; n++) { 433 if (dladm_name2info(links[n], &port[ndev + n].lp_linkid, 434 NULL, NULL, NULL) != DLADM_STATUS_OK) { 435 die("invalid link name '%s'", links[n]); 436 } 437 } 438 439 status = dladm_aggr_create(name, key, ndev + nlink, port, policy, 440 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 441 lacp_timer, flags); 442 done: 443 if (status != DLADM_STATUS_OK) { 444 if (status == DLADM_STATUS_NONOTIF) { 445 die_dlerr(status, "not all links have link up/down " 446 "detection; must use -f (see dladm(1M))\n"); 447 } else { 448 die_dlerr(status, "create operation failed"); 449 } 450 } 451 } 452 453 /* 454 * arg is either the key or the aggr name. Validate it and convert it to 455 * the linkid if altroot is NULL. 456 */ 457 static dladm_status_t 458 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 459 datalink_id_t *linkidp, uint32_t flags) 460 { 461 int key = 0; 462 char *aggr = NULL; 463 dladm_status_t status; 464 465 if (!str2int(arg, &key)) 466 aggr = (char *)arg; 467 468 if (aggr == NULL && key == 0) 469 return (DLADM_STATUS_LINKINVAL); 470 471 if (altroot != NULL) 472 return (DLADM_STATUS_OK); 473 474 if (aggr != NULL) { 475 status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL); 476 } else { 477 status = dladm_key2linkid(key, linkidp, flags); 478 } 479 480 return (status); 481 } 482 483 static void 484 do_delete_aggr(int argc, char *argv[]) 485 { 486 char option; 487 char *altroot = NULL; 488 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 489 dladm_status_t status; 490 datalink_id_t linkid; 491 492 opterr = 0; 493 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 494 switch (option) { 495 case 't': 496 flags &= ~DLADM_OPT_PERSIST; 497 break; 498 case 'R': 499 altroot = optarg; 500 break; 501 default: 502 die_opterr(optopt, option); 503 break; 504 } 505 } 506 507 /* get key value or the aggregation name (required last argument) */ 508 if (optind != (argc-1)) 509 usage(); 510 511 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 512 if (status != DLADM_STATUS_OK) 513 goto done; 514 515 if (altroot != NULL) 516 altroot_cmd(altroot, argc, argv); 517 518 status = dladm_aggr_delete(linkid, flags); 519 done: 520 if (status != DLADM_STATUS_OK) 521 die_dlerr(status, "delete operation failed"); 522 } 523 524 static void 525 do_add_aggr(int argc, char *argv[]) 526 { 527 char option; 528 uint_t n, ndev, nlink; 529 char *altroot = NULL; 530 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 531 datalink_id_t linkid; 532 dladm_status_t status; 533 dladm_aggr_port_attr_db_t port[MAXPORT]; 534 char *devs[MAXPORT]; 535 char *links[MAXPORT]; 536 537 ndev = nlink = opterr = 0; 538 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 539 NULL)) != -1) { 540 switch (option) { 541 case 'd': 542 if (ndev + nlink >= MAXPORT) 543 die("too many ports specified"); 544 545 devs[ndev++] = optarg; 546 break; 547 case 'l': 548 if (ndev + nlink >= MAXPORT) 549 die("too many ports specified"); 550 551 links[nlink++] = optarg; 552 break; 553 case 't': 554 flags &= ~DLADM_OPT_PERSIST; 555 break; 556 case 'f': 557 flags |= DLADM_OPT_FORCE; 558 break; 559 case 'R': 560 altroot = optarg; 561 break; 562 default: 563 die_opterr(optopt, option); 564 break; 565 } 566 } 567 568 if (ndev + nlink == 0) 569 usage(); 570 571 /* get key value or the aggregation name (required last argument) */ 572 if (optind != (argc-1)) 573 usage(); 574 575 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 576 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 577 DLADM_STATUS_OK) { 578 goto done; 579 } 580 581 if (altroot != NULL) 582 altroot_cmd(altroot, argc, argv); 583 584 for (n = 0; n < ndev; n++) { 585 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 586 DLADM_STATUS_OK) { 587 die("invalid <dev> '%s'", devs[n]); 588 } 589 } 590 591 for (n = 0; n < nlink; n++) { 592 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 593 NULL, NULL, NULL) != DLADM_STATUS_OK) { 594 die("invalid <link> '%s'", links[n]); 595 } 596 } 597 598 status = dladm_aggr_add(linkid, ndev + nlink, port, flags); 599 done: 600 if (status != DLADM_STATUS_OK) { 601 /* 602 * checking DLADM_STATUS_NOTSUP is a temporary workaround 603 * and should be removed once 6399681 is fixed. 604 */ 605 if (status == DLADM_STATUS_NOTSUP) { 606 (void) fprintf(stderr, 607 gettext("%s: add operation failed: %s\n"), 608 progname, 609 gettext("link capabilities don't match")); 610 exit(ENOTSUP); 611 } else if (status == DLADM_STATUS_NONOTIF) { 612 die_dlerr(status, "not all links have link up/down " 613 "detection; must use -f (see dladm(1M))\n"); 614 } else { 615 die_dlerr(status, "add operation failed"); 616 } 617 } 618 } 619 620 static void 621 do_remove_aggr(int argc, char *argv[]) 622 { 623 char option; 624 dladm_aggr_port_attr_db_t port[MAXPORT]; 625 uint_t n, ndev, nlink; 626 char *devs[MAXPORT]; 627 char *links[MAXPORT]; 628 char *altroot = NULL; 629 uint32_t flags; 630 datalink_id_t linkid; 631 dladm_status_t status; 632 633 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 634 ndev = nlink = opterr = 0; 635 while ((option = getopt_long(argc, argv, ":d:l:R:t", 636 lopts, NULL)) != -1) { 637 switch (option) { 638 case 'd': 639 if (ndev + nlink >= MAXPORT) 640 die("too many ports specified"); 641 642 devs[ndev++] = optarg; 643 break; 644 case 'l': 645 if (ndev + nlink >= MAXPORT) 646 die("too many ports specified"); 647 648 links[nlink++] = optarg; 649 break; 650 case 't': 651 flags &= ~DLADM_OPT_PERSIST; 652 break; 653 case 'R': 654 altroot = optarg; 655 break; 656 default: 657 die_opterr(optopt, option); 658 break; 659 } 660 } 661 662 if (ndev + nlink == 0) 663 usage(); 664 665 /* get key value or the aggregation name (required last argument) */ 666 if (optind != (argc-1)) 667 usage(); 668 669 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 670 if (status != DLADM_STATUS_OK) 671 goto done; 672 673 if (altroot != NULL) 674 altroot_cmd(altroot, argc, argv); 675 676 for (n = 0; n < ndev; n++) { 677 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 678 DLADM_STATUS_OK) { 679 die("invalid <dev> '%s'", devs[n]); 680 } 681 } 682 683 for (n = 0; n < nlink; n++) { 684 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 685 NULL, NULL, NULL) != DLADM_STATUS_OK) { 686 die("invalid <link> '%s'", links[n]); 687 } 688 } 689 690 status = dladm_aggr_remove(linkid, ndev + nlink, port, flags); 691 done: 692 if (status != DLADM_STATUS_OK) 693 die_dlerr(status, "remove operation failed"); 694 } 695 696 static void 697 do_modify_aggr(int argc, char *argv[]) 698 { 699 char option; 700 uint32_t policy = AGGR_POLICY_L4; 701 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 702 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 703 uint8_t mac_addr[ETHERADDRL]; 704 boolean_t mac_addr_fixed = B_FALSE; 705 uint8_t modify_mask = 0; 706 char *altroot = NULL; 707 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 708 datalink_id_t linkid; 709 dladm_status_t status; 710 711 opterr = 0; 712 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 713 NULL)) != -1) { 714 switch (option) { 715 case 'P': 716 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 717 die_optdup(option); 718 719 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 720 721 if (!dladm_aggr_str2policy(optarg, &policy)) 722 die("invalid policy '%s'", optarg); 723 break; 724 case 'u': 725 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 726 die_optdup(option); 727 728 modify_mask |= DLADM_AGGR_MODIFY_MAC; 729 730 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 731 mac_addr)) 732 die("invalid MAC address '%s'", optarg); 733 break; 734 case 'l': 735 case 'L': 736 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 737 die_optdup(option); 738 739 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 740 741 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 742 die("invalid LACP mode '%s'", optarg); 743 break; 744 case 'T': 745 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 746 die_optdup(option); 747 748 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 749 750 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 751 die("invalid LACP timer value '%s'", optarg); 752 break; 753 case 't': 754 flags &= ~DLADM_OPT_PERSIST; 755 break; 756 case 'R': 757 altroot = optarg; 758 break; 759 default: 760 die_opterr(optopt, option); 761 break; 762 } 763 } 764 765 if (modify_mask == 0) 766 die("at least one of the -PulT options must be specified"); 767 768 /* get key value or the aggregation name (required last argument) */ 769 if (optind != (argc-1)) 770 usage(); 771 772 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 773 if (status != DLADM_STATUS_OK) 774 goto done; 775 776 if (altroot != NULL) 777 altroot_cmd(altroot, argc, argv); 778 779 status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed, 780 (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags); 781 782 done: 783 if (status != DLADM_STATUS_OK) 784 die_dlerr(status, "modify operation failed"); 785 } 786 787 static void 788 do_up_aggr(int argc, char *argv[]) 789 { 790 datalink_id_t linkid = DATALINK_ALL_LINKID; 791 dladm_status_t status; 792 793 /* 794 * get the key or the name of the aggregation (optional last argument) 795 */ 796 if (argc == 2) { 797 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 798 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) { 799 goto done; 800 } 801 } else if (argc > 2) { 802 usage(); 803 } 804 805 status = dladm_aggr_up(linkid); 806 done: 807 if (status != DLADM_STATUS_OK) { 808 if (argc == 2) { 809 die_dlerr(status, 810 "could not bring up aggregation '%s'", argv[1]); 811 } else { 812 die_dlerr(status, "could not bring aggregations up"); 813 } 814 } 815 } 816 817 static void 818 do_create_vlan(int argc, char *argv[]) 819 { 820 char *link = NULL; 821 char drv[DLPI_LINKNAME_MAX]; 822 uint_t ppa; 823 datalink_id_t linkid; 824 int vid = 0; 825 char option; 826 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 827 char *altroot = NULL; 828 char vlan[MAXLINKNAMELEN]; 829 dladm_status_t status; 830 831 opterr = 0; 832 while ((option = getopt_long(argc, argv, ":tfl:v:", 833 lopts, NULL)) != -1) { 834 switch (option) { 835 case 'v': 836 if (vid != 0) 837 die_optdup(option); 838 839 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 840 die("invalid VLAN identifier '%s'", optarg); 841 842 break; 843 case 'l': 844 if (link != NULL) 845 die_optdup(option); 846 847 link = optarg; 848 break; 849 case 'f': 850 flags |= DLADM_OPT_FORCE; 851 break; 852 case 't': 853 flags &= ~DLADM_OPT_PERSIST; 854 break; 855 case 'R': 856 altroot = optarg; 857 break; 858 default: 859 die_opterr(optopt, option); 860 break; 861 } 862 } 863 864 /* get vlan name if there is any */ 865 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 866 usage(); 867 868 if (optind == (argc - 1)) { 869 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 870 MAXLINKNAMELEN) { 871 die("vlan name too long '%s'", argv[optind]); 872 } 873 } else { 874 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 875 (ppa >= 1000) || 876 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 877 DLPI_SUCCESS)) { 878 die("invalid link name '%s'", link); 879 } 880 } 881 882 if (altroot != NULL) 883 altroot_cmd(altroot, argc, argv); 884 885 if (dladm_name2info(link, &linkid, NULL, NULL, NULL) != 886 DLADM_STATUS_OK) { 887 die("invalid link name '%s'", link); 888 } 889 890 if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) != 891 DLADM_STATUS_OK) { 892 if (status == DLADM_STATUS_NOTSUP) { 893 die_dlerr(status, "VLAN over '%s' may require lowered " 894 "MTU; must use -f (see dladm(1M))\n", link); 895 } else { 896 die_dlerr(status, "create operation failed"); 897 } 898 } 899 } 900 901 static void 902 do_delete_vlan(int argc, char *argv[]) 903 { 904 char option; 905 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 906 char *altroot = NULL; 907 datalink_id_t linkid; 908 dladm_status_t status; 909 910 opterr = 0; 911 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 912 switch (option) { 913 case 't': 914 flags &= ~DLADM_OPT_PERSIST; 915 break; 916 case 'R': 917 altroot = optarg; 918 break; 919 default: 920 die_opterr(optopt, option); 921 break; 922 } 923 } 924 925 /* get VLAN link name (required last argument) */ 926 if (optind != (argc - 1)) 927 usage(); 928 929 if (altroot != NULL) 930 altroot_cmd(altroot, argc, argv); 931 932 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 933 if (status != DLADM_STATUS_OK) 934 goto done; 935 936 status = dladm_vlan_delete(linkid, flags); 937 done: 938 if (status != DLADM_STATUS_OK) 939 die_dlerr(status, "delete operation failed"); 940 } 941 942 static void 943 do_up_vlan(int argc, char *argv[]) 944 { 945 datalink_id_t linkid = DATALINK_ALL_LINKID; 946 dladm_status_t status; 947 948 /* 949 * get the name of the VLAN (optional last argument) 950 */ 951 if (argc > 2) 952 usage(); 953 954 if (argc == 2) { 955 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 956 if (status != DLADM_STATUS_OK) 957 goto done; 958 } 959 960 status = dladm_vlan_up(linkid); 961 done: 962 if (status != DLADM_STATUS_OK) { 963 if (argc == 2) { 964 die_dlerr(status, 965 "could not bring up VLAN '%s'", argv[1]); 966 } else { 967 die_dlerr(status, "could not bring VLANs up"); 968 } 969 } 970 } 971 972 static void 973 do_rename_link(int argc, char *argv[]) 974 { 975 char option; 976 char *link1, *link2; 977 char *altroot = NULL; 978 dladm_status_t status; 979 980 opterr = 0; 981 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 982 switch (option) { 983 case 'R': 984 altroot = optarg; 985 break; 986 default: 987 die_opterr(optopt, option); 988 break; 989 } 990 } 991 992 /* get link1 and link2 name (required the last 2 arguments) */ 993 if (optind != (argc - 2)) 994 usage(); 995 996 if (altroot != NULL) 997 altroot_cmd(altroot, argc, argv); 998 999 link1 = argv[optind++]; 1000 link2 = argv[optind]; 1001 if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK) 1002 die_dlerr(status, "rename operation failed"); 1003 } 1004 1005 static void 1006 do_delete_phys(int argc, char *argv[]) 1007 { 1008 datalink_id_t linkid = DATALINK_ALL_LINKID; 1009 dladm_status_t status; 1010 1011 /* get link name (required the last argument) */ 1012 if (argc > 2) 1013 usage(); 1014 1015 if (argc == 2) { 1016 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 1017 if (status != DLADM_STATUS_OK) 1018 die_dlerr(status, "cannot delete '%s'", argv[1]); 1019 } 1020 1021 if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) { 1022 if (argc == 2) 1023 die_dlerr(status, "cannot delete '%s'", argv[1]); 1024 else 1025 die_dlerr(status, "delete operation failed"); 1026 } 1027 } 1028 1029 /*ARGSUSED*/ 1030 static int 1031 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg) 1032 { 1033 char name[MAXLINKNAMELEN]; 1034 char mediabuf[DLADM_STRSIZE]; 1035 char classbuf[DLADM_STRSIZE]; 1036 datalink_class_t class; 1037 uint32_t media; 1038 uint32_t flags; 1039 1040 if (dladm_datalink_id2info(linkid, &flags, &class, &media, name, 1041 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 1042 (void) dladm_class2str(class, classbuf); 1043 (void) dladm_media2str(media, mediabuf); 1044 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 1045 linkid, classbuf, mediabuf, flags); 1046 } 1047 return (DLADM_WALK_CONTINUE); 1048 } 1049 1050 /*ARGSUSED*/ 1051 static void 1052 do_show_linkmap(int argc, char *argv[]) 1053 { 1054 if (argc != 1) 1055 die("invalid arguments"); 1056 1057 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 1058 "CLASS", "MEDIA", "FLAGS"); 1059 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL, 1060 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1061 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1062 } 1063 1064 /* 1065 * Delete inactive physical links. 1066 */ 1067 /*ARGSUSED*/ 1068 static int 1069 purge_phys(datalink_id_t linkid, void *arg) 1070 { 1071 datalink_class_t class; 1072 uint32_t flags; 1073 1074 if (dladm_datalink_id2info(linkid, &flags, &class, NULL, 1075 NULL, 0) != DLADM_STATUS_OK) { 1076 return (DLADM_WALK_CONTINUE); 1077 } 1078 1079 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 1080 (void) dladm_phys_delete(linkid); 1081 1082 return (DLADM_WALK_CONTINUE); 1083 } 1084 1085 /*ARGSUSED*/ 1086 static void 1087 do_init_phys(int argc, char *argv[]) 1088 { 1089 di_node_t devtree; 1090 1091 if (argc > 1) 1092 usage(); 1093 1094 /* 1095 * Force all the devices to attach, therefore all the network physical 1096 * devices can be known to the dlmgmtd daemon. 1097 */ 1098 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 1099 di_fini(devtree); 1100 1101 (void) dladm_walk_datalink_id(purge_phys, NULL, 1102 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1103 } 1104 1105 static void 1106 print_link_head(show_state_t *state) 1107 { 1108 if (state->ls_donefirst) 1109 return; 1110 state->ls_donefirst = B_TRUE; 1111 1112 if (state->ls_parseable) 1113 return; 1114 1115 if (state->ls_flags & DLADM_OPT_ACTIVE) { 1116 (void) printf("%-12s%-8s%6s %-9s%s\n", "LINK", "CLASS", "MTU", 1117 "STATE", "OVER"); 1118 } else { 1119 (void) printf("%-12s%-8s%s\n", "LINK", "CLASS", "OVER"); 1120 } 1121 } 1122 1123 /* 1124 * Print the active topology information. 1125 */ 1126 static dladm_status_t 1127 print_link_topology(show_state_t *state, datalink_id_t linkid, 1128 datalink_class_t class, char **pptr, char *lim) 1129 { 1130 char *fmt; 1131 char over[MAXLINKNAMELEN]; 1132 uint32_t flags = state->ls_flags; 1133 dladm_status_t status = DLADM_STATUS_OK; 1134 1135 if (state->ls_parseable) 1136 fmt = "OVER=\"%s"; 1137 else 1138 fmt = "%s"; 1139 1140 if (class == DATALINK_CLASS_VLAN) { 1141 dladm_vlan_attr_t vinfo; 1142 1143 status = dladm_vlan_info(linkid, &vinfo, flags); 1144 if (status != DLADM_STATUS_OK) 1145 goto done; 1146 status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, 1147 NULL, over, sizeof (over)); 1148 if (status != DLADM_STATUS_OK) 1149 goto done; 1150 1151 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1152 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); 1153 } else if (class == DATALINK_CLASS_AGGR) { 1154 dladm_aggr_grp_attr_t ginfo; 1155 int i; 1156 1157 status = dladm_aggr_info(linkid, &ginfo, flags); 1158 if (status != DLADM_STATUS_OK) 1159 goto done; 1160 1161 if (ginfo.lg_nports == 0) { 1162 status = DLADM_STATUS_BADVAL; 1163 goto done; 1164 } 1165 for (i = 0; i < ginfo.lg_nports; i++) { 1166 status = dladm_datalink_id2info( 1167 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, over, 1168 sizeof (over)); 1169 if (status != DLADM_STATUS_OK) { 1170 free(ginfo.lg_ports); 1171 goto done; 1172 } 1173 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1174 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); 1175 fmt = " %s"; 1176 } 1177 free(ginfo.lg_ports); 1178 } else if (class == DATALINK_CLASS_VNIC) { 1179 dladm_vnic_attr_sys_t vinfo; 1180 1181 if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != 1182 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 1183 vinfo.va_link_id, NULL, NULL, NULL, over, 1184 sizeof (over))) != DLADM_STATUS_OK) { 1185 goto done; 1186 } 1187 1188 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1189 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); 1190 } else { 1191 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1192 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, 1193 state->ls_parseable ? "" : "--"); 1194 } 1195 if (state->ls_parseable) 1196 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\"\n"); 1197 else 1198 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\n"); 1199 1200 done: 1201 return (status); 1202 } 1203 1204 static dladm_status_t 1205 print_link(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) 1206 { 1207 char link[MAXLINKNAMELEN]; 1208 char buf[DLADM_STRSIZE]; 1209 datalink_class_t class; 1210 uint_t mtu; 1211 char *fmt; 1212 uint32_t flags; 1213 dladm_status_t status; 1214 1215 if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL, 1216 link, sizeof (link))) != DLADM_STATUS_OK) { 1217 goto done; 1218 } 1219 1220 if (!(state->ls_flags & flags)) { 1221 status = DLADM_STATUS_NOTFOUND; 1222 goto done; 1223 } 1224 1225 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1226 dladm_attr_t dlattr; 1227 1228 if (class == DATALINK_CLASS_PHYS) { 1229 dladm_phys_attr_t dpa; 1230 dlpi_handle_t dh; 1231 dlpi_info_t dlinfo; 1232 1233 if ((status = dladm_phys_info(linkid, &dpa, 1234 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1235 goto done; 1236 } 1237 1238 if (!dpa.dp_novanity) 1239 goto link_mtu; 1240 1241 /* 1242 * This is a physical link that does not have 1243 * vanity naming support. 1244 */ 1245 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 1246 DLPI_SUCCESS) { 1247 status = DLADM_STATUS_NOTFOUND; 1248 goto done; 1249 } 1250 1251 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 1252 dlpi_close(dh); 1253 status = DLADM_STATUS_BADARG; 1254 goto done; 1255 } 1256 1257 dlpi_close(dh); 1258 mtu = dlinfo.di_max_sdu; 1259 } else { 1260 link_mtu: 1261 status = dladm_info(linkid, &dlattr); 1262 if (status != DLADM_STATUS_OK) 1263 goto done; 1264 mtu = dlattr.da_max_sdu; 1265 } 1266 } 1267 1268 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1269 if (state->ls_parseable) 1270 fmt = "LINK=\"%s\" CLASS=\"%s\" MTU=\"%d\" "; 1271 else 1272 fmt = "%-12s%-8s%6d "; 1273 } else { 1274 if (state->ls_parseable) 1275 fmt = "LINK=\"%s\" CLASS=\"%s\" "; 1276 else 1277 fmt = "%-12s%-8s"; 1278 } 1279 1280 (void) dladm_class2str(class, buf); 1281 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1282 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1283 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, 1284 buf, mtu); 1285 } else { 1286 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1287 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, buf); 1288 } 1289 1290 (void) get_linkstate(link, B_TRUE, buf); 1291 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1292 if (state->ls_parseable) { 1293 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1294 "STATE=\"%s\" ", buf); 1295 } else { 1296 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1297 "%-9s", buf); 1298 } 1299 } 1300 1301 status = print_link_topology(state, linkid, class, pptr, lim); 1302 if (status != DLADM_STATUS_OK) 1303 goto done; 1304 1305 done: 1306 return (status); 1307 } 1308 1309 static int 1310 show_link(datalink_id_t linkid, void *arg) 1311 { 1312 show_state_t *state = arg; 1313 dladm_status_t status; 1314 char buf[MAXLINELEN]; 1315 char *ptr = buf, *lim = buf + MAXLINELEN; 1316 1317 status = print_link(state, linkid, &ptr, lim); 1318 if (status != DLADM_STATUS_OK) 1319 goto done; 1320 print_link_head(state); 1321 (void) printf("%s", buf); 1322 1323 done: 1324 state->ls_status = status; 1325 return (DLADM_WALK_CONTINUE); 1326 } 1327 1328 static int 1329 show_link_stats(datalink_id_t linkid, void *arg) 1330 { 1331 char link[MAXLINKNAMELEN]; 1332 datalink_class_t class; 1333 show_state_t *state = arg; 1334 pktsum_t stats, diff_stats; 1335 dladm_phys_attr_t dpa; 1336 1337 if (state->ls_firstonly) { 1338 if (state->ls_donefirst) 1339 return (DLADM_WALK_CONTINUE); 1340 state->ls_donefirst = B_TRUE; 1341 } else { 1342 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 1343 } 1344 1345 if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, 1346 sizeof (link)) != DLADM_STATUS_OK) { 1347 return (DLADM_WALK_CONTINUE); 1348 } 1349 1350 if (class == DATALINK_CLASS_PHYS) { 1351 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 1352 DLADM_STATUS_OK) { 1353 return (DLADM_WALK_CONTINUE); 1354 } 1355 if (dpa.dp_novanity) 1356 get_mac_stats(dpa.dp_dev, &stats); 1357 else 1358 get_link_stats(link, &stats); 1359 } else { 1360 get_link_stats(link, &stats); 1361 } 1362 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 1363 1364 (void) printf("%-12s", link); 1365 (void) printf("%-10llu", diff_stats.ipackets); 1366 (void) printf("%-12llu", diff_stats.rbytes); 1367 (void) printf("%-8u", diff_stats.ierrors); 1368 (void) printf("%-10llu", diff_stats.opackets); 1369 (void) printf("%-12llu", diff_stats.obytes); 1370 (void) printf("%-8u\n", diff_stats.oerrors); 1371 1372 state->ls_prevstats = stats; 1373 return (DLADM_WALK_CONTINUE); 1374 } 1375 1376 static void 1377 print_port_stat(const char *port, pktsum_t *old_stats, pktsum_t *port_stats, 1378 pktsum_t *tot_stats, char **pptr, char *lim) 1379 { 1380 pktsum_t diff_stats; 1381 1382 stats_diff(&diff_stats, port_stats, old_stats); 1383 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1384 "%-12s%-10s%8llu %8llu %8llu %8llu ", "", port, 1385 diff_stats.ipackets, diff_stats.rbytes, diff_stats.opackets, 1386 diff_stats.obytes); 1387 1388 if (tot_stats->ipackets == 0) { 1389 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s ", "--"); 1390 } else { 1391 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%% ", 1392 (double)diff_stats.ipackets/ 1393 (double)tot_stats->ipackets * 100); 1394 } 1395 1396 if (tot_stats->opackets == 0) { 1397 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s\n", "--"); 1398 } else { 1399 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%%\n", 1400 (double)diff_stats.opackets/ 1401 (double)tot_stats->opackets * 100); 1402 } 1403 1404 *old_stats = *port_stats; 1405 } 1406 1407 static void 1408 print_aggr_head(show_grp_state_t *state) 1409 { 1410 if (state->gs_donefirst) 1411 return; 1412 state->gs_donefirst = B_TRUE; 1413 1414 if (state->gs_parseable) 1415 return; 1416 1417 if (state->gs_lacp) { 1418 (void) printf("%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n", "LINK", 1419 "PORT", "AGGREGATABLE", "SYNC", "COLL", "DIST", 1420 "DEFAULTED", "EXPIRED"); 1421 } else if (state->gs_extended) { 1422 (void) printf("%-12s%-14s%6s %-9s%-9s%-18s%s\n", "LINK", 1423 "PORT", "SPEED", "DUPLEX", "STATE", "ADDRESS", "PORTSTATE"); 1424 } else if (!state->gs_stats) { 1425 (void) printf("%-12s%-8s%-24s%-13s%-11s%s\n", "LINK", "POLICY", 1426 "ADDRPOLICY", "LACPACTIVITY", "LACPTIMER", "FLAGS"); 1427 } 1428 } 1429 1430 static dladm_status_t 1431 print_aggr_info(show_grp_state_t *state, const char *link, 1432 dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) 1433 { 1434 char buf[DLADM_STRSIZE]; 1435 char *fmt; 1436 char addr_str[ETHERADDRL * 3]; 1437 char str[ETHERADDRL * 3 + 2]; 1438 1439 if (state->gs_parseable) 1440 fmt = "LINK=\"%s\" POLICY=\"%s\" ADDRPOLICY=\"%s%s\" "; 1441 else 1442 fmt = "%-12s%-8s%-6s%-18s"; 1443 1444 if (ginfop->lg_mac_fixed) { 1445 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 1446 (void) snprintf(str, ETHERADDRL * 3 + 3, " (%s)", addr_str); 1447 } else { 1448 str[0] = '\0'; 1449 } 1450 1451 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1452 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, 1453 dladm_aggr_policy2str(ginfop->lg_policy, buf), 1454 ginfop->lg_mac_fixed ? "fixed" : "auto", str); 1455 1456 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, buf); 1457 if (state->gs_parseable) { 1458 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1459 "LACPACTIVITY=\"%s\" ", buf); 1460 } else { 1461 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-13s", buf); 1462 } 1463 1464 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, buf); 1465 if (state->gs_parseable) { 1466 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1467 "LACPTIMER=\"%s\" FLAGS=\"%c----\"\n", buf, 1468 ginfop->lg_force ? 'f' : '-'); 1469 } else { 1470 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1471 "%-11s%c----\n", buf, ginfop->lg_force ? 'f' : '-'); 1472 } 1473 1474 return (DLADM_STATUS_OK); 1475 } 1476 1477 static dladm_status_t 1478 print_aggr_extended(show_grp_state_t *state, const char *link, 1479 dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) 1480 { 1481 char addr_str[ETHERADDRL * 3]; 1482 char port[MAXLINKNAMELEN]; 1483 dladm_phys_attr_t dpa; 1484 char buf[DLADM_STRSIZE]; 1485 char *fmt; 1486 int i; 1487 dladm_status_t status; 1488 1489 if (state->gs_parseable) 1490 fmt = "LINK=\"%s\" PORT=\"%s\" SPEED=\"%uMb\" DUPLEX=\"%s\" "; 1491 else 1492 fmt = "%-12s%-14s%4uMb %-9s"; 1493 1494 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 1495 1496 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1497 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, 1498 state->gs_parseable ? "" : "--", 1499 (uint_t)((get_ifspeed(link, B_TRUE)) / 1000000ull), 1500 get_linkduplex(link, B_TRUE, buf)); 1501 1502 (void) get_linkstate(link, B_TRUE, buf); 1503 if (state->gs_parseable) { 1504 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1505 "STATE=\"%s\" ADDRESS=\"%s\" PORTSTATE=\"%s\"\n", buf, 1506 addr_str, ""); 1507 } else { 1508 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-9s%-18s%s\n", 1509 buf, addr_str, "--"); 1510 } 1511 1512 for (i = 0; i < ginfop->lg_nports; i++) { 1513 dladm_aggr_port_attr_t *portp = &(ginfop->lg_ports[i]); 1514 const char *tmp; 1515 1516 if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 1517 NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { 1518 goto done; 1519 } 1520 1521 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 1522 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1523 goto done; 1524 } 1525 1526 (void) dladm_aggr_macaddr2str(portp->lp_mac, addr_str); 1527 1528 if (state->gs_parseable) 1529 tmp = link; 1530 else 1531 tmp = ""; 1532 1533 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1534 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, tmp, port, 1535 (uint_t)((get_ifspeed(dpa.dp_dev, B_FALSE)) / 1000000ull), 1536 get_linkduplex(dpa.dp_dev, B_FALSE, buf)); 1537 1538 (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); 1539 if (state->gs_parseable) { 1540 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1541 "STATE=\"%s\" ADDRESS=\"%s\" ", buf, addr_str); 1542 } else { 1543 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1544 "%-9s%-18s", buf, addr_str); 1545 } 1546 1547 (void) dladm_aggr_portstate2str( 1548 ginfop->lg_ports[i].lp_state, buf); 1549 if (state->gs_parseable) { 1550 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1551 "PORTSTATE=\"%s\"\n", buf); 1552 } else { 1553 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1554 "%s\n", buf); 1555 } 1556 } 1557 1558 status = DLADM_STATUS_OK; 1559 done: 1560 return (status); 1561 } 1562 1563 static dladm_status_t 1564 print_aggr_lacp(show_grp_state_t *state, const char *link, 1565 dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) 1566 { 1567 char port[MAXLINKNAMELEN]; 1568 char *fmt; 1569 const char *dlink = link; 1570 int i; 1571 dladm_status_t status; 1572 1573 if (state->gs_parseable) { 1574 fmt = "LINK=\"%s\" PORT=\"%s\" AGGREGATABLE=\"%s\" SYNC=\"%s\" " 1575 "COLL=\"%s\" DIST=\"%s\" DEFAULTED=\"%s\" EXPITED=\"%s\"\n"; 1576 } else { 1577 fmt = "%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n"; 1578 } 1579 1580 for (i = 0; i < ginfop->lg_nports; i++) { 1581 aggr_lacp_state_t *lstate; 1582 1583 status = dladm_datalink_id2info(ginfop->lg_ports[i].lp_linkid, 1584 NULL, NULL, NULL, port, sizeof (port)); 1585 if (status != DLADM_STATUS_OK) 1586 goto done; 1587 1588 /* 1589 * Only display link for the first port. 1590 */ 1591 if ((i > 0) && !(state->gs_parseable)) 1592 dlink = ""; 1593 lstate = &(ginfop->lg_ports[i].lp_lacp_state); 1594 1595 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1596 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, dlink, port, 1597 lstate->bit.aggregation ? "yes" : "no", 1598 lstate->bit.sync ? "yes" : "no", 1599 lstate->bit.collecting ? "yes" : "no", 1600 lstate->bit.distributing ? "yes" : "no", 1601 lstate->bit.defaulted ? "yes" : "no", 1602 lstate->bit.expired ? "yes" : "no"); 1603 } 1604 1605 status = DLADM_STATUS_OK; 1606 done: 1607 return (status); 1608 } 1609 1610 static dladm_status_t 1611 print_aggr_stats(show_grp_state_t *state, const char *link, 1612 dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) 1613 { 1614 char port[MAXLINKNAMELEN]; 1615 dladm_phys_attr_t dpa; 1616 dladm_aggr_port_attr_t *portp; 1617 pktsum_t pktsumtot, port_stat; 1618 dladm_status_t status; 1619 int i; 1620 1621 if (state->gs_firstonly) { 1622 if (state->gs_donefirst) 1623 return (DLADM_WALK_CONTINUE); 1624 state->gs_donefirst = B_TRUE; 1625 } else { 1626 bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 1627 } 1628 1629 /* sum the ports statistics */ 1630 bzero(&pktsumtot, sizeof (pktsumtot)); 1631 1632 for (i = 0; i < ginfop->lg_nports; i++) { 1633 1634 portp = &(ginfop->lg_ports[i]); 1635 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 1636 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1637 goto done; 1638 } 1639 1640 get_mac_stats(dpa.dp_dev, &port_stat); 1641 stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]); 1642 } 1643 1644 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 1645 "%-12s%-10s%8llu %8llu %8llu %8llu %8s %8s\n", link, "--", 1646 pktsumtot.ipackets, pktsumtot.rbytes, pktsumtot.opackets, 1647 pktsumtot.obytes, "--", "--"); 1648 1649 for (i = 0; i < ginfop->lg_nports; i++) { 1650 portp = &(ginfop->lg_ports[i]); 1651 1652 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 1653 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1654 goto done; 1655 } 1656 1657 get_mac_stats(dpa.dp_dev, &port_stat); 1658 1659 if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 1660 NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { 1661 goto done; 1662 } 1663 1664 print_port_stat(port, &state->gs_prevstats[i], &port_stat, 1665 &pktsumtot, pptr, lim); 1666 } 1667 1668 status = DLADM_STATUS_OK; 1669 done: 1670 return (status); 1671 } 1672 1673 static dladm_status_t 1674 print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, 1675 char *lim) 1676 { 1677 char link[MAXLINKNAMELEN]; 1678 dladm_aggr_grp_attr_t ginfo; 1679 uint32_t flags; 1680 dladm_status_t status; 1681 1682 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 1683 sizeof (link))) != DLADM_STATUS_OK) { 1684 return (status); 1685 } 1686 1687 if (!(state->gs_flags & flags)) 1688 return (DLADM_STATUS_NOTFOUND); 1689 1690 status = dladm_aggr_info(linkid, &ginfo, state->gs_flags); 1691 if (status != DLADM_STATUS_OK) 1692 return (status); 1693 1694 if (state->gs_lacp) 1695 status = print_aggr_lacp(state, link, &ginfo, pptr, lim); 1696 else if (state->gs_extended) 1697 status = print_aggr_extended(state, link, &ginfo, pptr, lim); 1698 else if (state->gs_stats) 1699 status = print_aggr_stats(state, link, &ginfo, pptr, lim); 1700 else 1701 status = print_aggr_info(state, link, &ginfo, pptr, lim); 1702 1703 done: 1704 free(ginfo.lg_ports); 1705 return (status); 1706 } 1707 1708 static int 1709 show_aggr(datalink_id_t linkid, void *arg) 1710 { 1711 show_grp_state_t *state = arg; 1712 dladm_status_t status; 1713 char buf[MAXLINELEN]; 1714 char *ptr = buf, *lim = buf + MAXLINELEN; 1715 1716 status = print_aggr(state, linkid, &ptr, lim); 1717 if (status != DLADM_STATUS_OK) 1718 goto done; 1719 print_aggr_head(state); 1720 (void) printf("%s", buf); 1721 1722 done: 1723 state->gs_status = status; 1724 return (DLADM_WALK_CONTINUE); 1725 } 1726 1727 static int 1728 kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 1729 { 1730 kstat_named_t *knp; 1731 1732 if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 1733 return (-1); 1734 1735 if (knp->data_type != type) 1736 return (-1); 1737 1738 switch (type) { 1739 case KSTAT_DATA_UINT64: 1740 *(uint64_t *)buf = knp->value.ui64; 1741 break; 1742 case KSTAT_DATA_UINT32: 1743 *(uint32_t *)buf = knp->value.ui32; 1744 break; 1745 default: 1746 return (-1); 1747 } 1748 1749 return (0); 1750 } 1751 1752 static int 1753 show_dev(const char *dev, void *arg) 1754 { 1755 show_state_t *state = arg; 1756 char buf[DLADM_STRSIZE]; 1757 char *fmt; 1758 1759 if (state->ls_parseable) 1760 fmt = "DEV=\"%s\" STATE=\"%s\" SPEED=\"%u\" "; 1761 else 1762 fmt = "%-12s%-10s%4uMb "; 1763 1764 if (!state->ls_donefirst) { 1765 if (!state->ls_parseable) { 1766 (void) printf("%-12s%-10s%6s %s\n", "DEV", "STATE", 1767 "SPEED", "DUPLEX"); 1768 } 1769 state->ls_donefirst = B_TRUE; 1770 } 1771 1772 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 1773 (void) printf(fmt, dev, get_linkstate(dev, B_FALSE, buf), 1774 (uint_t)(get_ifspeed(dev, B_FALSE) / 1000000ull)); 1775 1776 (void) get_linkduplex(dev, B_FALSE, buf); 1777 if (state->ls_parseable) 1778 (void) printf("DUPLEX=\"%s\"\n", buf); 1779 else 1780 (void) printf("%s\n", buf); 1781 1782 return (DLADM_WALK_CONTINUE); 1783 } 1784 1785 static int 1786 show_dev_stats(const char *dev, void *arg) 1787 { 1788 show_state_t *state = arg; 1789 pktsum_t stats, diff_stats; 1790 1791 if (state->ls_firstonly) { 1792 if (state->ls_donefirst) 1793 return (DLADM_WALK_CONTINUE); 1794 state->ls_donefirst = B_TRUE; 1795 } else { 1796 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 1797 } 1798 1799 get_mac_stats(dev, &stats); 1800 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 1801 1802 (void) printf("%-12s", dev); 1803 (void) printf("%-10llu", diff_stats.ipackets); 1804 (void) printf("%-12llu", diff_stats.rbytes); 1805 (void) printf("%-8u", diff_stats.ierrors); 1806 (void) printf("%-10llu", diff_stats.opackets); 1807 (void) printf("%-12llu", diff_stats.obytes); 1808 (void) printf("%-8u\n", diff_stats.oerrors); 1809 1810 state->ls_prevstats = stats; 1811 return (DLADM_WALK_CONTINUE); 1812 } 1813 1814 static void 1815 do_show_link(int argc, char *argv[]) 1816 { 1817 int option; 1818 boolean_t s_arg = B_FALSE; 1819 boolean_t i_arg = B_FALSE; 1820 uint32_t flags = DLADM_OPT_ACTIVE; 1821 boolean_t p_arg = B_FALSE; 1822 datalink_id_t linkid = DATALINK_ALL_LINKID; 1823 int interval = 0; 1824 show_state_t state; 1825 dladm_status_t status; 1826 1827 opterr = 0; 1828 while ((option = getopt_long(argc, argv, ":pPsi:", 1829 show_lopts, NULL)) != -1) { 1830 switch (option) { 1831 case 'p': 1832 if (p_arg) 1833 die_optdup(option); 1834 1835 p_arg = B_TRUE; 1836 break; 1837 case 's': 1838 if (s_arg) 1839 die_optdup(option); 1840 1841 s_arg = B_TRUE; 1842 break; 1843 case 'P': 1844 if (flags != DLADM_OPT_ACTIVE) 1845 die_optdup(option); 1846 1847 flags = DLADM_OPT_PERSIST; 1848 break; 1849 case 'i': 1850 if (i_arg) 1851 die_optdup(option); 1852 1853 i_arg = B_TRUE; 1854 if (!str2int(optarg, &interval) || interval == 0) 1855 die("invalid interval value '%s'", optarg); 1856 break; 1857 default: 1858 die_opterr(optopt, option); 1859 break; 1860 } 1861 } 1862 1863 if (i_arg && !s_arg) 1864 die("the option -i can be used only with -s"); 1865 1866 if (s_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 1867 die("the option -%c cannot be used with -s", p_arg ? 'p' : 'P'); 1868 1869 /* get link name (optional last argument) */ 1870 if (optind == (argc-1)) { 1871 uint32_t f; 1872 1873 if ((status = dladm_name2info(argv[optind], &linkid, &f, 1874 NULL, NULL)) != DLADM_STATUS_OK) { 1875 die_dlerr(status, "link %s is not valid", argv[optind]); 1876 } 1877 1878 if (!(f & flags)) { 1879 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 1880 argv[optind], flags == DLADM_OPT_PERSIST ? 1881 "a temporary link" : "temporarily removed"); 1882 } 1883 } else if (optind != argc) { 1884 usage(); 1885 } 1886 1887 if (s_arg) { 1888 link_stats(linkid, interval); 1889 return; 1890 } 1891 1892 state.ls_parseable = p_arg; 1893 state.ls_flags = flags; 1894 state.ls_donefirst = B_FALSE; 1895 if (linkid == DATALINK_ALL_LINKID) { 1896 (void) dladm_walk_datalink_id(show_link, &state, 1897 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 1898 } else { 1899 (void) show_link(linkid, &state); 1900 if (state.ls_status != DLADM_STATUS_OK) { 1901 die_dlerr(state.ls_status, "failed to show link %s", 1902 argv[optind]); 1903 } 1904 } 1905 } 1906 1907 static void 1908 do_show_aggr(int argc, char *argv[]) 1909 { 1910 boolean_t L_arg = B_FALSE; 1911 boolean_t s_arg = B_FALSE; 1912 boolean_t i_arg = B_FALSE; 1913 boolean_t p_arg = B_FALSE; 1914 boolean_t x_arg = B_FALSE; 1915 show_grp_state_t state; 1916 uint32_t flags = DLADM_OPT_ACTIVE; 1917 datalink_id_t linkid = DATALINK_ALL_LINKID; 1918 int option; 1919 int interval = 0; 1920 int key; 1921 dladm_status_t status; 1922 1923 opterr = 0; 1924 while ((option = getopt_long(argc, argv, ":LpPxsi:", 1925 show_lopts, NULL)) != -1) { 1926 switch (option) { 1927 case 'L': 1928 if (L_arg) 1929 die_optdup(option); 1930 1931 L_arg = B_TRUE; 1932 break; 1933 case 'p': 1934 if (p_arg) 1935 die_optdup(option); 1936 1937 p_arg = B_TRUE; 1938 break; 1939 case 'x': 1940 if (x_arg) 1941 die_optdup(option); 1942 1943 x_arg = B_TRUE; 1944 break; 1945 case 'P': 1946 if (flags != DLADM_OPT_ACTIVE) 1947 die_optdup(option); 1948 1949 flags = DLADM_OPT_PERSIST; 1950 break; 1951 case 's': 1952 if (s_arg) 1953 die_optdup(option); 1954 1955 s_arg = B_TRUE; 1956 break; 1957 case 'i': 1958 if (i_arg) 1959 die_optdup(option); 1960 1961 i_arg = B_TRUE; 1962 if (!str2int(optarg, &interval) || interval == 0) 1963 die("invalid interval value '%s'", optarg); 1964 break; 1965 default: 1966 die_opterr(optopt, option); 1967 break; 1968 } 1969 } 1970 1971 if (i_arg && !s_arg) 1972 die("the option -i can be used only with -s"); 1973 1974 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 1975 die("the option -%c cannot be used with -s", 1976 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 1977 } 1978 1979 if (L_arg && flags != DLADM_OPT_ACTIVE) 1980 die("the option -P cannot be used with -L"); 1981 1982 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 1983 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 1984 1985 /* get aggregation key or aggrname (optional last argument) */ 1986 if (optind == (argc-1)) { 1987 if (!str2int(argv[optind], &key)) { 1988 status = dladm_name2info(argv[optind], &linkid, NULL, 1989 NULL, NULL); 1990 } else { 1991 status = dladm_key2linkid((uint16_t)key, 1992 &linkid, DLADM_OPT_ACTIVE); 1993 } 1994 1995 if (status != DLADM_STATUS_OK) 1996 die("non-existent aggregation '%s'", argv[optind]); 1997 1998 } else if (optind != argc) { 1999 usage(); 2000 } 2001 2002 bzero(&state, sizeof (state)); 2003 state.gs_lacp = L_arg; 2004 state.gs_stats = s_arg; 2005 state.gs_flags = flags; 2006 state.gs_parseable = p_arg; 2007 state.gs_extended = x_arg; 2008 2009 if (s_arg) { 2010 aggr_stats(linkid, &state, interval); 2011 return; 2012 } 2013 2014 if (linkid == DATALINK_ALL_LINKID) { 2015 (void) dladm_walk_datalink_id(show_aggr, &state, 2016 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 2017 } else { 2018 (void) show_aggr(linkid, &state); 2019 if (state.gs_status != DLADM_STATUS_OK) { 2020 die_dlerr(state.gs_status, "failed to show aggr %s", 2021 argv[optind]); 2022 } 2023 } 2024 } 2025 2026 static void 2027 do_show_dev(int argc, char *argv[]) 2028 { 2029 int option; 2030 char *dev = NULL; 2031 boolean_t s_arg = B_FALSE; 2032 boolean_t i_arg = B_FALSE; 2033 boolean_t p_arg = B_FALSE; 2034 datalink_id_t linkid; 2035 int interval = 0; 2036 show_state_t state; 2037 2038 opterr = 0; 2039 while ((option = getopt_long(argc, argv, ":psi:", 2040 show_lopts, NULL)) != -1) { 2041 switch (option) { 2042 case 'p': 2043 if (p_arg) 2044 die_optdup(option); 2045 2046 p_arg = B_TRUE; 2047 break; 2048 case 's': 2049 if (s_arg) 2050 die_optdup(option); 2051 2052 s_arg = B_TRUE; 2053 break; 2054 case 'i': 2055 if (i_arg) 2056 die_optdup(option); 2057 2058 i_arg = B_TRUE; 2059 if (!str2int(optarg, &interval) || interval == 0) 2060 die("invalid interval value '%s'", optarg); 2061 break; 2062 default: 2063 die_opterr(optopt, option); 2064 break; 2065 } 2066 } 2067 2068 if (i_arg && !s_arg) 2069 die("the option -i can be used only with -s"); 2070 2071 if (s_arg && p_arg) 2072 die("the option -s cannot be used with -p"); 2073 2074 /* get dev name (optional last argument) */ 2075 if (optind == (argc-1)) { 2076 uint32_t flags; 2077 2078 dev = argv[optind]; 2079 2080 if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK) 2081 die("invalid device %s", dev); 2082 2083 if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL, 2084 NULL, 0) != DLADM_STATUS_OK) || 2085 !(flags & DLADM_OPT_ACTIVE)) { 2086 die("device %s has been removed", dev); 2087 } 2088 } else if (optind != argc) { 2089 usage(); 2090 } 2091 2092 if (s_arg) { 2093 dev_stats(dev, interval); 2094 return; 2095 } 2096 2097 state.ls_donefirst = B_FALSE; 2098 state.ls_parseable = p_arg; 2099 if (dev == NULL) { 2100 (void) dladm_mac_walk(show_dev, &state); 2101 } else { 2102 (void) show_dev(dev, &state); 2103 } 2104 } 2105 2106 static void 2107 print_phys_head(show_state_t *state) 2108 { 2109 if (state->ls_donefirst) 2110 return; 2111 state->ls_donefirst = B_TRUE; 2112 2113 if (state->ls_parseable) 2114 return; 2115 2116 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2117 (void) printf("%-12s%-20s%-10s%6s %-9s%s\n", "LINK", 2118 "MEDIA", "STATE", "SPEED", "DUPLEX", "DEVICE"); 2119 } else { 2120 (void) printf("%-12s%-12s%-20s%s\n", "LINK", "DEVICE", 2121 "MEDIA", "FLAGS"); 2122 } 2123 } 2124 2125 static dladm_status_t 2126 print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) 2127 { 2128 char link[MAXLINKNAMELEN]; 2129 dladm_phys_attr_t dpa; 2130 char buf[DLADM_STRSIZE]; 2131 uint32_t flags; 2132 datalink_class_t class; 2133 uint32_t media; 2134 dladm_status_t status; 2135 2136 if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, 2137 link, sizeof (link))) != DLADM_STATUS_OK) { 2138 goto done; 2139 } 2140 2141 if (class != DATALINK_CLASS_PHYS) { 2142 status = DLADM_STATUS_BADARG; 2143 goto done; 2144 } 2145 2146 if (!(state->ls_flags & flags)) { 2147 status = DLADM_STATUS_NOTFOUND; 2148 goto done; 2149 } 2150 2151 status = dladm_phys_info(linkid, &dpa, state->ls_flags); 2152 if (status != DLADM_STATUS_OK) 2153 goto done; 2154 2155 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2156 char name[MAXLINKNAMELEN]; 2157 boolean_t islink; 2158 2159 if (!dpa.dp_novanity) { 2160 (void) strlcpy(name, link, sizeof (name)); 2161 islink = B_TRUE; 2162 } else { 2163 /* 2164 * This is a physical link that does not have 2165 * vanity naming support. 2166 */ 2167 (void) strlcpy(name, dpa.dp_dev, sizeof (name)); 2168 islink = B_FALSE; 2169 } 2170 2171 if (state->ls_parseable) { 2172 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2173 "LINK=\"%s\" MEDIA=\"%s\" ", link, 2174 dladm_media2str(media, buf)); 2175 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2176 "STATE=\"%s\" SPEED=\"%uMb\" ", 2177 get_linkstate(name, islink, buf), 2178 (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); 2179 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2180 "DUPLEX=\"%s\" DEVICE=\"%s\"\n", 2181 get_linkduplex(name, islink, buf), dpa.dp_dev); 2182 } else { 2183 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2184 "%-12s%-20s", link, 2185 dladm_media2str(media, buf)); 2186 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2187 "%-10s%4uMb ", 2188 get_linkstate(name, islink, buf), 2189 (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); 2190 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2191 "%-9s%s\n", get_linkduplex(name, islink, buf), 2192 dpa.dp_dev); 2193 } 2194 } else { 2195 if (state->ls_parseable) { 2196 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2197 "LINK=\"%s\" DEVICE=\"%s\" MEDIA=\"%s\" " 2198 "FLAGS=\"%c----\"\n", link, dpa.dp_dev, 2199 dladm_media2str(media, buf), 2200 flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 2201 } else { 2202 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), 2203 "%-12s%-12s%-20s%c----\n", link, 2204 dpa.dp_dev, dladm_media2str(media, buf), 2205 flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 2206 } 2207 } 2208 2209 done: 2210 return (status); 2211 } 2212 2213 static int 2214 show_phys(datalink_id_t linkid, void *arg) 2215 { 2216 show_state_t *state = arg; 2217 dladm_status_t status; 2218 char buf[MAXLINELEN]; 2219 char *ptr = buf, *lim = buf + MAXLINELEN; 2220 2221 status = print_phys(state, linkid, &ptr, lim); 2222 if (status != DLADM_STATUS_OK) 2223 goto done; 2224 print_phys_head(state); 2225 (void) printf("%s", buf); 2226 2227 done: 2228 state->ls_status = status; 2229 return (DLADM_WALK_CONTINUE); 2230 } 2231 2232 static void 2233 print_vlan_head(show_state_t *state) 2234 { 2235 if (state->ls_donefirst) 2236 return; 2237 state->ls_donefirst = B_TRUE; 2238 2239 if (state->ls_parseable) 2240 return; 2241 2242 (void) printf("%-12s%5s %-12s%s\n", "LINK", "VID", "OVER", "FLAGS"); 2243 } 2244 2245 /* 2246 * Print the active topology information. 2247 */ 2248 static dladm_status_t 2249 print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) 2250 { 2251 char link[MAXLINKNAMELEN]; 2252 char over[MAXLINKNAMELEN]; 2253 char *fmt; 2254 dladm_vlan_attr_t vinfo; 2255 uint32_t flags; 2256 dladm_status_t status; 2257 2258 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 2259 sizeof (link))) != DLADM_STATUS_OK) { 2260 goto done; 2261 } 2262 2263 if (!(state->ls_flags & flags)) { 2264 status = DLADM_STATUS_NOTFOUND; 2265 goto done; 2266 } 2267 2268 if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != 2269 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 2270 vinfo.dv_linkid, NULL, NULL, NULL, over, sizeof (over))) != 2271 DLADM_STATUS_OK) { 2272 goto done; 2273 } 2274 2275 if (state->ls_parseable) 2276 fmt = "LINK=\"%s\" VID=\"%d\" OVER=\"%s\" FLAGS=\"%c%c---\"\n"; 2277 else 2278 fmt = "%-12s%5d %-12s%c%c---\n"; 2279 /*LINTED: E_SEC_PRINTF_VAR_FMT*/ 2280 *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, 2281 vinfo.dv_vid, over, vinfo.dv_force ? 'f' : '-', 2282 vinfo.dv_implicit ? 'i' : '-'); 2283 2284 done: 2285 return (status); 2286 } 2287 2288 static int 2289 show_vlan(datalink_id_t linkid, void *arg) 2290 { 2291 show_state_t *state = arg; 2292 dladm_status_t status; 2293 char buf[MAXLINELEN]; 2294 char *ptr = buf, *lim = buf + MAXLINELEN; 2295 2296 status = print_vlan(state, linkid, &ptr, lim); 2297 if (status != DLADM_STATUS_OK) 2298 goto done; 2299 print_vlan_head(state); 2300 (void) printf("%s", buf); 2301 2302 done: 2303 state->ls_status = status; 2304 return (DLADM_WALK_CONTINUE); 2305 } 2306 2307 static void 2308 do_show_phys(int argc, char *argv[]) 2309 { 2310 int option; 2311 uint32_t flags = DLADM_OPT_ACTIVE; 2312 boolean_t p_arg = B_FALSE; 2313 datalink_id_t linkid = DATALINK_ALL_LINKID; 2314 show_state_t state; 2315 dladm_status_t status; 2316 2317 opterr = 0; 2318 while ((option = getopt_long(argc, argv, ":pP", 2319 show_lopts, NULL)) != -1) { 2320 switch (option) { 2321 case 'p': 2322 if (p_arg) 2323 die_optdup(option); 2324 2325 p_arg = B_TRUE; 2326 break; 2327 case 'P': 2328 if (flags != DLADM_OPT_ACTIVE) 2329 die_optdup(option); 2330 2331 flags = DLADM_OPT_PERSIST; 2332 break; 2333 default: 2334 die_opterr(optopt, option); 2335 break; 2336 } 2337 } 2338 2339 /* get link name (optional last argument) */ 2340 if (optind == (argc-1)) { 2341 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 2342 NULL, NULL)) != DLADM_STATUS_OK) { 2343 die_dlerr(status, "link %s is not valid", argv[optind]); 2344 } 2345 } else if (optind != argc) { 2346 usage(); 2347 } 2348 2349 state.ls_parseable = p_arg; 2350 state.ls_flags = flags; 2351 state.ls_donefirst = B_FALSE; 2352 2353 if (linkid == DATALINK_ALL_LINKID) { 2354 (void) dladm_walk_datalink_id(show_phys, &state, 2355 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 2356 } else { 2357 (void) show_phys(linkid, &state); 2358 if (state.ls_status != DLADM_STATUS_OK) { 2359 die_dlerr(state.ls_status, 2360 "failed to show physical link %s", argv[optind]); 2361 } 2362 } 2363 } 2364 2365 static void 2366 do_show_vlan(int argc, char *argv[]) 2367 { 2368 int option; 2369 uint32_t flags = DLADM_OPT_ACTIVE; 2370 boolean_t p_arg = B_FALSE; 2371 datalink_id_t linkid = DATALINK_ALL_LINKID; 2372 show_state_t state; 2373 dladm_status_t status; 2374 2375 opterr = 0; 2376 while ((option = getopt_long(argc, argv, ":pP", 2377 show_lopts, NULL)) != -1) { 2378 switch (option) { 2379 case 'p': 2380 if (p_arg) 2381 die_optdup(option); 2382 2383 p_arg = B_TRUE; 2384 break; 2385 case 'P': 2386 if (flags != DLADM_OPT_ACTIVE) 2387 die_optdup(option); 2388 2389 flags = DLADM_OPT_PERSIST; 2390 break; 2391 default: 2392 die_opterr(optopt, option); 2393 break; 2394 } 2395 } 2396 2397 /* get link name (optional last argument) */ 2398 if (optind == (argc-1)) { 2399 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 2400 NULL, NULL)) != DLADM_STATUS_OK) { 2401 die_dlerr(status, "link %s is not valid", argv[optind]); 2402 } 2403 } else if (optind != argc) { 2404 usage(); 2405 } 2406 2407 state.ls_parseable = p_arg; 2408 state.ls_flags = flags; 2409 state.ls_donefirst = B_FALSE; 2410 2411 if (linkid == DATALINK_ALL_LINKID) { 2412 (void) dladm_walk_datalink_id(show_vlan, &state, 2413 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 2414 } else { 2415 (void) show_vlan(linkid, &state); 2416 if (state.ls_status != DLADM_STATUS_OK) { 2417 die_dlerr(state.ls_status, "failed to show vlan %s", 2418 argv[optind]); 2419 } 2420 } 2421 } 2422 2423 static void 2424 link_stats(datalink_id_t linkid, uint_t interval) 2425 { 2426 show_state_t state; 2427 2428 bzero(&state, sizeof (state)); 2429 2430 /* 2431 * If an interval is specified, continuously show the stats 2432 * only for the first MAC port. 2433 */ 2434 state.ls_firstonly = (interval != 0); 2435 2436 for (;;) { 2437 (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", 2438 "LINK", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", 2439 "OBYTES", "OERRORS"); 2440 2441 state.ls_donefirst = B_FALSE; 2442 if (linkid == DATALINK_ALL_LINKID) { 2443 (void) dladm_walk_datalink_id(show_link_stats, &state, 2444 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2445 DLADM_OPT_ACTIVE); 2446 } else { 2447 (void) show_link_stats(linkid, &state); 2448 } 2449 2450 if (interval == 0) 2451 break; 2452 2453 (void) sleep(interval); 2454 } 2455 } 2456 2457 static void 2458 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 2459 { 2460 /* 2461 * If an interval is specified, continuously show the stats 2462 * only for the first group. 2463 */ 2464 state->gs_firstonly = (interval != 0); 2465 2466 for (;;) { 2467 2468 (void) printf("%-12s%-10s%8s %8s %8s %8s %-9s%s\n", 2469 "LINK", "PORT", "IPACKETS", "RBYTES", "OPACKETS", 2470 "OBYTES", "IPKTDIST", "OPKTDIST"); 2471 2472 state->gs_donefirst = B_FALSE; 2473 if (linkid == DATALINK_ALL_LINKID) 2474 (void) dladm_walk_datalink_id(show_aggr, state, 2475 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 2476 DLADM_OPT_ACTIVE); 2477 else 2478 (void) show_aggr(linkid, state); 2479 2480 if (interval == 0) 2481 break; 2482 2483 (void) sleep(interval); 2484 } 2485 } 2486 2487 static void 2488 dev_stats(const char *dev, uint32_t interval) 2489 { 2490 show_state_t state; 2491 2492 bzero(&state, sizeof (state)); 2493 2494 /* 2495 * If an interval is specified, continuously show the stats 2496 * only for the first MAC port. 2497 */ 2498 state.ls_firstonly = (interval != 0); 2499 2500 for (;;) { 2501 2502 (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", 2503 "DEV", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", 2504 "OBYTES", "OERRORS"); 2505 2506 state.ls_donefirst = B_FALSE; 2507 if (dev == NULL) 2508 (void) dladm_mac_walk(show_dev_stats, &state); 2509 else 2510 (void) show_dev_stats(dev, &state); 2511 2512 if (interval == 0) 2513 break; 2514 2515 (void) sleep(interval); 2516 } 2517 2518 if (dev != NULL && state.ls_status != DLADM_STATUS_OK) 2519 die_dlerr(state.ls_status, "cannot show device '%s'", dev); 2520 } 2521 2522 /* accumulate stats (s1 += (s2 - s3)) */ 2523 static void 2524 stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 2525 { 2526 s1->ipackets += (s2->ipackets - s3->ipackets); 2527 s1->opackets += (s2->opackets - s3->opackets); 2528 s1->rbytes += (s2->rbytes - s3->rbytes); 2529 s1->obytes += (s2->obytes - s3->obytes); 2530 s1->ierrors += (s2->ierrors - s3->ierrors); 2531 s1->oerrors += (s2->oerrors - s3->oerrors); 2532 } 2533 2534 /* compute stats differences (s1 = s2 - s3) */ 2535 static void 2536 stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 2537 { 2538 s1->ipackets = s2->ipackets - s3->ipackets; 2539 s1->opackets = s2->opackets - s3->opackets; 2540 s1->rbytes = s2->rbytes - s3->rbytes; 2541 s1->obytes = s2->obytes - s3->obytes; 2542 s1->ierrors = s2->ierrors - s3->ierrors; 2543 s1->oerrors = s2->oerrors - s3->oerrors; 2544 } 2545 2546 static void 2547 get_stats(char *module, int instance, const char *name, pktsum_t *stats) 2548 { 2549 kstat_ctl_t *kcp; 2550 kstat_t *ksp; 2551 2552 if ((kcp = kstat_open()) == NULL) { 2553 warn("kstat open operation failed"); 2554 return; 2555 } 2556 2557 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 2558 /* 2559 * The kstat query could fail if the underlying MAC 2560 * driver was already detached. 2561 */ 2562 (void) kstat_close(kcp); 2563 return; 2564 } 2565 2566 if (kstat_read(kcp, ksp, NULL) == -1) 2567 goto bail; 2568 2569 if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 2570 &stats->ipackets) < 0) 2571 goto bail; 2572 2573 if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 2574 &stats->opackets) < 0) 2575 goto bail; 2576 2577 if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 2578 &stats->rbytes) < 0) 2579 goto bail; 2580 2581 if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 2582 &stats->obytes) < 0) 2583 goto bail; 2584 2585 if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 2586 &stats->ierrors) < 0) 2587 goto bail; 2588 2589 if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 2590 &stats->oerrors) < 0) 2591 goto bail; 2592 2593 bail: 2594 (void) kstat_close(kcp); 2595 return; 2596 2597 } 2598 2599 static void 2600 get_mac_stats(const char *dev, pktsum_t *stats) 2601 { 2602 char module[DLPI_LINKNAME_MAX]; 2603 uint_t instance; 2604 2605 bzero(stats, sizeof (*stats)); 2606 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 2607 return; 2608 2609 get_stats(module, instance, "mac", stats); 2610 } 2611 2612 static void 2613 get_link_stats(const char *link, pktsum_t *stats) 2614 { 2615 bzero(stats, sizeof (*stats)); 2616 get_stats("link", 0, link, stats); 2617 } 2618 2619 static int 2620 query_kstat(char *module, int instance, const char *name, const char *stat, 2621 uint8_t type, void *val) 2622 { 2623 kstat_ctl_t *kcp; 2624 kstat_t *ksp; 2625 2626 if ((kcp = kstat_open()) == NULL) { 2627 warn("kstat open operation failed"); 2628 return (-1); 2629 } 2630 2631 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 2632 /* 2633 * The kstat query could fail if the underlying MAC 2634 * driver was already detached. 2635 */ 2636 goto bail; 2637 } 2638 2639 if (kstat_read(kcp, ksp, NULL) == -1) { 2640 warn("kstat read failed"); 2641 goto bail; 2642 } 2643 2644 if (kstat_value(ksp, stat, type, val) < 0) 2645 goto bail; 2646 2647 (void) kstat_close(kcp); 2648 return (0); 2649 2650 bail: 2651 (void) kstat_close(kcp); 2652 return (-1); 2653 } 2654 2655 static int 2656 get_one_kstat(const char *name, const char *stat, uint8_t type, 2657 void *val, boolean_t islink) 2658 { 2659 char module[DLPI_LINKNAME_MAX]; 2660 uint_t instance; 2661 2662 if (islink) { 2663 return (query_kstat("link", 0, name, stat, type, val)); 2664 } else { 2665 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 2666 return (-1); 2667 2668 return (query_kstat(module, instance, "mac", stat, type, val)); 2669 } 2670 } 2671 2672 static uint64_t 2673 get_ifspeed(const char *name, boolean_t islink) 2674 { 2675 uint64_t ifspeed = 0; 2676 2677 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 2678 &ifspeed, islink); 2679 2680 return (ifspeed); 2681 } 2682 2683 static const char * 2684 get_linkstate(const char *name, boolean_t islink, char *buf) 2685 { 2686 link_state_t linkstate; 2687 2688 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 2689 &linkstate, islink) != 0) { 2690 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 2691 return (buf); 2692 } 2693 return (dladm_linkstate2str(linkstate, buf)); 2694 } 2695 2696 static const char * 2697 get_linkduplex(const char *name, boolean_t islink, char *buf) 2698 { 2699 link_duplex_t linkduplex; 2700 2701 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 2702 &linkduplex, islink) != 0) { 2703 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 2704 return (buf); 2705 } 2706 2707 return (dladm_linkduplex2str(linkduplex, buf)); 2708 } 2709 2710 #define WIFI_CMD_SCAN 0x00000001 2711 #define WIFI_CMD_SHOW 0x00000002 2712 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 2713 typedef struct wifi_field { 2714 const char *wf_name; 2715 const char *wf_header; 2716 uint_t wf_width; 2717 uint_t wf_mask; 2718 uint_t wf_cmdtype; 2719 } wifi_field_t; 2720 2721 static wifi_field_t wifi_fields[] = { 2722 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 2723 { "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 2724 { "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 2725 { "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 2726 { "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 2727 { "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 2728 { "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 2729 { "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 2730 { "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 2731 { "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, 2732 { "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 2733 ; 2734 2735 static char *all_scan_wifi_fields = 2736 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 2737 static char *all_show_wifi_fields = 2738 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 2739 static char *def_scan_wifi_fields = 2740 "link,essid,bssid,sec,strength,mode,speed"; 2741 static char *def_show_wifi_fields = 2742 "link,status,essid,sec,strength,mode,speed"; 2743 2744 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 2745 #define WIFI_MAX_FIELD_LEN 32 2746 2747 typedef struct { 2748 char *s_buf; 2749 char **s_fields; /* array of pointer to the fields in s_buf */ 2750 uint_t s_nfields; /* the number of fields in s_buf */ 2751 } split_t; 2752 2753 /* 2754 * Free the split_t structure pointed to by `sp'. 2755 */ 2756 static void 2757 splitfree(split_t *sp) 2758 { 2759 free(sp->s_buf); 2760 free(sp->s_fields); 2761 free(sp); 2762 } 2763 2764 /* 2765 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 2766 * length. Return a pointer to a split_t containing the split fields, or NULL 2767 * on failure. 2768 */ 2769 static split_t * 2770 split(const char *str, uint_t maxfields, uint_t maxlen) 2771 { 2772 char *field, *token, *lasts = NULL; 2773 split_t *sp; 2774 2775 if (*str == '\0' || maxfields == 0 || maxlen == 0) 2776 return (NULL); 2777 2778 sp = calloc(sizeof (split_t), 1); 2779 if (sp == NULL) 2780 return (NULL); 2781 2782 sp->s_buf = strdup(str); 2783 sp->s_fields = malloc(sizeof (char *) * maxfields); 2784 if (sp->s_buf == NULL || sp->s_fields == NULL) 2785 goto fail; 2786 2787 token = sp->s_buf; 2788 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 2789 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 2790 goto fail; 2791 token = NULL; 2792 sp->s_fields[sp->s_nfields++] = field; 2793 } 2794 return (sp); 2795 fail: 2796 splitfree(sp); 2797 return (NULL); 2798 } 2799 2800 static int 2801 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 2802 uint_t cmdtype) 2803 { 2804 uint_t i, j; 2805 wifi_field_t **wf = NULL; 2806 split_t *sp; 2807 boolean_t good_match = B_FALSE; 2808 2809 if (cmdtype == WIFI_CMD_SCAN) { 2810 if (str == NULL) 2811 str = def_scan_wifi_fields; 2812 if (strcasecmp(str, "all") == 0) 2813 str = all_scan_wifi_fields; 2814 } else if (cmdtype == WIFI_CMD_SHOW) { 2815 if (str == NULL) 2816 str = def_show_wifi_fields; 2817 if (strcasecmp(str, "all") == 0) 2818 str = all_show_wifi_fields; 2819 } else { 2820 return (-1); 2821 } 2822 2823 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 2824 if (sp == NULL) 2825 return (-1); 2826 2827 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 2828 if (wf == NULL) 2829 goto fail; 2830 2831 for (i = 0; i < sp->s_nfields; i++) { 2832 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 2833 if (strcasecmp(sp->s_fields[i], 2834 wifi_fields[j].wf_name) == 0) { 2835 good_match = wifi_fields[j]. 2836 wf_cmdtype & cmdtype; 2837 break; 2838 } 2839 } 2840 if (!good_match) 2841 goto fail; 2842 2843 good_match = B_FALSE; 2844 wf[i] = &wifi_fields[j]; 2845 } 2846 *countp = i; 2847 *fields = wf; 2848 splitfree(sp); 2849 return (0); 2850 fail: 2851 free(wf); 2852 splitfree(sp); 2853 return (-1); 2854 } 2855 2856 typedef struct print_wifi_state { 2857 char *ws_link; 2858 boolean_t ws_parseable; 2859 boolean_t ws_header; 2860 wifi_field_t **ws_fields; 2861 uint_t ws_nfields; 2862 boolean_t ws_lastfield; 2863 uint_t ws_overflow; 2864 } print_wifi_state_t; 2865 2866 static void 2867 print_wifi_head(print_wifi_state_t *statep) 2868 { 2869 int i; 2870 wifi_field_t *wfp; 2871 2872 for (i = 0; i < statep->ws_nfields; i++) { 2873 wfp = statep->ws_fields[i]; 2874 if (i + 1 < statep->ws_nfields) 2875 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 2876 else 2877 (void) printf("%s", wfp->wf_header); 2878 } 2879 (void) printf("\n"); 2880 } 2881 2882 static void 2883 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 2884 const char *value) 2885 { 2886 uint_t width = wfp->wf_width; 2887 uint_t valwidth = strlen(value); 2888 uint_t compress; 2889 2890 if (statep->ws_parseable) { 2891 (void) printf("%s=\"%s\"", wfp->wf_header, value); 2892 } else { 2893 if (value[0] == '\0') 2894 value = "--"; 2895 if (statep->ws_lastfield) { 2896 (void) printf("%s", value); 2897 return; 2898 } 2899 2900 if (valwidth > width) { 2901 statep->ws_overflow += valwidth - width; 2902 } else if (valwidth < width && statep->ws_overflow > 0) { 2903 compress = min(statep->ws_overflow, width - valwidth); 2904 statep->ws_overflow -= compress; 2905 width -= compress; 2906 } 2907 (void) printf("%-*s", width, value); 2908 } 2909 2910 if (!statep->ws_lastfield) 2911 (void) putchar(' '); 2912 } 2913 2914 static void 2915 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 2916 dladm_wlan_attr_t *attrp) 2917 { 2918 char buf[DLADM_STRSIZE]; 2919 const char *str = ""; 2920 2921 if (wfp->wf_mask == 0) { 2922 print_wifi_field(statep, wfp, statep->ws_link); 2923 return; 2924 } 2925 2926 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 2927 print_wifi_field(statep, wfp, ""); 2928 return; 2929 } 2930 2931 switch (wfp->wf_mask) { 2932 case DLADM_WLAN_ATTR_ESSID: 2933 str = dladm_wlan_essid2str(&attrp->wa_essid, buf); 2934 break; 2935 case DLADM_WLAN_ATTR_BSSID: 2936 str = dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 2937 break; 2938 case DLADM_WLAN_ATTR_SECMODE: 2939 str = dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 2940 break; 2941 case DLADM_WLAN_ATTR_STRENGTH: 2942 str = dladm_wlan_strength2str(&attrp->wa_strength, buf); 2943 break; 2944 case DLADM_WLAN_ATTR_MODE: 2945 str = dladm_wlan_mode2str(&attrp->wa_mode, buf); 2946 break; 2947 case DLADM_WLAN_ATTR_SPEED: 2948 str = dladm_wlan_speed2str(&attrp->wa_speed, buf); 2949 (void) strlcat(buf, "Mb", sizeof (buf)); 2950 break; 2951 case DLADM_WLAN_ATTR_AUTH: 2952 str = dladm_wlan_auth2str(&attrp->wa_auth, buf); 2953 break; 2954 case DLADM_WLAN_ATTR_BSSTYPE: 2955 str = dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 2956 break; 2957 } 2958 2959 print_wifi_field(statep, wfp, str); 2960 } 2961 2962 static boolean_t 2963 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 2964 { 2965 print_wifi_state_t *statep = arg; 2966 int i; 2967 2968 if (statep->ws_header) { 2969 statep->ws_header = B_FALSE; 2970 if (!statep->ws_parseable) 2971 print_wifi_head(statep); 2972 } 2973 2974 statep->ws_overflow = 0; 2975 for (i = 0; i < statep->ws_nfields; i++) { 2976 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 2977 print_wlan_attr(statep, statep->ws_fields[i], attrp); 2978 } 2979 (void) putchar('\n'); 2980 return (B_TRUE); 2981 } 2982 2983 static int 2984 scan_wifi(datalink_id_t linkid, void *arg) 2985 { 2986 print_wifi_state_t *statep = arg; 2987 dladm_status_t status; 2988 char link[MAXLINKNAMELEN]; 2989 2990 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 2991 sizeof (link)) != DLADM_STATUS_OK) { 2992 return (DLADM_WALK_CONTINUE); 2993 } 2994 2995 statep->ws_link = link; 2996 status = dladm_wlan_scan(linkid, statep, print_scan_results); 2997 if (status != DLADM_STATUS_OK) 2998 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 2999 3000 return (DLADM_WALK_CONTINUE); 3001 } 3002 3003 static void 3004 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 3005 dladm_wlan_linkattr_t *attrp) 3006 { 3007 char buf[DLADM_STRSIZE]; 3008 const char *str = ""; 3009 3010 if (strcmp(wfp->wf_name, "status") == 0) { 3011 if ((wfp->wf_mask & attrp->la_valid) != 0) 3012 str = dladm_wlan_linkstatus2str(&attrp->la_status, buf); 3013 print_wifi_field(statep, wfp, str); 3014 return; 3015 } 3016 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 3017 } 3018 3019 static int 3020 show_wifi(datalink_id_t linkid, void *arg) 3021 { 3022 int i; 3023 print_wifi_state_t *statep = arg; 3024 dladm_wlan_linkattr_t attr; 3025 dladm_status_t status; 3026 char link[MAXLINKNAMELEN]; 3027 3028 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 3029 sizeof (link)) != DLADM_STATUS_OK) { 3030 return (DLADM_WALK_CONTINUE); 3031 } 3032 3033 status = dladm_wlan_get_linkattr(linkid, &attr); 3034 if (status != DLADM_STATUS_OK) 3035 die_dlerr(status, "cannot get link attributes for %s", link); 3036 3037 statep->ws_link = link; 3038 3039 if (statep->ws_header) { 3040 statep->ws_header = B_FALSE; 3041 if (!statep->ws_parseable) 3042 print_wifi_head(statep); 3043 } 3044 3045 statep->ws_overflow = 0; 3046 for (i = 0; i < statep->ws_nfields; i++) { 3047 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 3048 print_link_attr(statep, statep->ws_fields[i], &attr); 3049 } 3050 (void) putchar('\n'); 3051 return (DLADM_WALK_CONTINUE); 3052 } 3053 3054 static void 3055 do_display_wifi(int argc, char **argv, int cmd) 3056 { 3057 int option; 3058 char *fields_str = NULL; 3059 wifi_field_t **fields; 3060 int (*callback)(datalink_id_t, void *); 3061 uint_t nfields; 3062 print_wifi_state_t state; 3063 datalink_id_t linkid = DATALINK_ALL_LINKID; 3064 dladm_status_t status; 3065 3066 if (cmd == WIFI_CMD_SCAN) 3067 callback = scan_wifi; 3068 else if (cmd == WIFI_CMD_SHOW) 3069 callback = show_wifi; 3070 else 3071 return; 3072 3073 state.ws_parseable = B_FALSE; 3074 state.ws_header = B_TRUE; 3075 opterr = 0; 3076 while ((option = getopt_long(argc, argv, ":o:p", 3077 wifi_longopts, NULL)) != -1) { 3078 switch (option) { 3079 case 'o': 3080 fields_str = optarg; 3081 break; 3082 case 'p': 3083 state.ws_parseable = B_TRUE; 3084 if (fields_str == NULL) 3085 fields_str = "all"; 3086 break; 3087 default: 3088 die_opterr(optopt, option); 3089 break; 3090 } 3091 } 3092 3093 if (optind == (argc - 1)) { 3094 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3095 NULL, NULL)) != DLADM_STATUS_OK) { 3096 die_dlerr(status, "link %s is not valid", argv[optind]); 3097 } 3098 } else if (optind != argc) { 3099 usage(); 3100 } 3101 3102 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 3103 die("invalid field(s) specified"); 3104 3105 state.ws_fields = fields; 3106 state.ws_nfields = nfields; 3107 3108 if (linkid == DATALINK_ALL_LINKID) { 3109 (void) dladm_walk_datalink_id(callback, &state, 3110 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 3111 } else { 3112 (void) (*callback)(linkid, &state); 3113 } 3114 free(fields); 3115 } 3116 3117 static void 3118 do_scan_wifi(int argc, char **argv) 3119 { 3120 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 3121 } 3122 3123 static void 3124 do_show_wifi(int argc, char **argv) 3125 { 3126 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 3127 } 3128 3129 typedef struct wlan_count_attr { 3130 uint_t wc_count; 3131 datalink_id_t wc_linkid; 3132 } wlan_count_attr_t; 3133 3134 static int 3135 do_count_wlan(datalink_id_t linkid, void *arg) 3136 { 3137 wlan_count_attr_t *cp = arg; 3138 3139 if (cp->wc_count == 0) 3140 cp->wc_linkid = linkid; 3141 cp->wc_count++; 3142 return (DLADM_WALK_CONTINUE); 3143 } 3144 3145 static int 3146 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 3147 { 3148 uint_t i; 3149 split_t *sp; 3150 dladm_wlan_key_t *wk; 3151 3152 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 3153 if (sp == NULL) 3154 return (-1); 3155 3156 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 3157 if (wk == NULL) 3158 goto fail; 3159 3160 for (i = 0; i < sp->s_nfields; i++) { 3161 char *s; 3162 dladm_secobj_class_t class; 3163 dladm_status_t status; 3164 3165 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 3166 DLADM_WLAN_MAX_KEYNAME_LEN); 3167 3168 wk[i].wk_idx = 1; 3169 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 3170 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 3171 goto fail; 3172 3173 wk[i].wk_idx = (uint_t)(s[1] - '0'); 3174 *s = '\0'; 3175 } 3176 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 3177 3178 status = dladm_get_secobj(wk[i].wk_name, &class, 3179 wk[i].wk_val, &wk[i].wk_len, 0); 3180 if (status != DLADM_STATUS_OK) { 3181 if (status == DLADM_STATUS_NOTFOUND) { 3182 status = dladm_get_secobj(wk[i].wk_name, 3183 &class, wk[i].wk_val, &wk[i].wk_len, 3184 DLADM_OPT_PERSIST); 3185 } 3186 if (status != DLADM_STATUS_OK) 3187 goto fail; 3188 } 3189 wk[i].wk_class = class; 3190 } 3191 *keys = wk; 3192 *key_countp = i; 3193 splitfree(sp); 3194 return (0); 3195 fail: 3196 free(wk); 3197 splitfree(sp); 3198 return (-1); 3199 } 3200 3201 static void 3202 do_connect_wifi(int argc, char **argv) 3203 { 3204 int option; 3205 dladm_wlan_attr_t attr, *attrp; 3206 dladm_status_t status = DLADM_STATUS_OK; 3207 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 3208 datalink_id_t linkid = DATALINK_ALL_LINKID; 3209 dladm_wlan_key_t *keys = NULL; 3210 uint_t key_count = 0; 3211 uint_t flags = 0; 3212 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 3213 char buf[DLADM_STRSIZE]; 3214 3215 opterr = 0; 3216 (void) memset(&attr, 0, sizeof (attr)); 3217 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 3218 wifi_longopts, NULL)) != -1) { 3219 switch (option) { 3220 case 'e': 3221 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 3222 if (status != DLADM_STATUS_OK) 3223 die("invalid ESSID '%s'", optarg); 3224 3225 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 3226 /* 3227 * Try to connect without doing a scan. 3228 */ 3229 flags |= DLADM_WLAN_CONNECT_NOSCAN; 3230 break; 3231 case 'i': 3232 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 3233 if (status != DLADM_STATUS_OK) 3234 die("invalid BSSID %s", optarg); 3235 3236 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 3237 break; 3238 case 'a': 3239 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 3240 if (status != DLADM_STATUS_OK) 3241 die("invalid authentication mode '%s'", optarg); 3242 3243 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 3244 break; 3245 case 'm': 3246 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 3247 if (status != DLADM_STATUS_OK) 3248 die("invalid mode '%s'", optarg); 3249 3250 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 3251 break; 3252 case 'b': 3253 if ((status = dladm_wlan_str2bsstype(optarg, 3254 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 3255 die("invalid bsstype '%s'", optarg); 3256 } 3257 3258 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 3259 break; 3260 case 's': 3261 if ((status = dladm_wlan_str2secmode(optarg, 3262 &attr.wa_secmode)) != DLADM_STATUS_OK) { 3263 die("invalid security mode '%s'", optarg); 3264 } 3265 3266 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 3267 break; 3268 case 'k': 3269 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 3270 die("invalid key(s) '%s'", optarg); 3271 3272 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 3273 keysecmode = DLADM_WLAN_SECMODE_WEP; 3274 else 3275 keysecmode = DLADM_WLAN_SECMODE_WPA; 3276 break; 3277 case 'T': 3278 if (strcasecmp(optarg, "forever") == 0) { 3279 timeout = -1; 3280 break; 3281 } 3282 if (!str2int(optarg, &timeout) || timeout < 0) 3283 die("invalid timeout value '%s'", optarg); 3284 break; 3285 case 'c': 3286 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 3287 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 3288 break; 3289 default: 3290 die_opterr(optopt, option); 3291 break; 3292 } 3293 } 3294 3295 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 3296 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 3297 die("key required for security mode '%s'", 3298 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 3299 } 3300 } else { 3301 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 3302 attr.wa_secmode != keysecmode) 3303 die("incompatible -s and -k options"); 3304 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 3305 attr.wa_secmode = keysecmode; 3306 } 3307 3308 if (optind == (argc - 1)) { 3309 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3310 NULL, NULL)) != DLADM_STATUS_OK) { 3311 die_dlerr(status, "link %s is not valid", argv[optind]); 3312 } 3313 } else if (optind != argc) { 3314 usage(); 3315 } 3316 3317 if (linkid == DATALINK_ALL_LINKID) { 3318 wlan_count_attr_t wcattr; 3319 3320 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 3321 wcattr.wc_count = 0; 3322 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 3323 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 3324 if (wcattr.wc_count == 0) { 3325 die("no wifi links are available"); 3326 } else if (wcattr.wc_count > 1) { 3327 die("link name is required when more than one wifi " 3328 "link is available"); 3329 } 3330 linkid = wcattr.wc_linkid; 3331 } 3332 attrp = (attr.wa_valid == 0) ? NULL : &attr; 3333 again: 3334 if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys, 3335 key_count, flags)) != DLADM_STATUS_OK) { 3336 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 3337 /* 3338 * Try again with scanning and filtering. 3339 */ 3340 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 3341 goto again; 3342 } 3343 3344 if (status == DLADM_STATUS_NOTFOUND) { 3345 if (attr.wa_valid == 0) { 3346 die("no wifi networks are available"); 3347 } else { 3348 die("no wifi networks with the specified " 3349 "criteria are available"); 3350 } 3351 } 3352 die_dlerr(status, "cannot connect"); 3353 } 3354 free(keys); 3355 } 3356 3357 /* ARGSUSED */ 3358 static int 3359 do_all_disconnect_wifi(datalink_id_t linkid, void *arg) 3360 { 3361 dladm_status_t status; 3362 3363 status = dladm_wlan_disconnect(linkid); 3364 if (status != DLADM_STATUS_OK) 3365 warn_dlerr(status, "cannot disconnect link"); 3366 3367 return (DLADM_WALK_CONTINUE); 3368 } 3369 3370 static void 3371 do_disconnect_wifi(int argc, char **argv) 3372 { 3373 int option; 3374 datalink_id_t linkid = DATALINK_ALL_LINKID; 3375 boolean_t all_links = B_FALSE; 3376 dladm_status_t status; 3377 wlan_count_attr_t wcattr; 3378 3379 opterr = 0; 3380 while ((option = getopt_long(argc, argv, ":a", 3381 wifi_longopts, NULL)) != -1) { 3382 switch (option) { 3383 case 'a': 3384 all_links = B_TRUE; 3385 break; 3386 default: 3387 die_opterr(optopt, option); 3388 break; 3389 } 3390 } 3391 3392 if (optind == (argc - 1)) { 3393 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3394 NULL, NULL)) != DLADM_STATUS_OK) { 3395 die_dlerr(status, "link %s is not valid", argv[optind]); 3396 } 3397 } else if (optind != argc) { 3398 usage(); 3399 } 3400 3401 if (linkid == DATALINK_ALL_LINKID) { 3402 if (!all_links) { 3403 wcattr.wc_linkid = linkid; 3404 wcattr.wc_count = 0; 3405 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 3406 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 3407 if (wcattr.wc_count == 0) { 3408 die("no wifi links are available"); 3409 } else if (wcattr.wc_count > 1) { 3410 die("link name is required when more than " 3411 "one wifi link is available"); 3412 } 3413 linkid = wcattr.wc_linkid; 3414 } else { 3415 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 3416 NULL, DATALINK_CLASS_PHYS, DL_WIFI, 3417 DLADM_OPT_ACTIVE); 3418 return; 3419 } 3420 } 3421 status = dladm_wlan_disconnect(linkid); 3422 if (status != DLADM_STATUS_OK) 3423 die_dlerr(status, "cannot disconnect"); 3424 } 3425 3426 #define MAX_PROPS 32 3427 #define MAX_PROP_LINE 512 3428 3429 typedef struct prop_info { 3430 char *pi_name; 3431 char *pi_val[DLADM_MAX_PROP_VALCNT]; 3432 uint_t pi_count; 3433 } prop_info_t; 3434 3435 typedef struct prop_list { 3436 prop_info_t pl_info[MAX_PROPS]; 3437 uint_t pl_count; 3438 char *pl_buf; 3439 } prop_list_t; 3440 3441 typedef struct show_linkprop_state { 3442 char ls_link[MAXLINKNAMELEN]; 3443 char *ls_line; 3444 char **ls_propvals; 3445 prop_list_t *ls_proplist; 3446 uint32_t ls_parseable : 1, 3447 ls_persist : 1, 3448 ls_header : 1, 3449 ls_pad_bits : 29; 3450 dladm_status_t ls_status; 3451 } show_linkprop_state_t; 3452 3453 static void 3454 free_props(prop_list_t *list) 3455 { 3456 if (list != NULL) { 3457 free(list->pl_buf); 3458 free(list); 3459 } 3460 } 3461 3462 static int 3463 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 3464 { 3465 prop_list_t *list; 3466 prop_info_t *pip; 3467 char *buf, *curr; 3468 int len, i; 3469 3470 list = malloc(sizeof (prop_list_t)); 3471 if (list == NULL) 3472 return (-1); 3473 3474 list->pl_count = 0; 3475 list->pl_buf = buf = strdup(str); 3476 if (buf == NULL) 3477 goto fail; 3478 3479 curr = buf; 3480 len = strlen(buf); 3481 pip = NULL; 3482 for (i = 0; i < len; i++) { 3483 char c = buf[i]; 3484 boolean_t match = (c == '=' || c == ','); 3485 3486 if (!match && i != len - 1) 3487 continue; 3488 3489 if (match) { 3490 buf[i] = '\0'; 3491 if (*curr == '\0') 3492 goto fail; 3493 } 3494 3495 if (pip != NULL && c != '=') { 3496 if (pip->pi_count > DLADM_MAX_PROP_VALCNT) 3497 goto fail; 3498 3499 if (novalues) 3500 goto fail; 3501 3502 pip->pi_val[pip->pi_count] = curr; 3503 pip->pi_count++; 3504 } else { 3505 if (list->pl_count > MAX_PROPS) 3506 goto fail; 3507 3508 pip = &list->pl_info[list->pl_count]; 3509 pip->pi_name = curr; 3510 pip->pi_count = 0; 3511 list->pl_count++; 3512 if (c == ',') 3513 pip = NULL; 3514 } 3515 curr = buf + i + 1; 3516 } 3517 *listp = list; 3518 return (0); 3519 3520 fail: 3521 free_props(list); 3522 return (-1); 3523 } 3524 3525 static void 3526 print_linkprop_head(void) 3527 { 3528 (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 3529 "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 3530 } 3531 3532 static void 3533 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 3534 const char *propname, dladm_prop_type_t type, const char *typename, 3535 const char *format, char **pptr) 3536 { 3537 int i; 3538 char *ptr, *lim; 3539 char buf[DLADM_STRSIZE]; 3540 char *unknown = "?", *notsup = ""; 3541 char **propvals = statep->ls_propvals; 3542 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 3543 dladm_status_t status; 3544 3545 status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt); 3546 if (status != DLADM_STATUS_OK) { 3547 if (status == DLADM_STATUS_TEMPONLY) { 3548 if (type == DLADM_PROP_VAL_MODIFIABLE && 3549 statep->ls_persist) { 3550 valcnt = 1; 3551 propvals = &unknown; 3552 } else { 3553 statep->ls_status = status; 3554 return; 3555 } 3556 } else if (status == DLADM_STATUS_NOTSUP || 3557 statep->ls_persist) { 3558 valcnt = 1; 3559 if (type == DLADM_PROP_VAL_CURRENT) 3560 propvals = &unknown; 3561 else 3562 propvals = ¬sup; 3563 } else { 3564 statep->ls_status = status; 3565 if (statep->ls_proplist) { 3566 warn_dlerr(status, 3567 "cannot get link property '%s' for %s", 3568 propname, statep->ls_link); 3569 } 3570 return; 3571 } 3572 } 3573 3574 ptr = buf; 3575 lim = buf + DLADM_STRSIZE; 3576 for (i = 0; i < valcnt; i++) { 3577 if (propvals[i][0] == '\0' && !statep->ls_parseable) 3578 ptr += snprintf(ptr, lim - ptr, "--,"); 3579 else 3580 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 3581 if (ptr >= lim) 3582 break; 3583 } 3584 if (valcnt > 0) 3585 buf[strlen(buf) - 1] = '\0'; 3586 3587 lim = statep->ls_line + MAX_PROP_LINE; 3588 if (statep->ls_parseable) { 3589 *pptr += snprintf(*pptr, lim - *pptr, 3590 "%s=\"%s\" ", typename, buf); 3591 } else { 3592 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 3593 } 3594 } 3595 3596 static int 3597 show_linkprop(datalink_id_t linkid, const char *propname, void *arg) 3598 { 3599 show_linkprop_state_t *statep = arg; 3600 char *ptr = statep->ls_line; 3601 char *lim = ptr + MAX_PROP_LINE; 3602 3603 if (statep->ls_parseable) 3604 ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 3605 statep->ls_link); 3606 else 3607 ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 3608 3609 if (statep->ls_parseable) 3610 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 3611 else 3612 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 3613 3614 print_linkprop(linkid, statep, propname, 3615 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 3616 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 3617 3618 /* 3619 * If we failed to query the link property, for example, query 3620 * the persistent value of a non-persistable link property, simply 3621 * skip the output. 3622 */ 3623 if (statep->ls_status != DLADM_STATUS_OK) 3624 return (DLADM_WALK_CONTINUE); 3625 3626 print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_DEFAULT, 3627 "DEFAULT", "%-14s ", &ptr); 3628 if (statep->ls_status != DLADM_STATUS_OK) 3629 return (DLADM_WALK_CONTINUE); 3630 3631 print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_MODIFIABLE, 3632 "POSSIBLE", "%-20s ", &ptr); 3633 if (statep->ls_status != DLADM_STATUS_OK) 3634 return (DLADM_WALK_CONTINUE); 3635 3636 if (statep->ls_header) { 3637 statep->ls_header = B_FALSE; 3638 if (!statep->ls_parseable) 3639 print_linkprop_head(); 3640 } 3641 (void) printf("%s\n", statep->ls_line); 3642 return (DLADM_WALK_CONTINUE); 3643 } 3644 3645 static void 3646 do_show_linkprop(int argc, char **argv) 3647 { 3648 int option; 3649 prop_list_t *proplist = NULL; 3650 datalink_id_t linkid = DATALINK_ALL_LINKID; 3651 show_linkprop_state_t state; 3652 uint32_t flags = DLADM_OPT_ACTIVE; 3653 dladm_status_t status; 3654 3655 opterr = 0; 3656 state.ls_propvals = NULL; 3657 state.ls_line = NULL; 3658 state.ls_parseable = B_FALSE; 3659 state.ls_persist = B_FALSE; 3660 state.ls_header = B_TRUE; 3661 while ((option = getopt_long(argc, argv, ":p:cP", 3662 prop_longopts, NULL)) != -1) { 3663 switch (option) { 3664 case 'p': 3665 if (parse_props(optarg, &proplist, B_TRUE) < 0) 3666 die("invalid link properties specified"); 3667 break; 3668 case 'c': 3669 state.ls_parseable = B_TRUE; 3670 break; 3671 case 'P': 3672 state.ls_persist = B_TRUE; 3673 flags = DLADM_OPT_PERSIST; 3674 break; 3675 default: 3676 die_opterr(optopt, option); 3677 break; 3678 } 3679 } 3680 3681 if (optind == (argc - 1)) { 3682 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3683 NULL, NULL)) != DLADM_STATUS_OK) { 3684 die_dlerr(status, "link %s is not valid", argv[optind]); 3685 } 3686 } else if (optind != argc) { 3687 usage(); 3688 } 3689 3690 state.ls_proplist = proplist; 3691 state.ls_status = DLADM_STATUS_OK; 3692 3693 if (linkid == DATALINK_ALL_LINKID) { 3694 (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, 3695 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 3696 } else { 3697 (void) show_linkprop_onelink(linkid, &state); 3698 } 3699 free_props(proplist); 3700 3701 if (state.ls_status != DLADM_STATUS_OK) { 3702 if (optind == (argc - 1)) { 3703 warn_dlerr(state.ls_status, 3704 "show-linkprop failed for %s", argv[optind]); 3705 } 3706 exit(EXIT_FAILURE); 3707 } 3708 } 3709 3710 static int 3711 show_linkprop_onelink(datalink_id_t linkid, void *arg) 3712 { 3713 int i; 3714 char *buf; 3715 uint32_t flags; 3716 prop_list_t *proplist = NULL; 3717 show_linkprop_state_t *statep = arg; 3718 dlpi_handle_t dh = NULL; 3719 3720 statep->ls_status = DLADM_STATUS_OK; 3721 3722 if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link, 3723 MAXLINKNAMELEN) != DLADM_STATUS_OK) { 3724 statep->ls_status = DLADM_STATUS_NOTFOUND; 3725 return (DLADM_WALK_CONTINUE); 3726 } 3727 3728 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 3729 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 3730 statep->ls_status = DLADM_STATUS_BADARG; 3731 return (DLADM_WALK_CONTINUE); 3732 } 3733 3734 proplist = statep->ls_proplist; 3735 3736 /* 3737 * When some WiFi links are opened for the first time, their hardware 3738 * automatically scans for APs and does other slow operations. Thus, 3739 * if there are no open links, the retrieval of link properties 3740 * (below) will proceed slowly unless we hold the link open. 3741 * 3742 * Note that failure of dlpi_open() does not necessarily mean invalid 3743 * link properties, because dlpi_open() may fail because of incorrect 3744 * autopush configuration. Therefore, we ingore the return value of 3745 * dlpi_open(). 3746 */ 3747 if (!statep->ls_persist) 3748 (void) dlpi_open(statep->ls_link, &dh, 0); 3749 3750 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 3751 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 3752 if (buf == NULL) 3753 die("insufficient memory"); 3754 3755 statep->ls_propvals = (char **)(void *)buf; 3756 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 3757 statep->ls_propvals[i] = buf + 3758 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 3759 i * DLADM_PROP_VAL_MAX; 3760 } 3761 statep->ls_line = buf + 3762 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 3763 3764 if (proplist != NULL) { 3765 for (i = 0; i < proplist->pl_count; i++) { 3766 (void) show_linkprop(linkid, 3767 proplist->pl_info[i].pi_name, statep); 3768 } 3769 } else { 3770 (void) dladm_walk_linkprop(linkid, statep, show_linkprop); 3771 } 3772 if (dh != NULL) 3773 dlpi_close(dh); 3774 free(buf); 3775 return (DLADM_WALK_CONTINUE); 3776 } 3777 3778 static dladm_status_t 3779 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 3780 char **prop_val, uint_t val_cnt, boolean_t reset) 3781 { 3782 dladm_status_t status; 3783 3784 status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt, 3785 DLADM_OPT_PERSIST); 3786 3787 if (status != DLADM_STATUS_OK) { 3788 warn_dlerr(status, "cannot persistently %s link property", 3789 reset ? "reset" : "set"); 3790 } 3791 return (status); 3792 } 3793 3794 static void 3795 set_linkprop(int argc, char **argv, boolean_t reset) 3796 { 3797 int i, option; 3798 char errmsg[DLADM_STRSIZE]; 3799 char *altroot = NULL; 3800 datalink_id_t linkid; 3801 prop_list_t *proplist = NULL; 3802 boolean_t temp = B_FALSE; 3803 dladm_status_t status = DLADM_STATUS_OK; 3804 3805 opterr = 0; 3806 while ((option = getopt_long(argc, argv, ":p:R:t", 3807 prop_longopts, NULL)) != -1) { 3808 switch (option) { 3809 case 'p': 3810 if (parse_props(optarg, &proplist, reset) < 0) 3811 die("invalid link properties specified"); 3812 break; 3813 case 't': 3814 temp = B_TRUE; 3815 break; 3816 case 'R': 3817 altroot = optarg; 3818 break; 3819 default: 3820 die_opterr(optopt, option); 3821 break; 3822 } 3823 } 3824 3825 /* get link name (required last argument) */ 3826 if (optind != (argc - 1)) 3827 usage(); 3828 3829 if (proplist == NULL && !reset) 3830 die("link property must be specified"); 3831 3832 if (altroot != NULL) { 3833 free_props(proplist); 3834 altroot_cmd(altroot, argc, argv); 3835 } 3836 3837 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 3838 if (status != DLADM_STATUS_OK) 3839 die_dlerr(status, "link %s is not valid", argv[optind]); 3840 3841 if (proplist == NULL) { 3842 if ((status = dladm_set_linkprop(linkid, NULL, NULL, 0, 3843 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 3844 warn_dlerr(status, "cannot reset link property " 3845 "on '%s'", argv[optind]); 3846 } 3847 if (!temp) { 3848 dladm_status_t s; 3849 3850 s = set_linkprop_persist(linkid, NULL, NULL, 0, reset); 3851 if (s != DLADM_STATUS_OK) 3852 status = s; 3853 } 3854 goto done; 3855 } 3856 3857 for (i = 0; i < proplist->pl_count; i++) { 3858 prop_info_t *pip = &proplist->pl_info[i]; 3859 char **val; 3860 uint_t count; 3861 dladm_status_t s; 3862 3863 if (reset) { 3864 val = NULL; 3865 count = 0; 3866 } else { 3867 val = pip->pi_val; 3868 count = pip->pi_count; 3869 if (count == 0) { 3870 warn("no value specified for '%s'", 3871 pip->pi_name); 3872 status = DLADM_STATUS_BADARG; 3873 continue; 3874 } 3875 } 3876 s = dladm_set_linkprop(linkid, pip->pi_name, val, count, 3877 DLADM_OPT_ACTIVE); 3878 if (s == DLADM_STATUS_OK) { 3879 if (!temp) { 3880 s = set_linkprop_persist(linkid, 3881 pip->pi_name, val, count, reset); 3882 if (s != DLADM_STATUS_OK) 3883 status = s; 3884 } 3885 continue; 3886 } 3887 status = s; 3888 switch (s) { 3889 case DLADM_STATUS_NOTFOUND: 3890 warn("invalid link property '%s'", pip->pi_name); 3891 break; 3892 case DLADM_STATUS_BADVAL: { 3893 int j; 3894 char *ptr, *lim; 3895 char **propvals = NULL; 3896 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 3897 3898 ptr = malloc((sizeof (char *) + 3899 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 3900 MAX_PROP_LINE); 3901 3902 propvals = (char **)(void *)ptr; 3903 if (propvals == NULL) 3904 die("insufficient memory"); 3905 3906 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 3907 propvals[j] = ptr + sizeof (char *) * 3908 DLADM_MAX_PROP_VALCNT + 3909 j * DLADM_PROP_VAL_MAX; 3910 } 3911 s = dladm_get_linkprop(linkid, 3912 DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals, 3913 &valcnt); 3914 3915 if (s != DLADM_STATUS_OK) { 3916 warn_dlerr(status, "cannot set link property " 3917 "'%s' on '%s'", pip->pi_name, argv[optind]); 3918 free(propvals); 3919 break; 3920 } 3921 3922 ptr = errmsg; 3923 lim = ptr + DLADM_STRSIZE; 3924 *ptr = '\0'; 3925 for (j = 0; j < valcnt; j++) { 3926 ptr += snprintf(ptr, lim - ptr, "%s,", 3927 propvals[j]); 3928 if (ptr >= lim) 3929 break; 3930 } 3931 if (ptr > errmsg) { 3932 *(ptr - 1) = '\0'; 3933 warn("link property '%s' must be one of: %s", 3934 pip->pi_name, errmsg); 3935 } else 3936 warn("invalid link property '%s'", *val); 3937 free(propvals); 3938 break; 3939 } 3940 default: 3941 if (reset) { 3942 warn_dlerr(status, "cannot reset link property " 3943 "'%s' on '%s'", pip->pi_name, argv[optind]); 3944 } else { 3945 warn_dlerr(status, "cannot set link property " 3946 "'%s' on '%s'", pip->pi_name, argv[optind]); 3947 } 3948 break; 3949 } 3950 } 3951 done: 3952 free_props(proplist); 3953 if (status != DLADM_STATUS_OK) 3954 exit(1); 3955 } 3956 3957 static void 3958 do_set_linkprop(int argc, char **argv) 3959 { 3960 set_linkprop(argc, argv, B_FALSE); 3961 } 3962 3963 static void 3964 do_reset_linkprop(int argc, char **argv) 3965 { 3966 set_linkprop(argc, argv, B_TRUE); 3967 } 3968 3969 static int 3970 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 3971 dladm_secobj_class_t class) 3972 { 3973 int error = 0; 3974 3975 if (class == DLADM_SECOBJ_CLASS_WPA) { 3976 if (len < 8 || len > 63) 3977 return (EINVAL); 3978 (void) memcpy(obj_val, buf, len); 3979 *obj_lenp = len; 3980 return (error); 3981 } 3982 3983 if (class == DLADM_SECOBJ_CLASS_WEP) { 3984 switch (len) { 3985 case 5: /* ASCII key sizes */ 3986 case 13: 3987 (void) memcpy(obj_val, buf, len); 3988 *obj_lenp = len; 3989 break; 3990 case 10: /* Hex key sizes, not preceded by 0x */ 3991 case 26: 3992 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 3993 break; 3994 case 12: /* Hex key sizes, preceded by 0x */ 3995 case 28: 3996 if (strncmp(buf, "0x", 2) != 0) 3997 return (EINVAL); 3998 error = hexascii_to_octet(buf + 2, len - 2, 3999 obj_val, obj_lenp); 4000 break; 4001 default: 4002 return (EINVAL); 4003 } 4004 return (error); 4005 } 4006 4007 return (ENOENT); 4008 } 4009 4010 /* ARGSUSED */ 4011 static void 4012 defersig(int sig) 4013 { 4014 signalled = sig; 4015 } 4016 4017 static int 4018 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 4019 { 4020 uint_t len = 0; 4021 int c; 4022 struct termios stored, current; 4023 void (*sigfunc)(int); 4024 4025 /* 4026 * Turn off echo -- but before we do so, defer SIGINT handling 4027 * so that a ^C doesn't leave the terminal corrupted. 4028 */ 4029 sigfunc = signal(SIGINT, defersig); 4030 (void) fflush(stdin); 4031 (void) tcgetattr(0, &stored); 4032 current = stored; 4033 current.c_lflag &= ~(ICANON|ECHO); 4034 current.c_cc[VTIME] = 0; 4035 current.c_cc[VMIN] = 1; 4036 (void) tcsetattr(0, TCSANOW, ¤t); 4037 again: 4038 if (try == 1) 4039 (void) printf(gettext("provide value for '%s': "), objname); 4040 else 4041 (void) printf(gettext("confirm value for '%s': "), objname); 4042 4043 (void) fflush(stdout); 4044 while (signalled == 0) { 4045 c = getchar(); 4046 if (c == '\n' || c == '\r') { 4047 if (len != 0) 4048 break; 4049 (void) putchar('\n'); 4050 goto again; 4051 } 4052 4053 buf[len++] = c; 4054 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 4055 break; 4056 (void) putchar('*'); 4057 } 4058 4059 (void) putchar('\n'); 4060 (void) fflush(stdin); 4061 4062 /* 4063 * Restore terminal setting and handle deferred signals. 4064 */ 4065 (void) tcsetattr(0, TCSANOW, &stored); 4066 4067 (void) signal(SIGINT, sigfunc); 4068 if (signalled != 0) 4069 (void) kill(getpid(), signalled); 4070 4071 return (len); 4072 } 4073 4074 static int 4075 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 4076 dladm_secobj_class_t class, FILE *filep) 4077 { 4078 int rval; 4079 uint_t len, len2; 4080 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 4081 4082 if (filep == NULL) { 4083 len = get_secobj_from_tty(1, obj_name, buf); 4084 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 4085 if (rval == 0) { 4086 len2 = get_secobj_from_tty(2, obj_name, buf2); 4087 if (len != len2 || memcmp(buf, buf2, len) != 0) 4088 rval = ENOTSUP; 4089 } 4090 return (rval); 4091 } else { 4092 for (;;) { 4093 if (fgets(buf, sizeof (buf), filep) == NULL) 4094 break; 4095 if (isspace(buf[0])) 4096 continue; 4097 4098 len = strlen(buf); 4099 if (buf[len - 1] == '\n') { 4100 buf[len - 1] = '\0'; 4101 len--; 4102 } 4103 break; 4104 } 4105 (void) fclose(filep); 4106 } 4107 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 4108 } 4109 4110 static boolean_t 4111 check_auth(const char *auth) 4112 { 4113 struct passwd *pw; 4114 4115 if ((pw = getpwuid(getuid())) == NULL) 4116 return (B_FALSE); 4117 4118 return (chkauthattr(auth, pw->pw_name) != 0); 4119 } 4120 4121 static void 4122 audit_secobj(char *auth, char *class, char *obj, 4123 boolean_t success, boolean_t create) 4124 { 4125 adt_session_data_t *ah; 4126 adt_event_data_t *event; 4127 au_event_t flag; 4128 char *errstr; 4129 4130 if (create) { 4131 flag = ADT_dladm_create_secobj; 4132 errstr = "ADT_dladm_create_secobj"; 4133 } else { 4134 flag = ADT_dladm_delete_secobj; 4135 errstr = "ADT_dladm_delete_secobj"; 4136 } 4137 4138 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 4139 die("adt_start_session: %s", strerror(errno)); 4140 4141 if ((event = adt_alloc_event(ah, flag)) == NULL) 4142 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 4143 4144 /* fill in audit info */ 4145 if (create) { 4146 event->adt_dladm_create_secobj.auth_used = auth; 4147 event->adt_dladm_create_secobj.obj_class = class; 4148 event->adt_dladm_create_secobj.obj_name = obj; 4149 } else { 4150 event->adt_dladm_delete_secobj.auth_used = auth; 4151 event->adt_dladm_delete_secobj.obj_class = class; 4152 event->adt_dladm_delete_secobj.obj_name = obj; 4153 } 4154 4155 if (success) { 4156 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 4157 die("adt_put_event (%s, success): %s", errstr, 4158 strerror(errno)); 4159 } 4160 } else { 4161 if (adt_put_event(event, ADT_FAILURE, 4162 ADT_FAIL_VALUE_AUTH) != 0) { 4163 die("adt_put_event: (%s, failure): %s", errstr, 4164 strerror(errno)); 4165 } 4166 } 4167 4168 adt_free_event(event); 4169 (void) adt_end_session(ah); 4170 } 4171 4172 #define MAX_SECOBJS 32 4173 #define MAX_SECOBJ_NAMELEN 32 4174 static void 4175 do_create_secobj(int argc, char **argv) 4176 { 4177 int option, rval; 4178 FILE *filep = NULL; 4179 char *obj_name = NULL; 4180 char *class_name = NULL; 4181 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 4182 uint_t obj_len; 4183 boolean_t success, temp = B_FALSE; 4184 dladm_status_t status; 4185 dladm_secobj_class_t class = -1; 4186 uid_t euid; 4187 4188 opterr = 0; 4189 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 4190 while ((option = getopt_long(argc, argv, ":f:c:R:t", 4191 wifi_longopts, NULL)) != -1) { 4192 switch (option) { 4193 case 'f': 4194 euid = geteuid(); 4195 (void) seteuid(getuid()); 4196 filep = fopen(optarg, "r"); 4197 if (filep == NULL) { 4198 die("cannot open %s: %s", optarg, 4199 strerror(errno)); 4200 } 4201 (void) seteuid(euid); 4202 break; 4203 case 'c': 4204 class_name = optarg; 4205 status = dladm_str2secobjclass(optarg, &class); 4206 if (status != DLADM_STATUS_OK) { 4207 die("invalid secure object class '%s', " 4208 "valid values are: wep, wpa", optarg); 4209 } 4210 break; 4211 case 't': 4212 temp = B_TRUE; 4213 break; 4214 case 'R': 4215 status = dladm_set_rootdir(optarg); 4216 if (status != DLADM_STATUS_OK) { 4217 die_dlerr(status, "invalid directory " 4218 "specified"); 4219 } 4220 break; 4221 default: 4222 die_opterr(optopt, option); 4223 break; 4224 } 4225 } 4226 4227 if (optind == (argc - 1)) 4228 obj_name = argv[optind]; 4229 else if (optind != argc) 4230 usage(); 4231 4232 if (class == -1) 4233 die("secure object class required"); 4234 4235 if (obj_name == NULL) 4236 die("secure object name required"); 4237 4238 success = check_auth(LINK_SEC_AUTH); 4239 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 4240 if (!success) 4241 die("authorization '%s' is required", LINK_SEC_AUTH); 4242 4243 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 4244 if (rval != 0) { 4245 switch (rval) { 4246 case ENOENT: 4247 die("invalid secure object class"); 4248 break; 4249 case EINVAL: 4250 die("invalid secure object value"); 4251 break; 4252 case ENOTSUP: 4253 die("verification failed"); 4254 break; 4255 default: 4256 die("invalid secure object: %s", strerror(rval)); 4257 break; 4258 } 4259 } 4260 4261 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 4262 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 4263 if (status != DLADM_STATUS_OK) { 4264 die_dlerr(status, "could not create secure object '%s'", 4265 obj_name); 4266 } 4267 if (temp) 4268 return; 4269 4270 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 4271 DLADM_OPT_PERSIST); 4272 if (status != DLADM_STATUS_OK) { 4273 warn_dlerr(status, "could not persistently create secure " 4274 "object '%s'", obj_name); 4275 } 4276 } 4277 4278 static void 4279 do_delete_secobj(int argc, char **argv) 4280 { 4281 int i, option; 4282 boolean_t temp = B_FALSE; 4283 split_t *sp = NULL; 4284 boolean_t success; 4285 dladm_status_t status, pstatus; 4286 4287 opterr = 0; 4288 status = pstatus = DLADM_STATUS_OK; 4289 while ((option = getopt_long(argc, argv, ":R:t", 4290 wifi_longopts, NULL)) != -1) { 4291 switch (option) { 4292 case 't': 4293 temp = B_TRUE; 4294 break; 4295 case 'R': 4296 status = dladm_set_rootdir(optarg); 4297 if (status != DLADM_STATUS_OK) { 4298 die_dlerr(status, "invalid directory " 4299 "specified"); 4300 } 4301 break; 4302 default: 4303 die_opterr(optopt, option); 4304 break; 4305 } 4306 } 4307 4308 if (optind == (argc - 1)) { 4309 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 4310 if (sp == NULL) { 4311 die("invalid secure object name(s): '%s'", 4312 argv[optind]); 4313 } 4314 } else if (optind != argc) 4315 usage(); 4316 4317 if (sp == NULL || sp->s_nfields < 1) 4318 die("secure object name required"); 4319 4320 success = check_auth(LINK_SEC_AUTH); 4321 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 4322 if (!success) 4323 die("authorization '%s' is required", LINK_SEC_AUTH); 4324 4325 for (i = 0; i < sp->s_nfields; i++) { 4326 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE); 4327 if (!temp) { 4328 pstatus = dladm_unset_secobj(sp->s_fields[i], 4329 DLADM_OPT_PERSIST); 4330 } else { 4331 pstatus = DLADM_STATUS_OK; 4332 } 4333 4334 if (status != DLADM_STATUS_OK) { 4335 warn_dlerr(status, "could not delete secure object " 4336 "'%s'", sp->s_fields[i]); 4337 } 4338 if (pstatus != DLADM_STATUS_OK) { 4339 warn_dlerr(pstatus, "could not persistently delete " 4340 "secure object '%s'", sp->s_fields[i]); 4341 } 4342 } 4343 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 4344 exit(1); 4345 } 4346 4347 typedef struct show_secobj_state { 4348 boolean_t ss_persist; 4349 boolean_t ss_parseable; 4350 boolean_t ss_debug; 4351 boolean_t ss_header; 4352 } show_secobj_state_t; 4353 4354 static void 4355 print_secobj_head(show_secobj_state_t *statep) 4356 { 4357 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 4358 if (statep->ss_debug) 4359 (void) printf("%-30s", "VALUE"); 4360 (void) putchar('\n'); 4361 } 4362 4363 static boolean_t 4364 show_secobj(void *arg, const char *obj_name) 4365 { 4366 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 4367 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 4368 char buf[DLADM_STRSIZE]; 4369 uint_t flags = 0; 4370 dladm_secobj_class_t class; 4371 show_secobj_state_t *statep = arg; 4372 dladm_status_t status; 4373 4374 if (statep->ss_persist) 4375 flags |= DLADM_OPT_PERSIST; 4376 4377 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 4378 if (status != DLADM_STATUS_OK) 4379 die_dlerr(status, "cannot get secure object '%s'", obj_name); 4380 4381 if (statep->ss_header) { 4382 statep->ss_header = B_FALSE; 4383 if (!statep->ss_parseable) 4384 print_secobj_head(statep); 4385 } 4386 4387 if (statep->ss_parseable) { 4388 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 4389 dladm_secobjclass2str(class, buf)); 4390 } else { 4391 (void) printf("%-20s %-20s ", obj_name, 4392 dladm_secobjclass2str(class, buf)); 4393 } 4394 4395 if (statep->ss_debug) { 4396 char val[DLADM_SECOBJ_VAL_MAX * 2]; 4397 uint_t len = sizeof (val); 4398 4399 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 4400 if (statep->ss_parseable) 4401 (void) printf("VALUE=\"0x%s\"", val); 4402 else 4403 (void) printf("0x%-30s", val); 4404 } 4405 } 4406 (void) putchar('\n'); 4407 return (B_TRUE); 4408 } 4409 4410 static void 4411 do_show_secobj(int argc, char **argv) 4412 { 4413 int option; 4414 show_secobj_state_t state; 4415 dladm_status_t status; 4416 uint_t i; 4417 split_t *sp; 4418 uint_t flags; 4419 4420 opterr = 0; 4421 state.ss_persist = B_FALSE; 4422 state.ss_parseable = B_FALSE; 4423 state.ss_debug = B_FALSE; 4424 state.ss_header = B_TRUE; 4425 while ((option = getopt_long(argc, argv, ":pPd", 4426 wifi_longopts, NULL)) != -1) { 4427 switch (option) { 4428 case 'p': 4429 state.ss_parseable = B_TRUE; 4430 break; 4431 case 'P': 4432 state.ss_persist = B_TRUE; 4433 break; 4434 case 'd': 4435 if (getuid() != 0) 4436 die("insufficient privileges"); 4437 state.ss_debug = B_TRUE; 4438 break; 4439 default: 4440 die_opterr(optopt, option); 4441 break; 4442 } 4443 } 4444 4445 if (optind == (argc - 1)) { 4446 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 4447 if (sp == NULL) { 4448 die("invalid secure object name(s): '%s'", 4449 argv[optind]); 4450 } 4451 for (i = 0; i < sp->s_nfields; i++) { 4452 if (!show_secobj(&state, sp->s_fields[i])) 4453 break; 4454 } 4455 splitfree(sp); 4456 return; 4457 } else if (optind != argc) 4458 usage(); 4459 4460 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 4461 status = dladm_walk_secobj(&state, show_secobj, flags); 4462 if (status != DLADM_STATUS_OK) 4463 die_dlerr(status, "show-secobj"); 4464 } 4465 4466 /*ARGSUSED*/ 4467 static int 4468 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 4469 { 4470 (void) dladm_init_linkprop(linkid); 4471 return (DLADM_WALK_CONTINUE); 4472 } 4473 4474 /* ARGSUSED */ 4475 static void 4476 do_init_linkprop(int argc, char **argv) 4477 { 4478 /* 4479 * linkprops of links of other classes have been initialized as a 4480 * part of the dladm up-xxx operation. 4481 */ 4482 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 4483 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 4484 } 4485 4486 /* ARGSUSED */ 4487 static void 4488 do_init_secobj(int argc, char **argv) 4489 { 4490 dladm_status_t status; 4491 4492 status = dladm_init_secobj(); 4493 if (status != DLADM_STATUS_OK) 4494 die_dlerr(status, "secure object initialization failed"); 4495 } 4496 4497 /* 4498 * "-R" option support. It is used for live upgrading. Append dladm commands 4499 * to a upgrade script which will be run when the alternative root boots up: 4500 * 4501 * - If the dlmgmtd door file exists on the alternative root, append dladm 4502 * commands to the <altroot>/var/svc/profile/upgrade_datalink script. This 4503 * script will be run as part of the network/physical service. We cannot defer 4504 * this to /var/svc/profile/upgrade because then the configuration will not 4505 * be able to take effect before network/physical plumbs various interfaces. 4506 * 4507 * - If the dlmgmtd door file does not exist on the alternative root, append 4508 * dladm commands to the <altroot>/var/svc/profile/upgrade script, which will 4509 * be run in the manifest-import service. 4510 * 4511 * Note that the SMF team is considering to move the manifest-import service 4512 * to be run at the very begining of boot. Once that is done, the need for 4513 * the /var/svc/profile/upgrade_datalink script will not exist any more. 4514 */ 4515 static void 4516 altroot_cmd(char *altroot, int argc, char *argv[]) 4517 { 4518 char path[MAXPATHLEN]; 4519 struct stat stbuf; 4520 FILE *fp; 4521 int i; 4522 4523 /* 4524 * Check for the existence of the dlmgmtd door file, and determine 4525 * the name of script file. 4526 */ 4527 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, DLMGMT_DOOR); 4528 if (stat(path, &stbuf) < 0) { 4529 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 4530 SMF_UPGRADE_FILE); 4531 } else { 4532 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 4533 SMF_UPGRADEDATALINK_FILE); 4534 } 4535 4536 if ((fp = fopen(path, "a+")) == NULL) 4537 die("operation not supported on %s", altroot); 4538 4539 (void) fprintf(fp, "/sbin/dladm "); 4540 for (i = 0; i < argc; i++) { 4541 /* 4542 * Directly write to the file if it is not the "-R <altroot>" 4543 * option. In which case, skip it. 4544 */ 4545 if (strcmp(argv[i], "-R") != 0) 4546 (void) fprintf(fp, "%s ", argv[i]); 4547 else 4548 i ++; 4549 } 4550 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 4551 (void) fclose(fp); 4552 exit(0); 4553 } 4554 4555 /* 4556 * Convert the string to an integer. Note that the string must not have any 4557 * trailing non-integer characters. 4558 */ 4559 static boolean_t 4560 str2int(const char *str, int *valp) 4561 { 4562 int val; 4563 char *endp = NULL; 4564 4565 errno = 0; 4566 val = strtol(str, &endp, 10); 4567 if (errno != 0 || *endp != '\0') 4568 return (B_FALSE); 4569 4570 *valp = val; 4571 return (B_TRUE); 4572 } 4573 4574 /* PRINTFLIKE1 */ 4575 static void 4576 warn(const char *format, ...) 4577 { 4578 va_list alist; 4579 4580 format = gettext(format); 4581 (void) fprintf(stderr, "%s: warning: ", progname); 4582 4583 va_start(alist, format); 4584 (void) vfprintf(stderr, format, alist); 4585 va_end(alist); 4586 4587 (void) putchar('\n'); 4588 } 4589 4590 /* PRINTFLIKE2 */ 4591 static void 4592 warn_dlerr(dladm_status_t err, const char *format, ...) 4593 { 4594 va_list alist; 4595 char errmsg[DLADM_STRSIZE]; 4596 4597 format = gettext(format); 4598 (void) fprintf(stderr, gettext("%s: warning: "), progname); 4599 4600 va_start(alist, format); 4601 (void) vfprintf(stderr, format, alist); 4602 va_end(alist); 4603 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 4604 } 4605 4606 /* PRINTFLIKE2 */ 4607 static void 4608 die_dlerr(dladm_status_t err, const char *format, ...) 4609 { 4610 va_list alist; 4611 char errmsg[DLADM_STRSIZE]; 4612 4613 format = gettext(format); 4614 (void) fprintf(stderr, "%s: ", progname); 4615 4616 va_start(alist, format); 4617 (void) vfprintf(stderr, format, alist); 4618 va_end(alist); 4619 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 4620 4621 exit(EXIT_FAILURE); 4622 } 4623 4624 /* PRINTFLIKE1 */ 4625 static void 4626 die(const char *format, ...) 4627 { 4628 va_list alist; 4629 4630 format = gettext(format); 4631 (void) fprintf(stderr, "%s: ", progname); 4632 4633 va_start(alist, format); 4634 (void) vfprintf(stderr, format, alist); 4635 va_end(alist); 4636 4637 (void) putchar('\n'); 4638 exit(EXIT_FAILURE); 4639 } 4640 4641 static void 4642 die_optdup(int opt) 4643 { 4644 die("the option -%c cannot be specified more than once", opt); 4645 } 4646 4647 static void 4648 die_opterr(int opt, int opterr) 4649 { 4650 switch (opterr) { 4651 case ':': 4652 die("option '-%c' requires a value", opt); 4653 break; 4654 case '?': 4655 default: 4656 die("unrecognized option '-%c'", opt); 4657 break; 4658 } 4659 } 4660