dladm.c revision 3448:aaf16568054b
1298770Sdelphij/* 2275970Scy * CDDL HEADER START 3275970Scy * 4275970Scy * The contents of this file are subject to the terms of the 5275970Scy * Common Development and Distribution License (the "License"). 6298770Sdelphij * You may not use this file except in compliance with the License. 7275970Scy * 8275970Scy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9275970Scy * or http://www.opensolaris.org/os/licensing. 10275970Scy * See the License for the specific language governing permissions 11275970Scy * and limitations under the License. 12275970Scy * 13275970Scy * When distributing Covered Code, include this CDDL HEADER in each 14275970Scy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15275970Scy * If applicable, add the following below this CDDL HEADER, with the 16275970Scy * fields enclosed by brackets "[]" replaced with your own identifying 17275970Scy * information: Portions Copyright [yyyy] [name of copyright owner] 18275970Scy * 19275970Scy * CDDL HEADER END 20275970Scy */ 21275970Scy/* 22275970Scy * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23275970Scy * Use is subject to license terms. 24275970Scy */ 25275970Scy 26275970Scy#pragma ident "%Z%%M% %I% %E% SMI" 27275970Scy 28275970Scy#include <stdio.h> 29275970Scy#include <ctype.h> 30275970Scy#include <locale.h> 31275970Scy#include <signal.h> 32275970Scy#include <stdarg.h> 33275970Scy#include <stdlib.h> 34275970Scy#include <fcntl.h> 35275970Scy#include <stdarg.h> 36275970Scy#include <string.h> 37275970Scy#include <stropts.h> 38275970Scy#include <errno.h> 39275970Scy#include <kstat.h> 40275970Scy#include <strings.h> 41275970Scy#include <getopt.h> 42275970Scy#include <unistd.h> 43275970Scy#include <priv.h> 44275970Scy#include <termios.h> 45275970Scy#include <pwd.h> 46275970Scy#include <auth_attr.h> 47275970Scy#include <auth_list.h> 48275970Scy#include <libintl.h> 49275970Scy#include <libdlpi.h> 50275970Scy#include <libdladm.h> 51275970Scy#include <liblaadm.h> 52275970Scy#include <libmacadm.h> 53275970Scy#include <libwladm.h> 54275970Scy#include <libinetutil.h> 55275970Scy#include <bsm/adt.h> 56275970Scy#include <bsm/adt_event.h> 57275970Scy 58275970Scy#define AGGR_DRV "aggr" 59275970Scy#define MAXPORT 256 60275970Scy#define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 61275970Scy "%-5s %-4s %-4s %-9s %-7s\n" 62275970Scy 63275970Scytypedef struct pktsum_s { 64275970Scy uint64_t ipackets; 65275970Scy uint64_t opackets; 66275970Scy uint64_t rbytes; 67275970Scy uint64_t obytes; 68275970Scy uint32_t ierrors; 69275970Scy uint32_t oerrors; 70275970Scy} pktsum_t; 71275970Scy 72275970Scytypedef struct show_link_state { 73275970Scy boolean_t ls_firstonly; 74275970Scy boolean_t ls_donefirst; 75275970Scy boolean_t ls_stats; 76275970Scy pktsum_t ls_prevstats; 77275970Scy boolean_t ls_parseable; 78275970Scy} show_link_state_t; 79275970Scy 80275970Scytypedef struct show_grp_state { 81275970Scy uint32_t gs_key; 82275970Scy boolean_t gs_lacp; 83275970Scy boolean_t gs_found; 84275970Scy boolean_t gs_stats; 85275970Scy boolean_t gs_firstonly; 86275970Scy pktsum_t gs_prevstats[MAXPORT]; 87275970Scy boolean_t gs_parseable; 88275970Scy} show_grp_state_t; 89275970Scy 90275970Scytypedef struct show_mac_state { 91275970Scy boolean_t ms_firstonly; 92275970Scy boolean_t ms_donefirst; 93275970Scy pktsum_t ms_prevstats; 94275970Scy boolean_t ms_parseable; 95275970Scy} show_mac_state_t; 96275970Scy 97275970Scytypedef struct port_state { 98275970Scy char *state_name; 99275970Scy aggr_port_state_t state_num; 100275970Scy} port_state_t; 101275970Scy 102275970Scystatic port_state_t port_states[] = { 103275970Scy {"standby", AGGR_PORT_STATE_STANDBY }, 104275970Scy {"attached", AGGR_PORT_STATE_ATTACHED } 105275970Scy}; 106275970Scy 107275970Scy#define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 108275970Scy 109275970Scytypedef void cmdfunc_t(int, char **); 110275970Scy 111275970Scystatic cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 112275970Scystatic cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 113275970Scystatic cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 114298770Sdelphijstatic cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 115298770Sdelphijstatic cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 116298770Sdelphijstatic cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 117298770Sdelphijstatic cmdfunc_t do_init_linkprop, do_init_secobj; 118298770Sdelphij 119298770Sdelphijstatic void show_linkprop_onelink(void *, const char *); 120298770Sdelphij 121298770Sdelphijstatic void link_stats(const char *, uint_t); 122275970Scystatic void aggr_stats(uint32_t, uint_t); 123275970Scystatic void dev_stats(const char *dev, uint32_t); 124275970Scy 125275970Scystatic void get_mac_stats(const char *, pktsum_t *); 126275970Scystatic void get_link_stats(const char *, pktsum_t *); 127275970Scystatic uint64_t mac_ifspeed(const char *); 128275970Scystatic char *mac_link_state(const char *); 129275970Scystatic char *mac_link_duplex(const char *); 130275970Scystatic void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 131275970Scystatic void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 132275970Scy 133275970Scystatic boolean_t str2int(const char *, int *); 134275970Scystatic void die(const char *, ...); 135275970Scystatic void die_optdup(int); 136275970Scystatic void die_opterr(int, int); 137275970Scystatic void die_laerr(laadm_diag_t, const char *, ...); 138275970Scystatic void die_wlerr(wladm_status_t, const char *, ...); 139275970Scystatic void die_dlerr(dladm_status_t, const char *, ...); 140275970Scystatic void warn(const char *, ...); 141275970Scystatic void warn_wlerr(wladm_status_t, const char *, ...); 142275970Scystatic void warn_dlerr(dladm_status_t, const char *, ...); 143275970Scy 144275970Scytypedef struct cmd { 145275970Scy char *c_name; 146275970Scy cmdfunc_t *c_fn; 147275970Scy} cmd_t; 148275970Scy 149275970Scystatic cmd_t cmds[] = { 150275970Scy { "show-link", do_show_link }, 151275970Scy { "show-dev", do_show_dev }, 152275970Scy { "create-aggr", do_create_aggr }, 153275970Scy { "delete-aggr", do_delete_aggr }, 154275970Scy { "add-aggr", do_add_aggr }, 155275970Scy { "remove-aggr", do_remove_aggr }, 156298770Sdelphij { "modify-aggr", do_modify_aggr }, 157275970Scy { "show-aggr", do_show_aggr }, 158275970Scy { "up-aggr", do_up_aggr }, 159275970Scy { "down-aggr", do_down_aggr }, 160275970Scy { "scan-wifi", do_scan_wifi }, 161275970Scy { "connect-wifi", do_connect_wifi }, 162275970Scy { "disconnect-wifi", do_disconnect_wifi }, 163275970Scy { "show-wifi", do_show_wifi }, 164298770Sdelphij { "show-linkprop", do_show_linkprop }, 165298770Sdelphij { "set-linkprop", do_set_linkprop }, 166275970Scy { "reset-linkprop", do_reset_linkprop }, 167275970Scy { "create-secobj", do_create_secobj }, 168275970Scy { "delete-secobj", do_delete_secobj }, 169275970Scy { "show-secobj", do_show_secobj }, 170275970Scy { "init-linkprop", do_init_linkprop }, 171275970Scy { "init-secobj", do_init_secobj } 172275970Scy}; 173298770Sdelphij 174275970Scystatic const struct option longopts[] = { 175275970Scy {"vlan-id", required_argument, 0, 'v' }, 176275970Scy {"dev", required_argument, 0, 'd' }, 177275970Scy {"policy", required_argument, 0, 'P' }, 178275970Scy {"lacp-mode", required_argument, 0, 'l' }, 179275970Scy {"lacp-timer", required_argument, 0, 'T' }, 180275970Scy {"unicast", required_argument, 0, 'u' }, 181275970Scy {"statistics", no_argument, 0, 's' }, 182275970Scy {"interval", required_argument, 0, 'i' }, 183275970Scy {"lacp", no_argument, 0, 'L' }, 184275970Scy {"temporary", no_argument, 0, 't' }, 185275970Scy {"root-dir", required_argument, 0, 'r' }, 186275970Scy {"parseable", no_argument, 0, 'p' }, 187275970Scy { 0, 0, 0, 0 } 188275970Scy}; 189275970Scy 190275970Scystatic const struct option prop_longopts[] = { 191275970Scy {"temporary", no_argument, 0, 't' }, 192275970Scy {"root-dir", required_argument, 0, 'R' }, 193275970Scy {"prop", required_argument, 0, 'p' }, 194275970Scy {"parseable", no_argument, 0, 'c' }, 195275970Scy {"persistent", no_argument, 0, 'P' }, 196275970Scy { 0, 0, 0, 0 } 197275970Scy}; 198275970Scy 199275970Scystatic const struct option wifi_longopts[] = { 200275970Scy {"parseable", no_argument, 0, 'p' }, 201275970Scy {"output", required_argument, 0, 'o' }, 202275970Scy {"essid", required_argument, 0, 'e' }, 203275970Scy {"bsstype", required_argument, 0, 'b' }, 204275970Scy {"mode", required_argument, 0, 'm' }, 205275970Scy {"key", required_argument, 0, 'k' }, 206275970Scy {"sec", required_argument, 0, 's' }, 207275970Scy {"auth", required_argument, 0, 'a' }, 208275970Scy {"create-ibss", required_argument, 0, 'c' }, 209275970Scy {"timeout", required_argument, 0, 'T' }, 210275970Scy {"all-links", no_argument, 0, 'a' }, 211275970Scy {"temporary", no_argument, 0, 't' }, 212275970Scy {"root-dir", required_argument, 0, 'R' }, 213275970Scy {"persistent", no_argument, 0, 'P' }, 214275970Scy {"file", required_argument, 0, 'f' }, 215275970Scy { 0, 0, 0, 0 } 216275970Scy}; 217275970Scy 218275970Scystatic char *progname; 219275970Scystatic sig_atomic_t signalled; 220275970Scy 221275970Scystatic void 222275970Scyusage(void) 223275970Scy{ 224275970Scy (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 225275970Scy "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 226275970Scy "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 227275970Scy "\n" 228275970Scy "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 229275970Scy "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 230275970Scy "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 231275970Scy "\t [-T <time>] [-u <address>] <key>\n" 232275970Scy "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 233275970Scy "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 234275970Scy "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 235275970Scy "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 236275970Scy "\n" 237275970Scy "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 238275970Scy "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 239275970Scy " [-s wep]\n" 240275970Scy "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 241275970Scy "\t [-T <time>] [<name>]\n" 242275970Scy "\tdisconnect-wifi [-a] [<name>]\n" 243275970Scy "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 244275970Scy "\n" 245275970Scy "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 246275970Scy " <name>\n" 247275970Scy "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 248275970Scy "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 249275970Scy "\n" 250275970Scy "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 251275970Scy " <secobj>\n" 252275970Scy "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 253275970Scy "\tshow-secobj [-pP][<secobj>,...]\n")); 254275970Scy exit(1); 255275970Scy} 256275970Scy 257275970Scyint 258275970Scymain(int argc, char *argv[]) 259275970Scy{ 260275970Scy int i; 261275970Scy cmd_t *cmdp; 262275970Scy 263275970Scy (void) setlocale(LC_ALL, ""); 264275970Scy#if !defined(TEXT_DOMAIN) 265275970Scy#define TEXT_DOMAIN "SYS_TEST" 266275970Scy#endif 267275970Scy (void) textdomain(TEXT_DOMAIN); 268275970Scy 269275970Scy progname = argv[0]; 270275970Scy 271275970Scy if (argc < 2) 272275970Scy usage(); 273275970Scy 274275970Scy if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 275275970Scy !priv_ineffect(PRIV_NET_RAWACCESS)) 276275970Scy die("insufficient privileges"); 277275970Scy 278275970Scy for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 279275970Scy cmdp = &cmds[i]; 280275970Scy if (strcmp(argv[1], cmdp->c_name) == 0) { 281275970Scy cmdp->c_fn(argc - 1, &argv[1]); 282275970Scy exit(0); 283275970Scy } 284275970Scy } 285275970Scy 286275970Scy (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 287275970Scy progname, argv[1]); 288275970Scy usage(); 289275970Scy 290275970Scy return (0); 291275970Scy} 292275970Scy 293275970Scystatic void 294275970Scydo_create_aggr(int argc, char *argv[]) 295275970Scy{ 296275970Scy char option; 297275970Scy int key; 298275970Scy uint32_t policy = AGGR_POLICY_L4; 299298770Sdelphij aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 300298770Sdelphij aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 301298770Sdelphij laadm_port_attr_db_t port[MAXPORT]; 302275970Scy uint_t nport = 0; 303275970Scy uint8_t mac_addr[ETHERADDRL]; 304275970Scy boolean_t mac_addr_fixed = B_FALSE; 305275970Scy boolean_t P_arg = B_FALSE; 306275970Scy boolean_t l_arg = B_FALSE; 307275970Scy boolean_t t_arg = B_FALSE; 308275970Scy boolean_t u_arg = B_FALSE; 309275970Scy boolean_t T_arg = B_FALSE; 310275970Scy char *altroot = NULL; 311275970Scy laadm_diag_t diag = 0; 312298770Sdelphij 313298770Sdelphij opterr = 0; 314298770Sdelphij while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 315275970Scy longopts, NULL)) != -1) { 316275970Scy switch (option) { 317275970Scy case 'd': 318275970Scy if (nport >= MAXPORT) 319275970Scy die("too many <dev> arguments"); 320275970Scy 321275970Scy if (strlcpy(port[nport].lp_devname, optarg, 322275970Scy MAXNAMELEN) >= MAXNAMELEN) 323275970Scy die("device name too long"); 324275970Scy 325275970Scy nport++; 326275970Scy break; 327275970Scy case 'P': 328275970Scy if (P_arg) 329275970Scy die_optdup(option); 330275970Scy 331275970Scy P_arg = B_TRUE; 332275970Scy if (!laadm_str_to_policy(optarg, &policy)) 333275970Scy die("invalid policy '%s'", optarg); 334275970Scy break; 335275970Scy case 'u': 336275970Scy if (u_arg) 337275970Scy die_optdup(option); 338275970Scy 339275970Scy u_arg = B_TRUE; 340275970Scy if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 341275970Scy mac_addr)) 342275970Scy die("invalid MAC address '%s'", optarg); 343275970Scy break; 344275970Scy case 'l': 345275970Scy if (l_arg) 346275970Scy die_optdup(option); 347298770Sdelphij 348298770Sdelphij l_arg = B_TRUE; 349298770Sdelphij if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 350298770Sdelphij die("invalid LACP mode '%s'", optarg); 351298770Sdelphij break; 352275970Scy case 'T': 353275970Scy if (T_arg) 354275970Scy die_optdup(option); 355275970Scy 356275970Scy T_arg = B_TRUE; 357275970Scy if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 358275970Scy die("invalid LACP timer value '%s'", optarg); 359275970Scy break; 360275970Scy case 't': 361275970Scy t_arg = B_TRUE; 362275970Scy break; 363275970Scy case 'R': 364298770Sdelphij altroot = optarg; 365298770Sdelphij break; 366298770Sdelphij default: 367298770Sdelphij die_opterr(optopt, option); 368298770Sdelphij break; 369275970Scy } 370275970Scy } 371275970Scy 372275970Scy if (nport == 0) 373275970Scy usage(); 374275970Scy 375275970Scy /* get key value (required last argument) */ 376275970Scy if (optind != (argc-1)) 377275970Scy usage(); 378275970Scy 379275970Scy if (!str2int(argv[optind], &key) || key < 1) 380275970Scy die("invalid key value '%s'", argv[optind]); 381275970Scy 382275970Scy if (laadm_create(key, nport, port, policy, mac_addr_fixed, 383275970Scy mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 384275970Scy die_laerr(diag, "create operation failed"); 385275970Scy} 386275970Scy 387298770Sdelphijstatic void 388298770Sdelphijdo_delete_aggr(int argc, char *argv[]) 389298770Sdelphij{ 390298770Sdelphij int key; 391298770Sdelphij char option; 392298770Sdelphij boolean_t t_arg = B_FALSE; 393275970Scy char *altroot = NULL; 394275970Scy laadm_diag_t diag = 0; 395275970Scy 396275970Scy opterr = 0; 397275970Scy while ((option = getopt_long(argc, argv, ":R:t", longopts, 398275970Scy NULL)) != -1) { 399275970Scy switch (option) { 400275970Scy case 't': 401275970Scy t_arg = B_TRUE; 402275970Scy break; 403275970Scy case 'R': 404275970Scy altroot = optarg; 405275970Scy break; 406275970Scy default: 407275970Scy die_opterr(optopt, option); 408275970Scy break; 409275970Scy } 410275970Scy } 411275970Scy 412275970Scy /* get key value (required last argument) */ 413275970Scy if (optind != (argc-1)) 414275970Scy usage(); 415275970Scy 416275970Scy if (!str2int(argv[optind], &key) || key < 1) 417275970Scy die("invalid key value '%s'", argv[optind]); 418275970Scy 419275970Scy if (laadm_delete(key, t_arg, altroot, &diag) < 0) 420275970Scy die_laerr(diag, "delete operation failed"); 421275970Scy} 422275970Scy 423275970Scystatic void 424275970Scydo_add_aggr(int argc, char *argv[]) 425275970Scy{ 426275970Scy char option; 427275970Scy int key; 428275970Scy laadm_port_attr_db_t port[MAXPORT]; 429275970Scy uint_t nport = 0; 430275970Scy boolean_t t_arg = B_FALSE; 431275970Scy char *altroot = NULL; 432275970Scy laadm_diag_t diag = 0; 433275970Scy 434275970Scy opterr = 0; 435280849Scy while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 436280849Scy NULL)) != -1) { 437280849Scy switch (option) { 438280849Scy case 'd': 439280849Scy if (nport >= MAXPORT) 440280849Scy die("too many <dev> arguments"); 441280849Scy 442280849Scy if (strlcpy(port[nport].lp_devname, optarg, 443280849Scy MAXNAMELEN) >= MAXNAMELEN) 444280849Scy die("device name too long"); 445280849Scy 446280849Scy nport++; 447280849Scy break; 448280849Scy case 't': 449275970Scy t_arg = B_TRUE; 450275970Scy break; 451275970Scy case 'R': 452275970Scy altroot = optarg; 453275970Scy break; 454275970Scy default: 455275970Scy die_opterr(optopt, option); 456275970Scy break; 457275970Scy } 458275970Scy } 459275970Scy 460275970Scy if (nport == 0) 461275970Scy usage(); 462275970Scy 463275970Scy /* get key value (required last argument) */ 464275970Scy if (optind != (argc-1)) 465275970Scy usage(); 466275970Scy 467275970Scy if (!str2int(argv[optind], &key) || key < 1) 468275970Scy die("invalid key value '%s'", argv[optind]); 469275970Scy 470275970Scy if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 471275970Scy /* 472275970Scy * checking ENOTSUP is a temporary workaround 473275970Scy * and should be removed once 6399681 is fixed. 474275970Scy */ 475275970Scy if (errno == ENOTSUP) { 476275970Scy (void) fprintf(stderr, 477275970Scy gettext("%s: add operation failed: %s\n"), 478275970Scy progname, 479275970Scy gettext("device capabilities don't match")); 480275970Scy exit(ENOTSUP); 481275970Scy } 482275970Scy die_laerr(diag, "add operation failed"); 483275970Scy } 484275970Scy} 485275970Scy 486275970Scystatic void 487275970Scydo_remove_aggr(int argc, char *argv[]) 488275970Scy{ 489275970Scy char option; 490275970Scy int key; 491275970Scy laadm_port_attr_db_t port[MAXPORT]; 492275970Scy uint_t nport = 0; 493275970Scy boolean_t t_arg = B_FALSE; 494275970Scy char *altroot = NULL; 495275970Scy laadm_diag_t diag = 0; 496275970Scy 497275970Scy opterr = 0; 498275970Scy while ((option = getopt_long(argc, argv, ":d:R:t", 499275970Scy longopts, NULL)) != -1) { 500275970Scy switch (option) { 501275970Scy case 'd': 502275970Scy if (nport >= MAXPORT) 503275970Scy die("too many <dev> arguments"); 504275970Scy 505275970Scy if (strlcpy(port[nport].lp_devname, optarg, 506275970Scy MAXNAMELEN) >= MAXNAMELEN) 507275970Scy die("device name too long"); 508275970Scy 509275970Scy nport++; 510275970Scy break; 511275970Scy case 't': 512275970Scy t_arg = B_TRUE; 513275970Scy break; 514275970Scy case 'R': 515275970Scy altroot = optarg; 516275970Scy break; 517275970Scy default: 518275970Scy die_opterr(optopt, option); 519275970Scy break; 520275970Scy } 521275970Scy } 522275970Scy 523275970Scy if (nport == 0) 524275970Scy usage(); 525275970Scy 526275970Scy /* get key value (required last argument) */ 527275970Scy if (optind != (argc-1)) 528275970Scy usage(); 529275970Scy 530275970Scy if (!str2int(argv[optind], &key) || key < 1) 531275970Scy die("invalid key value '%s'", argv[optind]); 532275970Scy 533275970Scy if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) 534275970Scy die_laerr(diag, "remove operation failed"); 535275970Scy} 536275970Scy 537275970Scystatic void 538298770Sdelphijdo_modify_aggr(int argc, char *argv[]) 539275970Scy{ 540275970Scy char option; 541275970Scy int key; 542275970Scy uint32_t policy = AGGR_POLICY_L4; 543275970Scy aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 544275970Scy aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 545275970Scy uint8_t mac_addr[ETHERADDRL]; 546275970Scy boolean_t mac_addr_fixed = B_FALSE; 547275970Scy uint8_t modify_mask = 0; 548275970Scy boolean_t t_arg = B_FALSE; 549275970Scy char *altroot = NULL; 550275970Scy laadm_diag_t diag = 0; 551275970Scy 552275970Scy opterr = 0; 553275970Scy while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 554275970Scy NULL)) != -1) { 555275970Scy switch (option) { 556275970Scy case 'P': 557275970Scy if (modify_mask & LAADM_MODIFY_POLICY) 558275970Scy die_optdup(option); 559275970Scy 560275970Scy modify_mask |= LAADM_MODIFY_POLICY; 561275970Scy 562275970Scy if (!laadm_str_to_policy(optarg, &policy)) 563275970Scy die("invalid policy '%s'", optarg); 564275970Scy break; 565275970Scy case 'u': 566275970Scy if (modify_mask & LAADM_MODIFY_MAC) 567275970Scy die_optdup(option); 568275970Scy 569275970Scy modify_mask |= LAADM_MODIFY_MAC; 570275970Scy 571275970Scy if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 572275970Scy mac_addr)) 573275970Scy die("invalid MAC address '%s'", optarg); 574275970Scy break; 575275970Scy case 'l': 576275970Scy if (modify_mask & LAADM_MODIFY_LACP_MODE) 577275970Scy die_optdup(option); 578275970Scy 579275970Scy modify_mask |= LAADM_MODIFY_LACP_MODE; 580275970Scy 581275970Scy if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 582275970Scy die("invalid LACP mode '%s'", optarg); 583275970Scy break; 584275970Scy case 'T': 585275970Scy if (modify_mask & LAADM_MODIFY_LACP_TIMER) 586275970Scy die_optdup(option); 587275970Scy 588275970Scy modify_mask |= LAADM_MODIFY_LACP_TIMER; 589275970Scy 590275970Scy if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 591275970Scy die("invalid LACP timer value '%s'", optarg); 592275970Scy break; 593275970Scy case 't': 594275970Scy t_arg = B_TRUE; 595275970Scy break; 596275970Scy case 'R': 597275970Scy altroot = optarg; 598275970Scy break; 599275970Scy default: 600275970Scy die_opterr(optopt, option); 601275970Scy break; 602275970Scy } 603275970Scy } 604275970Scy 605275970Scy if (modify_mask == 0) 606275970Scy die("at least one of the -PulT options must be specified"); 607275970Scy 608275970Scy /* get key value (required last argument) */ 609275970Scy if (optind != (argc-1)) 610275970Scy usage(); 611275970Scy 612275970Scy if (!str2int(argv[optind], &key) || key < 1) 613275970Scy die("invalid key value '%s'", argv[optind]); 614275970Scy 615275970Scy if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 616275970Scy lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 617275970Scy die_laerr(diag, "modify operation failed"); 618275970Scy} 619275970Scy 620275970Scystatic void 621275970Scydo_up_aggr(int argc, char *argv[]) 622275970Scy{ 623275970Scy int key = 0; 624275970Scy laadm_diag_t diag = 0; 625275970Scy 626275970Scy /* get aggregation key (optional last argument) */ 627275970Scy if (argc == 2) { 628275970Scy if (!str2int(argv[1], &key) || key < 1) 629275970Scy die("invalid key value '%s'", argv[1]); 630275970Scy } else if (argc > 2) { 631275970Scy usage(); 632275970Scy } 633275970Scy 634275970Scy if (laadm_up(key, NULL, &diag) < 0) { 635275970Scy if (key != 0) { 636275970Scy die_laerr(diag, "could not bring up aggregation '%u'", 637275970Scy key); 638275970Scy } else { 639275970Scy die_laerr(diag, "could not bring aggregations up"); 640275970Scy } 641275970Scy } 642275970Scy} 643275970Scy 644275970Scystatic void 645275970Scydo_down_aggr(int argc, char *argv[]) 646275970Scy{ 647275970Scy int key = 0; 648275970Scy 649275970Scy /* get aggregation key (optional last argument) */ 650275970Scy if (argc == 2) { 651275970Scy if (!str2int(argv[1], &key) || key < 1) 652275970Scy die("invalid key value '%s'", argv[1]); 653275970Scy } else if (argc > 2) { 654275970Scy usage(); 655275970Scy } 656275970Scy 657275970Scy if (laadm_down(key) < 0) { 658275970Scy if (key != 0) { 659275970Scy die("could not bring down aggregation '%u': %s", 660275970Scy key, strerror(errno)); 661275970Scy } else { 662275970Scy die("could not bring down aggregations: %s", 663275970Scy strerror(errno)); 664275970Scy } 665275970Scy } 666275970Scy} 667275970Scy 668275970Scy#define TYPE_WIDTH 10 669275970Scy 670275970Scystatic void 671275970Scyprint_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 672275970Scy{ 673275970Scy char type[TYPE_WIDTH]; 674275970Scy 675275970Scy if (!legacy) { 676275970Scy char drv[LIFNAMSIZ]; 677275970Scy int instance; 678275970Scy 679275970Scy if (dap->da_vid != 0) { 680275970Scy (void) snprintf(type, TYPE_WIDTH, "vlan %u", 681275970Scy dap->da_vid); 682275970Scy } else { 683275970Scy (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 684275970Scy } 685275970Scy if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 686275970Scy return; 687275970Scy if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 688275970Scy (void) printf("%s type=%s mtu=%d key=%u\n", 689275970Scy name, type, dap->da_max_sdu, instance); 690275970Scy } else { 691275970Scy (void) printf("%s type=%s mtu=%d device=%s\n", 692275970Scy name, type, dap->da_max_sdu, dap->da_dev); 693275970Scy } 694275970Scy } else { 695275970Scy (void) printf("%s type=legacy mtu=%d device=%s\n", 696275970Scy name, dap->da_max_sdu, name); 697275970Scy } 698275970Scy} 699275970Scy 700275970Scystatic void 701275970Scyprint_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 702275970Scy{ 703275970Scy char type[TYPE_WIDTH]; 704275970Scy 705275970Scy if (!legacy) { 706275970Scy char drv[LIFNAMSIZ]; 707275970Scy int instance; 708275970Scy 709275970Scy if (dap->da_vid != 0) { 710275970Scy (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 711275970Scy dap->da_vid); 712275970Scy } else { 713275970Scy (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 714275970Scy } 715275970Scy if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 716275970Scy return; 717275970Scy if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 718275970Scy (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 719275970Scy "\taggregation: key %u\n"), name, type, 720275970Scy dap->da_max_sdu, instance); 721275970Scy } else { 722275970Scy (void) printf(gettext("%-9s\ttype: %s\tmtu: " 723275970Scy "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 724275970Scy dap->da_dev); 725275970Scy } 726275970Scy } else { 727275970Scy (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 728298770Sdelphij "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 729275970Scy } 730275970Scy} 731275970Scy 732275970Scystatic int 733275970Scyget_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 734275970Scy{ 735275970Scy int err; 736275970Scy 737275970Scy if ((err = dladm_info(name, dlattrp)) == 0) { 738275970Scy *legacy = B_FALSE; 739275970Scy } else if (err < 0 && errno == ENODEV) { 740275970Scy int fd; 741275970Scy dlpi_if_attr_t dia; 742275970Scy dl_info_ack_t dlia; 743275970Scy 744275970Scy /* 745275970Scy * A return value of ENODEV means that the specified 746275970Scy * device is not gldv3. 747275970Scy */ 748275970Scy if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && 749275970Scy dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, 750275970Scy NULL, NULL) != -1) { 751275970Scy (void) dlpi_close(fd); 752275970Scy 753275970Scy *legacy = B_TRUE; 754275970Scy bzero(dlattrp, sizeof (*dlattrp)); 755275970Scy dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; 756275970Scy } else { 757275970Scy errno = ENOENT; 758275970Scy return (-1); 759275970Scy } 760275970Scy } else { 761275970Scy /* 762275970Scy * If the return value is not ENODEV, this means that 763275970Scy * user is either passing in a bogus interface name 764275970Scy * or a vlan interface name that doesn't exist yet. 765275970Scy */ 766275970Scy errno = ENOENT; 767275970Scy return (-1); 768275970Scy } 769275970Scy return (0); 770275970Scy} 771275970Scy 772275970Scy/* ARGSUSED */ 773275970Scystatic void 774275970Scyshow_link(void *arg, const char *name) 775275970Scy{ 776275970Scy dladm_attr_t dlattr; 777275970Scy boolean_t legacy = B_TRUE; 778275970Scy show_link_state_t *state = (show_link_state_t *)arg; 779275970Scy 780275970Scy if (get_if_info(name, &dlattr, &legacy) < 0) 781275970Scy die("invalid link '%s'", name); 782275970Scy 783275970Scy if (state->ls_parseable) { 784275970Scy print_link_parseable(name, &dlattr, legacy); 785275970Scy } else { 786275970Scy print_link(name, &dlattr, legacy); 787275970Scy } 788275970Scy} 789275970Scy 790275970Scystatic void 791275970Scyshow_link_stats(void *arg, const char *name) 792275970Scy{ 793275970Scy show_link_state_t *state = (show_link_state_t *)arg; 794275970Scy pktsum_t stats, diff_stats; 795275970Scy 796275970Scy if (state->ls_firstonly) { 797275970Scy if (state->ls_donefirst) 798275970Scy return; 799275970Scy state->ls_donefirst = B_TRUE; 800275970Scy } else { 801275970Scy bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 802275970Scy } 803275970Scy 804275970Scy get_link_stats(name, &stats); 805275970Scy stats_diff(&diff_stats, &stats, &state->ls_prevstats); 806275970Scy 807275970Scy (void) printf("%s", name); 808275970Scy (void) printf("\t\t%-10llu", diff_stats.ipackets); 809275970Scy (void) printf("%-12llu", diff_stats.rbytes); 810275970Scy (void) printf("%-8u", diff_stats.ierrors); 811275970Scy (void) printf("%-10llu", diff_stats.opackets); 812275970Scy (void) printf("%-12llu", diff_stats.obytes); 813275970Scy (void) printf("%-8u\n", diff_stats.oerrors); 814275970Scy 815275970Scy state->ls_prevstats = stats; 816275970Scy} 817275970Scy 818275970Scystatic void 819275970Scydump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 820275970Scy{ 821275970Scy char policy_str[LAADM_POLICY_STR_LEN]; 822275970Scy char addr_str[ETHERADDRL * 3]; 823275970Scy 824275970Scy if (!parseable) { 825275970Scy (void) printf(gettext("key: %d (0x%04x)"), 826275970Scy grp->lg_key, grp->lg_key); 827275970Scy 828275970Scy (void) printf(gettext("\tpolicy: %s"), 829275970Scy laadm_policy_to_str(grp->lg_policy, policy_str)); 830275970Scy 831275970Scy (void) printf(gettext("\taddress: %s (%s)\n"), 832275970Scy laadm_mac_addr_to_str(grp->lg_mac, addr_str), 833275970Scy (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 834275970Scy } else { 835275970Scy (void) printf("aggr key=%d", grp->lg_key); 836275970Scy 837275970Scy (void) printf(" policy=%s", 838275970Scy laadm_policy_to_str(grp->lg_policy, policy_str)); 839275970Scy 840275970Scy (void) printf(" address=%s", 841275970Scy laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 842275970Scy 843275970Scy (void) printf(" address-type=%s\n", 844275970Scy (grp->lg_mac_fixed) ? "fixed" : "auto"); 845275970Scy } 846275970Scy} 847275970Scy 848275970Scystatic void 849275970Scydump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 850275970Scy{ 851275970Scy const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 852275970Scy const char *lacp_timer_str = 853275970Scy laadm_lacp_timer_to_str(grp->lg_lacp_timer); 854275970Scy 855275970Scy if (!parseable) { 856275970Scy (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 857275970Scy (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 858275970Scy } else { 859275970Scy (void) printf(" lacp-mode=%s", lacp_mode_str); 860275970Scy (void) printf(" lacp-timer=%s\n", lacp_timer_str); 861275970Scy } 862275970Scy} 863275970Scy 864275970Scystatic void 865275970Scydump_grp_stats(laadm_grp_attr_sys_t *grp) 866275970Scy{ 867275970Scy (void) printf("key: %d", grp->lg_key); 868275970Scy (void) printf("\tipackets rbytes opackets obytes "); 869275970Scy (void) printf("%%ipkts %%opkts\n"); 870275970Scy} 871275970Scy 872275970Scystatic void 873275970Scydump_ports_lacp_head(void) 874275970Scy{ 875275970Scy (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 876275970Scy gettext("timeout"), gettext("aggregatable"), gettext("sync"), 877275970Scy gettext("coll"), gettext("dist"), gettext("defaulted"), 878275970Scy gettext("expired")); 879275970Scy} 880275970Scy 881275970Scystatic void 882275970Scydump_ports_head(void) 883275970Scy{ 884275970Scy (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 885275970Scy "state\n")); 886275970Scy} 887275970Scy 888275970Scystatic char * 889275970Scyport_state_to_str(aggr_port_state_t state_num) 890275970Scy{ 891275970Scy int i; 892275970Scy port_state_t *state; 893275970Scy 894275970Scy for (i = 0; i < NPORTSTATES; i++) { 895275970Scy state = &port_states[i]; 896275970Scy if (state->state_num == state_num) 897275970Scy return (state->state_name); 898275970Scy } 899275970Scy 900275970Scy return ("unknown"); 901275970Scy} 902275970Scy 903275970Scystatic void 904275970Scydump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 905275970Scy{ 906275970Scy char *dev = port->lp_devname; 907275970Scy char buf[ETHERADDRL * 3]; 908275970Scy 909275970Scy if (!parseable) { 910275970Scy (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 911275970Scy port->lp_mac, buf)); 912275970Scy (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) / 913275970Scy 1000000ull)); 914275970Scy (void) printf("\t%s", mac_link_duplex(dev)); 915275970Scy (void) printf("\t%s", mac_link_state(dev)); 916275970Scy (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 917275970Scy 918275970Scy } else { 919275970Scy (void) printf(" device=%s address=%s", dev, 920275970Scy laadm_mac_addr_to_str(port->lp_mac, buf)); 921275970Scy (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 922275970Scy 1000000ull)); 923275970Scy (void) printf(" duplex=%s", mac_link_duplex(dev)); 924275970Scy (void) printf(" link=%s", mac_link_state(dev)); 925275970Scy (void) printf(" port=%s", port_state_to_str(port->lp_state)); 926298770Sdelphij } 927298770Sdelphij} 928275970Scy 929275970Scystatic void 930275970Scydump_port_lacp(laadm_port_attr_sys_t *port) 931275970Scy{ 932275970Scy aggr_lacp_state_t *state = &port->lp_lacp_state; 933275970Scy 934275970Scy (void) printf(DUMP_LACP_FORMAT, 935275970Scy port->lp_devname, state->bit.activity ? "active" : "passive", 936275970Scy state->bit.timeout ? "short" : "long", 937298770Sdelphij state->bit.aggregation ? "yes" : "no", 938275970Scy state->bit.sync ? "yes" : "no", 939275970Scy state->bit.collecting ? "yes" : "no", 940275970Scy state->bit.distributing ? "yes" : "no", 941275970Scy state->bit.defaulted ? "yes" : "no", 942275970Scy state->bit.expired ? "yes" : "no"); 943275970Scy} 944275970Scy 945275970Scystatic void 946275970Scydump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 947275970Scy pktsum_t *tot_stats) 948275970Scy{ 949275970Scy pktsum_t diff_stats; 950275970Scy pktsum_t *old_stats = &state->gs_prevstats[index]; 951275970Scy 952275970Scy stats_diff(&diff_stats, port_stats, old_stats); 953275970Scy 954275970Scy (void) printf("\t%-10llu", diff_stats.ipackets); 955275970Scy (void) printf("%-12llu", diff_stats.rbytes); 956275970Scy (void) printf("%-10llu", diff_stats.opackets); 957275970Scy (void) printf("%-12llu", diff_stats.obytes); 958275970Scy 959275970Scy if (tot_stats->ipackets == 0) 960275970Scy (void) printf("\t-"); 961275970Scy else 962275970Scy (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 963275970Scy (double)tot_stats->ipackets * 100); 964275970Scy 965275970Scy if (tot_stats->opackets == 0) 966275970Scy (void) printf("\t-"); 967275970Scy else 968275970Scy (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 969275970Scy (double)tot_stats->opackets * 100); 970275970Scy 971275970Scy (void) printf("\n"); 972275970Scy 973275970Scy *old_stats = *port_stats; 974275970Scy} 975275970Scy 976275970Scystatic int 977275970Scyshow_key(void *arg, laadm_grp_attr_sys_t *grp) 978275970Scy{ 979275970Scy show_grp_state_t *state = (show_grp_state_t *)arg; 980275970Scy int i; 981275970Scy pktsum_t pktsumtot, port_stat; 982275970Scy 983275970Scy if (state->gs_key != 0 && state->gs_key != grp->lg_key) 984275970Scy return (0); 985275970Scy if (state->gs_firstonly) { 986275970Scy if (state->gs_found) 987275970Scy return (0); 988275970Scy } else { 989275970Scy bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 990275970Scy } 991275970Scy 992275970Scy state->gs_found = B_TRUE; 993275970Scy 994275970Scy if (state->gs_stats) { 995275970Scy /* show statistics */ 996275970Scy dump_grp_stats(grp); 997275970Scy 998275970Scy /* sum the ports statistics */ 999275970Scy bzero(&pktsumtot, sizeof (pktsumtot)); 1000275970Scy for (i = 0; i < grp->lg_nports; i++) { 1001275970Scy get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1002275970Scy stats_total(&pktsumtot, &port_stat, 1003275970Scy &state->gs_prevstats[i]); 1004275970Scy } 1005275970Scy 1006275970Scy (void) printf(" Total"); 1007275970Scy (void) printf("\t%-10llu", pktsumtot.ipackets); 1008275970Scy (void) printf("%-12llu", pktsumtot.rbytes); 1009275970Scy (void) printf("%-10llu", pktsumtot.opackets); 1010275970Scy (void) printf("%-12llu\n", pktsumtot.obytes); 1011275970Scy 1012275970Scy for (i = 0; i < grp->lg_nports; i++) { 1013275970Scy get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1014275970Scy (void) printf(" %s", grp->lg_ports[i].lp_devname); 1015275970Scy dump_port_stat(i, state, &port_stat, &pktsumtot); 1016275970Scy } 1017275970Scy } else if (state->gs_lacp) { 1018275970Scy /* show LACP info */ 1019275970Scy dump_grp(grp, state->gs_parseable); 1020275970Scy dump_grp_lacp(grp, state->gs_parseable); 1021275970Scy dump_ports_lacp_head(); 1022275970Scy for (i = 0; i < grp->lg_nports; i++) 1023275970Scy dump_port_lacp(&grp->lg_ports[i]); 1024275970Scy } else { 1025275970Scy dump_grp(grp, state->gs_parseable); 1026275970Scy if (!state->gs_parseable) 1027275970Scy dump_ports_head(); 1028275970Scy for (i = 0; i < grp->lg_nports; i++) { 1029275970Scy if (state->gs_parseable) 1030275970Scy (void) printf("dev key=%d", grp->lg_key); 1031275970Scy dump_port(&grp->lg_ports[i], state->gs_parseable); 1032275970Scy if (state->gs_parseable) 1033275970Scy (void) printf("\n"); 1034275970Scy } 1035275970Scy } 1036275970Scy 1037275970Scy return (0); 1038275970Scy} 1039275970Scy 1040275970Scystatic int 1041275970Scykstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 1042275970Scy{ 1043275970Scy kstat_named_t *knp; 1044275970Scy 1045275970Scy if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 1046275970Scy return (-1); 1047275970Scy 1048275970Scy if (knp->data_type != type) 1049275970Scy return (-1); 1050275970Scy 1051275970Scy switch (type) { 1052275970Scy case KSTAT_DATA_UINT64: 1053275970Scy *(uint64_t *)buf = knp->value.ui64; 1054275970Scy break; 1055275970Scy case KSTAT_DATA_UINT32: 1056275970Scy *(uint32_t *)buf = knp->value.ui32; 1057275970Scy break; 1058275970Scy default: 1059275970Scy return (-1); 1060275970Scy } 1061275970Scy 1062275970Scy return (0); 1063275970Scy} 1064275970Scy 1065275970Scystatic void 1066275970Scyshow_dev(void *arg, const char *dev) 1067275970Scy{ 1068275970Scy show_mac_state_t *state = (show_mac_state_t *)arg; 1069275970Scy 1070275970Scy (void) printf("%s", dev); 1071275970Scy 1072275970Scy if (!state->ms_parseable) { 1073275970Scy (void) printf(gettext("\t\tlink: %s"), 1074275970Scy mac_link_state(dev)); 1075275970Scy (void) printf(gettext("\tspeed: %5uMb"), 1076275970Scy (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1077275970Scy (void) printf(gettext("\tduplex: %s\n"), 1078298770Sdelphij mac_link_duplex(dev)); 1079275970Scy } else { 1080275970Scy (void) printf(" link=%s", mac_link_state(dev)); 1081275970Scy (void) printf(" speed=%u", 1082275970Scy (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1083275970Scy (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 1084275970Scy } 1085275970Scy} 1086275970Scy 1087275970Scy/*ARGSUSED*/ 1088275970Scystatic void 1089275970Scyshow_dev_stats(void *arg, const char *dev) 1090275970Scy{ 1091275970Scy show_mac_state_t *state = (show_mac_state_t *)arg; 1092275970Scy pktsum_t stats, diff_stats; 1093275970Scy 1094275970Scy if (state->ms_firstonly) { 1095275970Scy if (state->ms_donefirst) 1096275970Scy return; 1097275970Scy state->ms_donefirst = B_TRUE; 1098275970Scy } else { 1099275970Scy bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 1100275970Scy } 1101275970Scy 1102275970Scy get_mac_stats(dev, &stats); 1103275970Scy stats_diff(&diff_stats, &stats, &state->ms_prevstats); 1104275970Scy 1105275970Scy (void) printf("%s", dev); 1106275970Scy (void) printf("\t\t%-10llu", diff_stats.ipackets); 1107275970Scy (void) printf("%-12llu", diff_stats.rbytes); 1108275970Scy (void) printf("%-8u", diff_stats.ierrors); 1109275970Scy (void) printf("%-10llu", diff_stats.opackets); 1110275970Scy (void) printf("%-12llu", diff_stats.obytes); 1111275970Scy (void) printf("%-8u\n", diff_stats.oerrors); 1112275970Scy 1113275970Scy state->ms_prevstats = stats; 1114275970Scy} 1115275970Scy 1116275970Scystatic void 1117275970Scydo_show_link(int argc, char *argv[]) 1118275970Scy{ 1119275970Scy char *name = NULL; 1120275970Scy int option; 1121275970Scy boolean_t s_arg = B_FALSE; 1122275970Scy boolean_t i_arg = B_FALSE; 1123275970Scy int interval = 0; 1124275970Scy show_link_state_t state; 1125275970Scy 1126275970Scy state.ls_stats = B_FALSE; 1127275970Scy state.ls_parseable = B_FALSE; 1128275970Scy 1129275970Scy opterr = 0; 1130275970Scy while ((option = getopt_long(argc, argv, ":psi:", 1131275970Scy longopts, NULL)) != -1) { 1132275970Scy switch (option) { 1133275970Scy case 'p': 1134275970Scy state.ls_parseable = B_TRUE; 1135275970Scy break; 1136275970Scy case 's': 1137275970Scy if (s_arg) 1138275970Scy die_optdup(option); 1139275970Scy 1140275970Scy s_arg = B_TRUE; 1141275970Scy break; 1142275970Scy case 'i': 1143275970Scy if (i_arg) 1144275970Scy die_optdup(option); 1145275970Scy 1146275970Scy i_arg = B_TRUE; 1147275970Scy if (!str2int(optarg, &interval) || interval == 0) 1148275970Scy die("invalid interval value '%s'", optarg); 1149275970Scy break; 1150275970Scy default: 1151275970Scy die_opterr(optopt, option); 1152275970Scy break; 1153275970Scy } 1154275970Scy } 1155275970Scy 1156275970Scy if (i_arg && !s_arg) 1157275970Scy die("the option -i can be used only with -s"); 1158275970Scy 1159275970Scy /* get link name (optional last argument) */ 1160275970Scy if (optind == (argc-1)) 1161275970Scy name = argv[optind]; 1162275970Scy else if (optind != argc) 1163275970Scy usage(); 1164275970Scy 1165275970Scy if (s_arg) { 1166275970Scy link_stats(name, interval); 1167275970Scy return; 1168275970Scy } 1169275970Scy 1170275970Scy if (name == NULL) { 1171275970Scy (void) dladm_walk(show_link, &state); 1172275970Scy } else { 1173275970Scy show_link(&state, name); 1174275970Scy } 1175275970Scy} 1176275970Scy 1177275970Scystatic void 1178275970Scydo_show_aggr(int argc, char *argv[]) 1179275970Scy{ 1180275970Scy int option; 1181275970Scy int key = 0; 1182275970Scy boolean_t L_arg = B_FALSE; 1183275970Scy boolean_t s_arg = B_FALSE; 1184275970Scy boolean_t i_arg = B_FALSE; 1185275970Scy show_grp_state_t state; 1186275970Scy int interval = 0; 1187275970Scy 1188275970Scy state.gs_stats = B_FALSE; 1189275970Scy state.gs_lacp = B_FALSE; 1190275970Scy state.gs_parseable = B_FALSE; 1191275970Scy 1192275970Scy opterr = 0; 1193275970Scy while ((option = getopt_long(argc, argv, ":Lpsi:", 1194275970Scy longopts, NULL)) != -1) { 1195275970Scy switch (option) { 1196275970Scy case 'L': 1197275970Scy if (L_arg) 1198275970Scy die_optdup(option); 1199275970Scy 1200275970Scy if (s_arg || i_arg) { 1201275970Scy die("the option -L cannot be used with -i " 1202275970Scy "or -s"); 1203275970Scy } 1204275970Scy 1205275970Scy L_arg = B_TRUE; 1206275970Scy state.gs_lacp = B_TRUE; 1207275970Scy break; 1208275970Scy case 'p': 1209275970Scy state.gs_parseable = B_TRUE; 1210275970Scy break; 1211275970Scy case 's': 1212275970Scy if (s_arg) 1213275970Scy die_optdup(option); 1214275970Scy 1215275970Scy if (L_arg) 1216275970Scy die("the option -s cannot be used with -L"); 1217275970Scy 1218275970Scy s_arg = B_TRUE; 1219275970Scy break; 1220275970Scy case 'i': 1221275970Scy if (i_arg) 1222275970Scy die_optdup(option); 1223275970Scy 1224275970Scy if (L_arg) 1225275970Scy die("the option -i cannot be used with -L"); 1226275970Scy 1227275970Scy i_arg = B_TRUE; 1228275970Scy if (!str2int(optarg, &interval) || interval == 0) 1229275970Scy die("invalid interval value '%s'", optarg); 1230275970Scy break; 1231275970Scy default: 1232275970Scy die_opterr(optopt, option); 1233275970Scy break; 1234275970Scy } 1235275970Scy } 1236275970Scy 1237275970Scy if (i_arg && !s_arg) 1238275970Scy die("the option -i can be used only with -s"); 1239275970Scy 1240275970Scy /* get aggregation key (optional last argument) */ 1241275970Scy if (optind == (argc-1)) { 1242275970Scy if (!str2int(argv[optind], &key) || key < 1) 1243275970Scy die("invalid key value '%s'", argv[optind]); 1244275970Scy } else if (optind != argc) { 1245275970Scy usage(); 1246275970Scy } 1247275970Scy 1248275970Scy if (s_arg) { 1249275970Scy aggr_stats(key, interval); 1250275970Scy return; 1251275970Scy } 1252275970Scy 1253275970Scy state.gs_key = key; 1254275970Scy state.gs_found = B_FALSE; 1255275970Scy 1256275970Scy (void) laadm_walk_sys(show_key, &state); 1257275970Scy 1258275970Scy if (key != 0 && !state.gs_found) 1259275970Scy die("non-existent aggregation key '%u'", key); 1260275970Scy} 1261275970Scy 1262275970Scystatic void 1263275970Scydo_show_dev(int argc, char *argv[]) 1264275970Scy{ 1265275970Scy int option; 1266275970Scy char *dev = NULL; 1267275970Scy boolean_t s_arg = B_FALSE; 1268275970Scy boolean_t i_arg = B_FALSE; 1269275970Scy int interval = 0; 1270275970Scy show_mac_state_t state; 1271275970Scy 1272275970Scy state.ms_parseable = B_FALSE; 1273275970Scy 1274275970Scy opterr = 0; 1275275970Scy while ((option = getopt_long(argc, argv, ":psi:", 1276275970Scy longopts, NULL)) != -1) { 1277275970Scy switch (option) { 1278275970Scy case 'p': 1279275970Scy state.ms_parseable = B_TRUE; 1280275970Scy break; 1281275970Scy case 's': 1282275970Scy if (s_arg) 1283275970Scy die_optdup(option); 1284275970Scy 1285275970Scy s_arg = B_TRUE; 1286275970Scy break; 1287275970Scy case 'i': 1288275970Scy if (i_arg) 1289275970Scy die_optdup(option); 1290275970Scy 1291275970Scy i_arg = B_TRUE; 1292275970Scy if (!str2int(optarg, &interval) || interval == 0) 1293275970Scy die("invalid interval value '%s'", optarg); 1294275970Scy break; 1295275970Scy default: 1296275970Scy die_opterr(optopt, option); 1297275970Scy break; 1298275970Scy } 1299275970Scy } 1300275970Scy 1301275970Scy if (i_arg && !s_arg) 1302275970Scy die("the option -i can be used only with -s"); 1303275970Scy 1304275970Scy /* get dev name (optional last argument) */ 1305275970Scy if (optind == (argc-1)) 1306275970Scy dev = argv[optind]; 1307275970Scy else if (optind != argc) 1308275970Scy usage(); 1309275970Scy 1310275970Scy if (dev != NULL) { 1311275970Scy int index; 1312275970Scy char drv[LIFNAMSIZ]; 1313275970Scy dladm_attr_t dlattr; 1314275970Scy boolean_t legacy; 1315275970Scy 1316275970Scy /* 1317275970Scy * Check for invalid devices. 1318275970Scy * aggregations and vlans are not considered devices. 1319275970Scy */ 1320275970Scy if (strncmp(dev, "aggr", 4) == 0 || 1321275970Scy dlpi_if_parse(dev, drv, &index) < 0 || 1322275970Scy index >= 1000 || get_if_info(dev, &dlattr, &legacy) < 0) 1323275970Scy die("invalid device '%s'", dev); 1324275970Scy } 1325275970Scy 1326275970Scy if (s_arg) { 1327275970Scy dev_stats(dev, interval); 1328275970Scy return; 1329275970Scy } 1330275970Scy 1331275970Scy if (dev == NULL) 1332275970Scy (void) macadm_walk(show_dev, &state, B_TRUE); 1333275970Scy else 1334275970Scy show_dev(&state, dev); 1335275970Scy} 1336275970Scy 1337275970Scy/* ARGSUSED */ 1338275970Scystatic void 1339275970Scylink_stats(const char *link, uint_t interval) 1340275970Scy{ 1341275970Scy dladm_attr_t dlattr; 1342275970Scy boolean_t legacy; 1343275970Scy show_link_state_t state; 1344275970Scy 1345275970Scy if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 1346275970Scy die("invalid link '%s'", link); 1347275970Scy 1348275970Scy bzero(&state, sizeof (state)); 1349275970Scy 1350275970Scy /* 1351275970Scy * If an interval is specified, continuously show the stats 1352275970Scy * only for the first MAC port. 1353275970Scy */ 1354275970Scy state.ls_firstonly = (interval != 0); 1355275970Scy 1356275970Scy for (;;) { 1357275970Scy (void) printf("\t\tipackets rbytes ierrors "); 1358275970Scy (void) printf("opackets obytes oerrors\n"); 1359275970Scy 1360275970Scy state.ls_donefirst = B_FALSE; 1361275970Scy if (link == NULL) 1362275970Scy (void) dladm_walk(show_link_stats, &state); 1363275970Scy else 1364275970Scy show_link_stats(&state, link); 1365275970Scy 1366275970Scy if (interval == 0) 1367275970Scy break; 1368275970Scy 1369275970Scy (void) sleep(interval); 1370275970Scy } 1371275970Scy} 1372275970Scy 1373275970Scy/* ARGSUSED */ 1374275970Scystatic void 1375275970Scyaggr_stats(uint32_t key, uint_t interval) 1376275970Scy{ 1377275970Scy show_grp_state_t state; 1378275970Scy 1379275970Scy bzero(&state, sizeof (state)); 1380275970Scy state.gs_stats = B_TRUE; 1381275970Scy state.gs_key = key; 1382275970Scy 1383275970Scy /* 1384275970Scy * If an interval is specified, continuously show the stats 1385275970Scy * only for the first group. 1386275970Scy */ 1387275970Scy state.gs_firstonly = (interval != 0); 1388275970Scy 1389275970Scy for (;;) { 1390275970Scy state.gs_found = B_FALSE; 1391275970Scy (void) laadm_walk_sys(show_key, &state); 1392275970Scy if (state.gs_key != 0 && !state.gs_found) 1393275970Scy die("non-existent aggregation key '%u'", key); 1394275970Scy 1395275970Scy if (interval == 0) 1396275970Scy break; 1397275970Scy 1398275970Scy (void) sleep(interval); 1399275970Scy } 1400275970Scy} 1401275970Scy 1402275970Scy/* ARGSUSED */ 1403275970Scystatic void 1404275970Scydev_stats(const char *dev, uint32_t interval) 1405275970Scy{ 1406275970Scy show_mac_state_t state; 1407275970Scy 1408275970Scy bzero(&state, sizeof (state)); 1409275970Scy 1410275970Scy /* 1411275970Scy * If an interval is specified, continuously show the stats 1412298770Sdelphij * only for the first MAC port. 1413298770Sdelphij */ 1414298770Sdelphij state.ms_firstonly = (interval != 0); 1415275970Scy 1416275970Scy for (;;) { 1417275970Scy 1418275970Scy (void) printf("\t\tipackets rbytes ierrors "); 1419275970Scy (void) printf("opackets obytes oerrors\n"); 1420275970Scy 1421275970Scy state.ms_donefirst = B_FALSE; 1422275970Scy if (dev == NULL) 1423275970Scy (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1424275970Scy else 1425275970Scy show_dev_stats(&state, dev); 1426275970Scy 1427275970Scy if (interval == 0) 1428275970Scy break; 1429275970Scy 1430275970Scy (void) sleep(interval); 1431275970Scy } 1432275970Scy} 1433275970Scy 1434275970Scy/* accumulate stats (s1 += (s2 - s3)) */ 1435275970Scystatic void 1436275970Scystats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1437275970Scy{ 1438275970Scy s1->ipackets += (s2->ipackets - s3->ipackets); 1439275970Scy s1->opackets += (s2->opackets - s3->opackets); 1440275970Scy s1->rbytes += (s2->rbytes - s3->rbytes); 1441275970Scy s1->obytes += (s2->obytes - s3->obytes); 1442275970Scy s1->ierrors += (s2->ierrors - s3->ierrors); 1443275970Scy s1->oerrors += (s2->oerrors - s3->oerrors); 1444275970Scy} 1445275970Scy 1446275970Scy/* compute stats differences (s1 = s2 - s3) */ 1447275970Scystatic void 1448275970Scystats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1449275970Scy{ 1450275970Scy s1->ipackets = s2->ipackets - s3->ipackets; 1451275970Scy s1->opackets = s2->opackets - s3->opackets; 1452275970Scy s1->rbytes = s2->rbytes - s3->rbytes; 1453275970Scy s1->obytes = s2->obytes - s3->obytes; 1454275970Scy s1->ierrors = s2->ierrors - s3->ierrors; 1455275970Scy s1->oerrors = s2->oerrors - s3->oerrors; 1456275970Scy} 1457298770Sdelphij 1458298770Sdelphij/* 1459298770Sdelphij * In the following routines, we do the first kstat_lookup() assuming that 1460275970Scy * the device is gldv3-based and that the kstat name is the one passed in 1461275970Scy * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1462275970Scy * omitting the kstat name. This second lookup is needed for getting kstats 1463275970Scy * from legacy devices. This can fail too if the device is not attached or 1464275970Scy * the device is legacy and doesn't export the kstats we need. 1465275970Scy */ 1466275970Scystatic void 1467275970Scyget_stats(char *module, int instance, char *name, pktsum_t *stats) 1468275970Scy{ 1469298770Sdelphij kstat_ctl_t *kcp; 1470275970Scy kstat_t *ksp; 1471298770Sdelphij 1472275970Scy if ((kcp = kstat_open()) == NULL) { 1473275970Scy warn("kstat open operation failed"); 1474275970Scy return; 1475275970Scy } 1476275970Scy 1477275970Scy if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1478275970Scy (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1479275970Scy /* 1480275970Scy * The kstat query could fail if the underlying MAC 1481275970Scy * driver was already detached. 1482275970Scy */ 1483275970Scy (void) kstat_close(kcp); 1484275970Scy return; 1485275970Scy } 1486275970Scy 1487275970Scy if (kstat_read(kcp, ksp, NULL) == -1) 1488275970Scy goto bail; 1489275970Scy 1490275970Scy if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 1491275970Scy &stats->ipackets) < 0) 1492275970Scy goto bail; 1493275970Scy 1494275970Scy if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 1495275970Scy &stats->opackets) < 0) 1496275970Scy goto bail; 1497275970Scy 1498275970Scy if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 1499275970Scy &stats->rbytes) < 0) 1500275970Scy goto bail; 1501275970Scy 1502275970Scy if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 1503275970Scy &stats->obytes) < 0) 1504275970Scy goto bail; 1505275970Scy 1506275970Scy if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 1507275970Scy &stats->ierrors) < 0) 1508275970Scy goto bail; 1509275970Scy 1510275970Scy if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 1511275970Scy &stats->oerrors) < 0) 1512275970Scy goto bail; 1513275970Scy 1514275970Scy (void) kstat_close(kcp); 1515275970Scy return; 1516275970Scy 1517275970Scybail: 1518275970Scy (void) kstat_close(kcp); 1519275970Scy} 1520275970Scy 1521275970Scystatic void 1522275970Scyget_mac_stats(const char *dev, pktsum_t *stats) 1523275970Scy{ 1524275970Scy char module[LIFNAMSIZ]; 1525275970Scy int instance; 1526275970Scy 1527275970Scy if (dlpi_if_parse(dev, module, &instance) != 0) 1528275970Scy return; 1529298770Sdelphij bzero(stats, sizeof (*stats)); 1530298770Sdelphij get_stats(module, instance, "mac", stats); 1531298770Sdelphij} 1532275970Scy 1533275970Scystatic void 1534275970Scyget_link_stats(const char *link, pktsum_t *stats) 1535275970Scy{ 1536275970Scy char module[LIFNAMSIZ]; 1537275970Scy int instance; 1538275970Scy 1539275970Scy if (dlpi_if_parse(link, module, &instance) != 0) 1540275970Scy return; 1541275970Scy bzero(stats, sizeof (*stats)); 1542275970Scy get_stats(module, instance, (char *)link, stats); 1543275970Scy} 1544275970Scy 1545275970Scystatic int 1546275970Scyget_single_mac_stat(const char *dev, const char *name, uint8_t type, 1547275970Scy void *val) 1548275970Scy{ 1549275970Scy char module[LIFNAMSIZ]; 1550275970Scy int instance; 1551275970Scy kstat_ctl_t *kcp; 1552275970Scy kstat_t *ksp; 1553275970Scy 1554275970Scy if ((kcp = kstat_open()) == NULL) { 1555275970Scy warn("kstat open operation failed"); 1556275970Scy return (-1); 1557275970Scy } 1558275970Scy 1559275970Scy if (dlpi_if_parse(dev, module, &instance) != 0) 1560275970Scy return (-1); 1561275970Scy if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1562275970Scy (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1563275970Scy /* 1564275970Scy * The kstat query could fail if the underlying MAC 1565275970Scy * driver was already detached. 1566275970Scy */ 1567275970Scy goto bail; 1568275970Scy } 1569275970Scy 1570275970Scy if (kstat_read(kcp, ksp, NULL) == -1) { 1571275970Scy warn("kstat read failed"); 1572275970Scy goto bail; 1573275970Scy } 1574275970Scy 1575275970Scy if (kstat_value(ksp, name, type, val) < 0) 1576275970Scy goto bail; 1577275970Scy 1578275970Scy (void) kstat_close(kcp); 1579275970Scy return (0); 1580275970Scy 1581275970Scybail: 1582275970Scy (void) kstat_close(kcp); 1583275970Scy return (-1); 1584275970Scy} 1585275970Scy 1586275970Scystatic uint64_t 1587275970Scymac_ifspeed(const char *dev) 1588275970Scy{ 1589275970Scy uint64_t ifspeed = 0; 1590298770Sdelphij 1591298770Sdelphij (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 1592298770Sdelphij return (ifspeed); 1593275970Scy} 1594275970Scy 1595275970Scystatic char * 1596275970Scymac_link_state(const char *dev) 1597275970Scy{ 1598275970Scy link_state_t link_state; 1599275970Scy char *state_str = "unknown"; 1600275970Scy 1601275970Scy if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1602275970Scy &link_state) != 0) { 1603275970Scy return (state_str); 1604275970Scy } 1605275970Scy 1606275970Scy switch (link_state) { 1607275970Scy case LINK_STATE_UP: 1608275970Scy state_str = "up"; 1609275970Scy break; 1610275970Scy case LINK_STATE_DOWN: 1611275970Scy state_str = "down"; 1612275970Scy break; 1613275970Scy default: 1614275970Scy break; 1615275970Scy } 1616275970Scy 1617275970Scy return (state_str); 1618275970Scy} 1619275970Scy 1620275970Scy 1621275970Scystatic char * 1622275970Scymac_link_duplex(const char *dev) 1623275970Scy{ 1624275970Scy link_duplex_t link_duplex; 1625275970Scy char *duplex_str = "unknown"; 1626275970Scy 1627275970Scy if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1628275970Scy &link_duplex) != 0) { 1629275970Scy return (duplex_str); 1630275970Scy } 1631275970Scy 1632275970Scy switch (link_duplex) { 1633275970Scy case LINK_DUPLEX_FULL: 1634275970Scy duplex_str = "full"; 1635275970Scy break; 1636275970Scy case LINK_DUPLEX_HALF: 1637275970Scy duplex_str = "half"; 1638275970Scy break; 1639275970Scy default: 1640275970Scy break; 1641275970Scy } 1642275970Scy 1643275970Scy return (duplex_str); 1644275970Scy} 1645275970Scy 1646275970Scy#define WIFI_CMD_SCAN 0x00000001 1647275970Scy#define WIFI_CMD_SHOW 0x00000002 1648275970Scy#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 1649275970Scytypedef struct wifi_field { 1650275970Scy const char *wf_name; 1651275970Scy const char *wf_header; 1652298770Sdelphij uint_t wf_width; 1653298770Sdelphij uint_t wf_mask; 1654298770Sdelphij uint_t wf_cmdtype; 1655275970Scy} wifi_field_t; 1656275970Scy 1657275970Scystatic wifi_field_t wifi_fields[] = { 1658275970Scy{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, 1659275970Scy{ "essid", "ESSID", 19, WLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 1660275970Scy{ "bssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 1661275970Scy{ "ibssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 1662275970Scy{ "mode", "MODE", 6, WLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 1663275970Scy{ "speed", "SPEED", 6, WLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 1664275970Scy{ "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 1665275970Scy{ "bsstype", "BSSTYPE", 8, WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 1666275970Scy{ "sec", "SEC", 6, WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 1667275970Scy{ "status", "STATUS", 17, WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW}, 1668275970Scy{ "strength", "STRENGTH", 10, WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 1669275970Scy; 1670275970Scy 1671275970Scystatic char *all_scan_wifi_fields = 1672275970Scy "link,essid,bssid,sec,strength,mode,speed,bsstype"; 1673275970Scystatic char *all_show_wifi_fields = 1674275970Scy "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 1675275970Scystatic char *def_scan_wifi_fields = 1676275970Scy "link,essid,bssid,sec,strength,mode,speed"; 1677275970Scystatic char *def_show_wifi_fields = 1678275970Scy "link,status,essid,sec,strength,mode,speed"; 1679275970Scy 1680275970Scy#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 1681275970Scy#define WIFI_MAX_FIELD_LEN 32 1682275970Scy 1683275970Scytypedef struct { 1684275970Scy char *s_buf; 1685275970Scy char **s_fields; /* array of pointer to the fields in s_buf */ 1686275970Scy uint_t s_nfields; /* the number of fields in s_buf */ 1687275970Scy} split_t; 1688275970Scy 1689275970Scy/* 1690275970Scy * Free the split_t structure pointed to by `sp'. 1691275970Scy */ 1692275970Scystatic void 1693275970Scysplitfree(split_t *sp) 1694275970Scy{ 1695275970Scy free(sp->s_buf); 1696275970Scy free(sp->s_fields); 1697275970Scy free(sp); 1698275970Scy} 1699275970Scy 1700275970Scy/* 1701275970Scy * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 1702275970Scy * length. Return a pointer to a split_t containing the split fields, or NULL 1703275970Scy * on failure. 1704275970Scy */ 1705275970Scystatic split_t * 1706275970Scysplit(const char *str, uint_t maxfields, uint_t maxlen) 1707275970Scy{ 1708275970Scy char *field, *token, *lasts = NULL; 1709275970Scy split_t *sp; 1710275970Scy 1711275970Scy if (*str == '\0' || maxfields == 0 || maxlen == 0) 1712275970Scy return (NULL); 1713275970Scy 1714275970Scy sp = calloc(sizeof (split_t), 1); 1715275970Scy if (sp == NULL) 1716275970Scy return (NULL); 1717275970Scy 1718275970Scy sp->s_buf = strdup(str); 1719275970Scy sp->s_fields = malloc(sizeof (char *) * maxfields); 1720275970Scy if (sp->s_buf == NULL || sp->s_fields == NULL) 1721298770Sdelphij goto fail; 1722298770Sdelphij 1723298770Sdelphij token = sp->s_buf; 1724298770Sdelphij while ((field = strtok_r(token, ",", &lasts)) != NULL) { 1725298770Sdelphij if (sp->s_nfields == maxfields || strlen(field) > maxlen) 1726275970Scy goto fail; 1727275970Scy token = NULL; 1728275970Scy sp->s_fields[sp->s_nfields++] = field; 1729275970Scy } 1730275970Scy return (sp); 1731275970Scyfail: 1732275970Scy splitfree(sp); 1733275970Scy return (NULL); 1734275970Scy} 1735275970Scy 1736275970Scystatic int 1737275970Scyparse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 1738275970Scy uint_t cmdtype) 1739275970Scy{ 1740275970Scy uint_t i, j; 1741275970Scy wifi_field_t **wf = NULL; 1742275970Scy split_t *sp; 1743275970Scy boolean_t good_match = B_FALSE; 1744275970Scy 1745275970Scy if (cmdtype == WIFI_CMD_SCAN) { 1746275970Scy if (str == NULL) 1747275970Scy str = def_scan_wifi_fields; 1748275970Scy if (strcasecmp(str, "all") == 0) 1749275970Scy str = all_scan_wifi_fields; 1750275970Scy } else if (cmdtype == WIFI_CMD_SHOW) { 1751275970Scy if (str == NULL) 1752275970Scy str = def_show_wifi_fields; 1753275970Scy if (strcasecmp(str, "all") == 0) 1754275970Scy str = all_show_wifi_fields; 1755275970Scy } else { 1756275970Scy return (-1); 1757275970Scy } 1758275970Scy 1759275970Scy sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 1760275970Scy if (sp == NULL) 1761275970Scy return (-1); 1762275970Scy 1763275970Scy wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 1764275970Scy if (wf == NULL) 1765275970Scy goto fail; 1766275970Scy 1767275970Scy for (i = 0; i < sp->s_nfields; i++) { 1768275970Scy for (j = 0; j < WIFI_MAX_FIELDS; j++) { 1769275970Scy if (strcasecmp(sp->s_fields[i], 1770275970Scy wifi_fields[j].wf_name) == 0) { 1771275970Scy good_match = wifi_fields[j]. 1772275970Scy wf_cmdtype & cmdtype; 1773275970Scy break; 1774275970Scy } 1775275970Scy } 1776275970Scy if (!good_match) 1777275970Scy goto fail; 1778275970Scy 1779275970Scy good_match = B_FALSE; 1780275970Scy wf[i] = &wifi_fields[j]; 1781275970Scy } 1782275970Scy *countp = i; 1783275970Scy *fields = wf; 1784275970Scy splitfree(sp); 1785275970Scy return (0); 1786275970Scyfail: 1787275970Scy free(wf); 1788275970Scy splitfree(sp); 1789275970Scy return (-1); 1790275970Scy} 1791275970Scy 1792275970Scytypedef struct print_wifi_state { 1793275970Scy const char *ws_link; 1794275970Scy boolean_t ws_parseable; 1795298770Sdelphij boolean_t ws_header; 1796298770Sdelphij wifi_field_t **ws_fields; 1797298770Sdelphij uint_t ws_nfields; 1798275970Scy boolean_t ws_lastfield; 1799275970Scy uint_t ws_overflow; 1800275970Scy} print_wifi_state_t; 1801275970Scy 1802275970Scystatic void 1803275970Scyprint_wifi_head(print_wifi_state_t *statep) 1804275970Scy{ 1805275970Scy int i; 1806275970Scy wifi_field_t *wfp; 1807275970Scy 1808275970Scy for (i = 0; i < statep->ws_nfields; i++) { 1809275970Scy wfp = statep->ws_fields[i]; 1810275970Scy if (i + 1 < statep->ws_nfields) 1811275970Scy (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 1812275970Scy else 1813275970Scy (void) printf("%s", wfp->wf_header); 1814275970Scy } 1815275970Scy (void) printf("\n"); 1816275970Scy} 1817275970Scy 1818275970Scystatic void 1819275970Scyprint_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 1820275970Scy const char *value) 1821275970Scy{ 1822275970Scy uint_t width = wfp->wf_width; 1823275970Scy uint_t valwidth = strlen(value); 1824275970Scy uint_t compress; 1825275970Scy 1826275970Scy if (statep->ws_parseable) { 1827275970Scy (void) printf("%s=\"%s\"", wfp->wf_header, value); 1828275970Scy } else { 1829275970Scy if (value[0] == '\0') 1830275970Scy value = "--"; 1831275970Scy if (statep->ws_lastfield) { 1832275970Scy (void) printf("%s", value); 1833275970Scy return; 1834275970Scy } 1835275970Scy 1836275970Scy if (valwidth > width) { 1837275970Scy statep->ws_overflow += valwidth - width; 1838275970Scy } else if (valwidth < width && statep->ws_overflow > 0) { 1839275970Scy compress = min(statep->ws_overflow, width - valwidth); 1840275970Scy statep->ws_overflow -= compress; 1841275970Scy width -= compress; 1842275970Scy } 1843275970Scy (void) printf("%-*s", width, value); 1844275970Scy } 1845275970Scy 1846275970Scy if (!statep->ws_lastfield) 1847275970Scy (void) putchar(' '); 1848275970Scy} 1849275970Scy 1850275970Scystatic void 1851275970Scyprint_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 1852275970Scy wladm_wlan_attr_t *attrp) 1853275970Scy{ 1854275970Scy char buf[WLADM_STRSIZE]; 1855275970Scy const char *str = ""; 1856275970Scy 1857275970Scy if (wfp->wf_mask == 0) { 1858275970Scy print_wifi_field(statep, wfp, statep->ws_link); 1859275970Scy return; 1860275970Scy } 1861275970Scy 1862275970Scy if ((wfp->wf_mask & attrp->wa_valid) == 0) { 1863275970Scy print_wifi_field(statep, wfp, ""); 1864275970Scy return; 1865275970Scy } 1866275970Scy 1867275970Scy switch (wfp->wf_mask) { 1868275970Scy case WLADM_WLAN_ATTR_ESSID: 1869275970Scy str = wladm_essid2str(&attrp->wa_essid, buf); 1870275970Scy break; 1871275970Scy case WLADM_WLAN_ATTR_BSSID: 1872275970Scy str = wladm_bssid2str(&attrp->wa_bssid, buf); 1873275970Scy break; 1874275970Scy case WLADM_WLAN_ATTR_SECMODE: 1875275970Scy str = wladm_secmode2str(&attrp->wa_secmode, buf); 1876275970Scy break; 1877275970Scy case WLADM_WLAN_ATTR_STRENGTH: 1878275970Scy str = wladm_strength2str(&attrp->wa_strength, buf); 1879275970Scy break; 1880275970Scy case WLADM_WLAN_ATTR_MODE: 1881275970Scy str = wladm_mode2str(&attrp->wa_mode, buf); 1882275970Scy break; 1883275970Scy case WLADM_WLAN_ATTR_SPEED: 1884275970Scy str = wladm_speed2str(&attrp->wa_speed, buf); 1885275970Scy (void) strlcat(buf, "Mb", sizeof (buf)); 1886275970Scy break; 1887275970Scy case WLADM_WLAN_ATTR_AUTH: 1888275970Scy str = wladm_auth2str(&attrp->wa_auth, buf); 1889275970Scy break; 1890275970Scy case WLADM_WLAN_ATTR_BSSTYPE: 1891275970Scy str = wladm_bsstype2str(&attrp->wa_bsstype, buf); 1892275970Scy break; 1893275970Scy } 1894275970Scy 1895275970Scy print_wifi_field(statep, wfp, str); 1896275970Scy} 1897275970Scy 1898275970Scystatic boolean_t 1899275970Scyprint_scan_results(void *arg, wladm_wlan_attr_t *attrp) 1900275970Scy{ 1901275970Scy print_wifi_state_t *statep = arg; 1902275970Scy int i; 1903275970Scy 1904275970Scy if (statep->ws_header) { 1905275970Scy statep->ws_header = B_FALSE; 1906275970Scy if (!statep->ws_parseable) 1907275970Scy print_wifi_head(statep); 1908275970Scy } 1909275970Scy 1910275970Scy statep->ws_overflow = 0; 1911275970Scy for (i = 0; i < statep->ws_nfields; i++) { 1912275970Scy statep->ws_lastfield = (i + 1 == statep->ws_nfields); 1913275970Scy print_wlan_attr(statep, statep->ws_fields[i], attrp); 1914275970Scy } 1915275970Scy (void) putchar('\n'); 1916275970Scy return (B_TRUE); 1917275970Scy} 1918275970Scy 1919275970Scystatic boolean_t 1920275970Scyscan_wifi(void *arg, const char *link) 1921275970Scy{ 1922275970Scy print_wifi_state_t *statep = arg; 1923275970Scy wladm_status_t status; 1924275970Scy 1925275970Scy statep->ws_link = link; 1926275970Scy status = wladm_scan(link, statep, print_scan_results); 1927275970Scy if (status != WLADM_STATUS_OK) 1928275970Scy die_wlerr(status, "cannot scan link '%s'", link); 1929275970Scy 1930275970Scy return (B_TRUE); 1931275970Scy} 1932275970Scy 1933275970Scystatic void 1934275970Scyprint_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 1935275970Scy wladm_link_attr_t *attrp) 1936275970Scy{ 1937275970Scy char buf[WLADM_STRSIZE]; 1938275970Scy const char *str = ""; 1939275970Scy 1940275970Scy if (strcmp(wfp->wf_name, "status") == 0) { 1941275970Scy if ((wfp->wf_mask & attrp->la_valid) != 0) 1942275970Scy str = wladm_linkstatus2str(&attrp->la_status, buf); 1943275970Scy print_wifi_field(statep, wfp, str); 1944275970Scy return; 1945275970Scy } 1946275970Scy print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 1947275970Scy} 1948275970Scy 1949275970Scystatic boolean_t 1950289997Sglebiusshow_wifi(void *arg, const char *link) 1951275970Scy{ 1952275970Scy int i; 1953275970Scy print_wifi_state_t *statep = arg; 1954275970Scy wladm_link_attr_t attr; 1955275970Scy wladm_status_t status; 1956275970Scy 1957275970Scy status = wladm_get_link_attr(link, &attr); 1958275970Scy if (status != WLADM_STATUS_OK) 1959275970Scy die_wlerr(status, "cannot get link attributes for '%s'", link); 1960275970Scy 1961275970Scy if (statep->ws_header) { 1962275970Scy statep->ws_header = B_FALSE; 1963275970Scy if (!statep->ws_parseable) 1964275970Scy print_wifi_head(statep); 1965275970Scy } 1966275970Scy 1967275970Scy statep->ws_link = link; 1968275970Scy statep->ws_overflow = 0; 1969275970Scy for (i = 0; i < statep->ws_nfields; i++) { 1970275970Scy statep->ws_lastfield = (i + 1 == statep->ws_nfields); 1971275970Scy print_link_attr(statep, statep->ws_fields[i], &attr); 1972275970Scy } 1973275970Scy (void) putchar('\n'); 1974275970Scy return (B_TRUE); 1975275970Scy} 1976275970Scy 1977275970Scystatic void 1978275970Scydo_display_wifi(int argc, char **argv, int cmd) 1979275970Scy{ 1980275970Scy int option; 1981275970Scy char *fields_str = NULL; 1982275970Scy wifi_field_t **fields; 1983275970Scy boolean_t (*callback)(void *, const char *); 1984275970Scy uint_t nfields; 1985275970Scy print_wifi_state_t state; 1986275970Scy wladm_status_t status; 1987275970Scy 1988275970Scy if (cmd == WIFI_CMD_SCAN) 1989275970Scy callback = scan_wifi; 1990275970Scy else if (cmd == WIFI_CMD_SHOW) 1991275970Scy callback = show_wifi; 1992275970Scy else 1993275970Scy return; 1994275970Scy 1995275970Scy state.ws_link = NULL; 1996275970Scy state.ws_parseable = B_FALSE; 1997275970Scy state.ws_header = B_TRUE; 1998275970Scy opterr = 0; 1999275970Scy while ((option = getopt_long(argc, argv, ":o:p", 2000275970Scy wifi_longopts, NULL)) != -1) { 2001275970Scy switch (option) { 2002275970Scy case 'o': 2003275970Scy fields_str = optarg; 2004275970Scy break; 2005275970Scy case 'p': 2006275970Scy state.ws_parseable = B_TRUE; 2007275970Scy if (fields_str == NULL) 2008275970Scy fields_str = "all"; 2009275970Scy break; 2010275970Scy default: 2011275970Scy die_opterr(optopt, option); 2012275970Scy break; 2013275970Scy } 2014275970Scy } 2015275970Scy 2016275970Scy if (optind == (argc - 1)) 2017275970Scy state.ws_link = argv[optind]; 2018275970Scy else if (optind != argc) 2019275970Scy usage(); 2020275970Scy 2021275970Scy if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 2022275970Scy die("invalid field(s) specified"); 2023275970Scy 2024275970Scy state.ws_fields = fields; 2025275970Scy state.ws_nfields = nfields; 2026275970Scy 2027275970Scy if (state.ws_link == NULL) { 2028275970Scy status = wladm_walk(&state, callback); 2029275970Scy if (status != WLADM_STATUS_OK) 2030275970Scy die_wlerr(status, "cannot walk wifi links"); 2031275970Scy } else { 2032275970Scy (void) (*callback)(&state, state.ws_link); 2033275970Scy } 2034275970Scy free(fields); 2035275970Scy} 2036275970Scy 2037275970Scystatic void 2038275970Scydo_scan_wifi(int argc, char **argv) 2039275970Scy{ 2040275970Scy do_display_wifi(argc, argv, WIFI_CMD_SCAN); 2041275970Scy} 2042289997Sglebius 2043275970Scystatic void 2044275970Scydo_show_wifi(int argc, char **argv) 2045275970Scy{ 2046275970Scy do_display_wifi(argc, argv, WIFI_CMD_SHOW); 2047275970Scy} 2048275970Scy 2049275970Scytypedef struct wlan_count_attr { 2050275970Scy uint_t wc_count; 2051275970Scy const char *wc_link; 2052275970Scy} wlan_count_attr_t; 2053275970Scy 2054275970Scystatic boolean_t 2055275970Scydo_count_wlan(void *arg, const char *link) 2056275970Scy{ 2057275970Scy wlan_count_attr_t *cp = arg; 2058275970Scy 2059275970Scy if (cp->wc_count == 0) 2060275970Scy cp->wc_link = strdup(link); 2061275970Scy cp->wc_count++; 2062275970Scy return (B_TRUE); 2063275970Scy} 2064275970Scy 2065275970Scystatic int 2066275970Scyparse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp) 2067275970Scy{ 2068275970Scy uint_t i; 2069275970Scy split_t *sp; 2070275970Scy wladm_wep_key_t *wk; 2071275970Scy 2072275970Scy sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN); 2073275970Scy if (sp == NULL) 2074275970Scy return (-1); 2075275970Scy 2076275970Scy wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t)); 2077275970Scy if (wk == NULL) 2078275970Scy goto fail; 2079275970Scy 2080275970Scy for (i = 0; i < sp->s_nfields; i++) { 2081275970Scy char *s; 2082275970Scy dladm_secobj_class_t class; 2083275970Scy dladm_status_t status; 2084275970Scy 2085275970Scy (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 2086275970Scy WLADM_MAX_WEPKEYNAME_LEN); 2087275970Scy 2088275970Scy wk[i].wk_idx = 1; 2089275970Scy if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 2090275970Scy if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 2091275970Scy goto fail; 2092275970Scy 2093275970Scy wk[i].wk_idx = (uint_t)(s[1] - '0'); 2094275970Scy *s = '\0'; 2095275970Scy } 2096275970Scy wk[i].wk_len = WLADM_MAX_WEPKEY_LEN; 2097275970Scy 2098275970Scy status = dladm_get_secobj(wk[i].wk_name, &class, 2099275970Scy wk[i].wk_val, &wk[i].wk_len, 0); 2100275970Scy if (status != DLADM_STATUS_OK) { 2101275970Scy if (status == DLADM_STATUS_NOTFOUND) { 2102275970Scy status = dladm_get_secobj(wk[i].wk_name, 2103275970Scy &class, wk[i].wk_val, &wk[i].wk_len, 2104275970Scy DLADM_OPT_PERSIST); 2105275970Scy } 2106275970Scy if (status != DLADM_STATUS_OK) 2107275970Scy goto fail; 2108275970Scy } 2109275970Scy } 2110275970Scy *keys = wk; 2111275970Scy *key_countp = i; 2112275970Scy splitfree(sp); 2113275970Scy return (0); 2114275970Scyfail: 2115275970Scy free(wk); 2116275970Scy splitfree(sp); 2117275970Scy return (-1); 2118275970Scy} 2119275970Scy 2120275970Scystatic void 2121275970Scydo_connect_wifi(int argc, char **argv) 2122275970Scy{ 2123275970Scy int option; 2124275970Scy wladm_wlan_attr_t attr, *attrp; 2125275970Scy wladm_status_t status = WLADM_STATUS_OK; 2126275970Scy int timeout = WLADM_CONNECT_TIMEOUT_DEFAULT; 2127275970Scy const char *link = NULL; 2128275970Scy wladm_wep_key_t *keys = NULL; 2129275970Scy uint_t key_count = 0; 2130275970Scy uint_t flags = 0; 2131275970Scy wladm_secmode_t keysecmode = WLADM_SECMODE_NONE; 2132275970Scy 2133275970Scy opterr = 0; 2134275970Scy (void) memset(&attr, 0, sizeof (attr)); 2135275970Scy while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 2136275970Scy wifi_longopts, NULL)) != -1) { 2137275970Scy switch (option) { 2138275970Scy case 'e': 2139275970Scy status = wladm_str2essid(optarg, &attr.wa_essid); 2140275970Scy if (status != WLADM_STATUS_OK) 2141275970Scy die("invalid ESSID '%s'", optarg); 2142275970Scy 2143275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_ESSID; 2144275970Scy /* 2145275970Scy * Try to connect without doing a scan. 2146275970Scy */ 2147275970Scy flags |= WLADM_OPT_NOSCAN; 2148275970Scy break; 2149275970Scy case 'i': 2150275970Scy status = wladm_str2bssid(optarg, &attr.wa_bssid); 2151275970Scy if (status != WLADM_STATUS_OK) 2152275970Scy die("invalid BSSID %s", optarg); 2153275970Scy 2154275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 2155275970Scy break; 2156275970Scy case 'a': 2157275970Scy status = wladm_str2auth(optarg, &attr.wa_auth); 2158275970Scy if (status != WLADM_STATUS_OK) 2159275970Scy die("invalid authentication mode '%s'", optarg); 2160275970Scy 2161275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 2162275970Scy break; 2163275970Scy case 'm': 2164275970Scy status = wladm_str2mode(optarg, &attr.wa_mode); 2165275970Scy if (status != WLADM_STATUS_OK) 2166275970Scy die("invalid mode '%s'", optarg); 2167275970Scy 2168275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 2169275970Scy break; 2170275970Scy case 'b': 2171275970Scy status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 2172275970Scy if (status != WLADM_STATUS_OK) 2173275970Scy die("invalid bsstype '%s'", optarg); 2174275970Scy 2175275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 2176275970Scy break; 2177275970Scy case 's': 2178275970Scy status = wladm_str2secmode(optarg, &attr.wa_secmode); 2179275970Scy if (status != WLADM_STATUS_OK) 2180275970Scy die("invalid security mode '%s'", optarg); 2181275970Scy 2182275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 2183275970Scy break; 2184275970Scy case 'k': 2185275970Scy if (parse_wep_keys(optarg, &keys, &key_count) < 0) 2186275970Scy die("invalid key(s) '%s'", optarg); 2187275970Scy 2188275970Scy keysecmode = WLADM_SECMODE_WEP; 2189275970Scy break; 2190275970Scy case 'T': 2191275970Scy if (strcasecmp(optarg, "forever") == 0) { 2192275970Scy timeout = -1; 2193275970Scy break; 2194275970Scy } 2195275970Scy if (!str2int(optarg, &timeout) || timeout < 0) 2196275970Scy die("invalid timeout value '%s'", optarg); 2197275970Scy break; 2198275970Scy case 'c': 2199275970Scy flags |= WLADM_OPT_CREATEIBSS; 2200275970Scy break; 2201275970Scy default: 2202275970Scy die_opterr(optopt, option); 2203275970Scy break; 2204275970Scy } 2205275970Scy } 2206275970Scy 2207275970Scy if (keysecmode == WLADM_SECMODE_NONE) { 2208275970Scy if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 2209275970Scy attr.wa_secmode == WLADM_SECMODE_WEP) 2210275970Scy die("key required for security mode 'wep'"); 2211275970Scy } else { 2212275970Scy if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 2213275970Scy attr.wa_secmode != keysecmode) 2214275970Scy die("incompatible -s and -k options"); 2215275970Scy } 2216275970Scy attr.wa_secmode = keysecmode; 2217275970Scy attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 2218275970Scy 2219275970Scy if (optind == (argc - 1)) 2220275970Scy link = argv[optind]; 2221275970Scy else if (optind != argc) 2222275970Scy usage(); 2223275970Scy 2224275970Scy if (link == NULL) { 2225275970Scy wlan_count_attr_t wcattr; 2226275970Scy 2227275970Scy wcattr.wc_link = NULL; 2228275970Scy wcattr.wc_count = 0; 2229275970Scy (void) wladm_walk(&wcattr, do_count_wlan); 2230275970Scy if (wcattr.wc_count == 0) { 2231275970Scy die("no wifi links are available"); 2232275970Scy } else if (wcattr.wc_count > 1) { 2233275970Scy die("link name is required when more than one wifi " 2234275970Scy "link is available"); 2235275970Scy } 2236275970Scy link = wcattr.wc_link; 2237275970Scy } 2238275970Scy attrp = (attr.wa_valid == 0) ? NULL : &attr; 2239275970Scyagain: 2240275970Scy status = wladm_connect(link, attrp, timeout, keys, key_count, flags); 2241275970Scy if (status != WLADM_STATUS_OK) { 2242275970Scy if ((flags & WLADM_OPT_NOSCAN) != 0) { 2243275970Scy /* 2244275970Scy * Try again with scanning and filtering. 2245275970Scy */ 2246275970Scy flags &= ~WLADM_OPT_NOSCAN; 2247275970Scy goto again; 2248275970Scy } 2249275970Scy 2250275970Scy if (status == WLADM_STATUS_NOTFOUND) { 2251275970Scy if (attr.wa_valid == 0) { 2252275970Scy die("no wifi networks are available"); 2253275970Scy } else { 2254275970Scy die("no wifi networks with the specified " 2255275970Scy "criteria are available"); 2256275970Scy } 2257275970Scy } 2258275970Scy die_wlerr(status, "cannot connect link '%s'", link); 2259275970Scy } 2260275970Scy free(keys); 2261275970Scy} 2262275970Scy 2263275970Scy/* ARGSUSED */ 2264275970Scystatic boolean_t 2265275970Scydo_all_disconnect_wifi(void *arg, const char *link) 2266275970Scy{ 2267275970Scy wladm_status_t status; 2268275970Scy 2269275970Scy status = wladm_disconnect(link); 2270275970Scy if (status != WLADM_STATUS_OK) 2271275970Scy warn_wlerr(status, "cannot disconnect link '%s'", link); 2272275970Scy 2273275970Scy return (B_TRUE); 2274275970Scy} 2275275970Scy 2276275970Scystatic void 2277275970Scydo_disconnect_wifi(int argc, char **argv) 2278275970Scy{ 2279275970Scy int option; 2280275970Scy const char *link = NULL; 2281275970Scy boolean_t all_links = B_FALSE; 2282275970Scy wladm_status_t status; 2283275970Scy wlan_count_attr_t wcattr; 2284275970Scy 2285275970Scy opterr = 0; 2286275970Scy while ((option = getopt_long(argc, argv, ":a", 2287275970Scy wifi_longopts, NULL)) != -1) { 2288275970Scy switch (option) { 2289275970Scy case 'a': 2290275970Scy all_links = B_TRUE; 2291275970Scy break; 2292275970Scy default: 2293275970Scy die_opterr(optopt, option); 2294275970Scy break; 2295275970Scy } 2296275970Scy } 2297275970Scy 2298275970Scy if (optind == (argc - 1)) 2299275970Scy link = argv[optind]; 2300275970Scy else if (optind != argc) 2301275970Scy usage(); 2302275970Scy 2303275970Scy if (link == NULL) { 2304275970Scy if (!all_links) { 2305275970Scy wcattr.wc_link = NULL; 2306275970Scy wcattr.wc_count = 0; 2307275970Scy (void) wladm_walk(&wcattr, do_count_wlan); 2308275970Scy if (wcattr.wc_count == 0) { 2309275970Scy die("no wifi links are available"); 2310275970Scy } else if (wcattr.wc_count > 1) { 2311275970Scy die("link name is required when more than " 2312275970Scy "one wifi link is available"); 2313275970Scy } 2314275970Scy link = wcattr.wc_link; 2315275970Scy } else { 2316275970Scy (void) wladm_walk(&all_links, do_all_disconnect_wifi); 2317275970Scy return; 2318275970Scy } 2319275970Scy } 2320275970Scy status = wladm_disconnect(link); 2321275970Scy if (status != WLADM_STATUS_OK) 2322275970Scy die_wlerr(status, "cannot disconnect link '%s'", link); 2323275970Scy} 2324275970Scy 2325275970Scy#define MAX_PROPS 32 2326275970Scy#define MAX_PROP_VALS 32 2327275970Scy#define MAX_PROP_LINE 512 2328275970Scy 2329275970Scytypedef struct prop_info { 2330275970Scy char *pi_name; 2331275970Scy char *pi_val[MAX_PROP_VALS]; 2332275970Scy uint_t pi_count; 2333275970Scy} prop_info_t; 2334275970Scy 2335275970Scytypedef struct prop_list { 2336275970Scy prop_info_t pl_info[MAX_PROPS]; 2337275970Scy uint_t pl_count; 2338275970Scy char *pl_buf; 2339275970Scy} prop_list_t; 2340275970Scy 2341275970Scytypedef struct show_linkprop_state { 2342275970Scy const char *ls_link; 2343275970Scy char *ls_line; 2344275970Scy char **ls_propvals; 2345275970Scy prop_list_t *ls_proplist; 2346275970Scy boolean_t ls_parseable; 2347275970Scy boolean_t ls_persist; 2348275970Scy boolean_t ls_header; 2349275970Scy} show_linkprop_state_t; 2350275970Scy 2351275970Scystatic void 2352275970Scyfree_props(prop_list_t *list) 2353275970Scy{ 2354275970Scy if (list != NULL) { 2355275970Scy free(list->pl_buf); 2356275970Scy free(list); 2357275970Scy } 2358275970Scy} 2359275970Scy 2360275970Scystatic int 2361275970Scyparse_props(char *str, prop_list_t **listp, boolean_t novalues) 2362275970Scy{ 2363275970Scy prop_list_t *list; 2364275970Scy prop_info_t *pip; 2365275970Scy char *buf, *curr; 2366275970Scy int len, i; 2367275970Scy 2368275970Scy list = malloc(sizeof (prop_list_t)); 2369275970Scy if (list == NULL) 2370275970Scy return (-1); 2371275970Scy 2372275970Scy list->pl_count = 0; 2373275970Scy list->pl_buf = buf = strdup(str); 2374275970Scy if (buf == NULL) 2375275970Scy goto fail; 2376275970Scy 2377275970Scy curr = buf; 2378275970Scy len = strlen(buf); 2379275970Scy pip = NULL; 2380275970Scy for (i = 0; i < len; i++) { 2381275970Scy char c = buf[i]; 2382275970Scy boolean_t match = (c == '=' || c == ','); 2383275970Scy 2384275970Scy if (!match && i != len - 1) 2385275970Scy continue; 2386275970Scy 2387275970Scy if (match) { 2388275970Scy buf[i] = '\0'; 2389275970Scy if (*curr == '\0') 2390275970Scy goto fail; 2391275970Scy } 2392275970Scy 2393275970Scy if (pip != NULL && c != '=') { 2394275970Scy if (pip->pi_count > MAX_PROP_VALS) 2395275970Scy goto fail; 2396275970Scy 2397275970Scy if (novalues) 2398275970Scy goto fail; 2399275970Scy 2400275970Scy pip->pi_val[pip->pi_count] = curr; 2401275970Scy pip->pi_count++; 2402275970Scy } else { 2403275970Scy if (list->pl_count > MAX_PROPS) 2404275970Scy goto fail; 2405275970Scy 2406275970Scy pip = &list->pl_info[list->pl_count]; 2407275970Scy pip->pi_name = curr; 2408275970Scy pip->pi_count = 0; 2409275970Scy list->pl_count++; 2410275970Scy if (c == ',') 2411275970Scy pip = NULL; 2412275970Scy } 2413275970Scy curr = buf + i + 1; 2414275970Scy } 2415275970Scy *listp = list; 2416275970Scy return (0); 2417275970Scy 2418275970Scyfail: 2419275970Scy free_props(list); 2420275970Scy return (-1); 2421275970Scy} 2422275970Scy 2423275970Scystatic void 2424275970Scyprint_linkprop_head(void) 2425275970Scy{ 2426275970Scy (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 2427275970Scy "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 2428275970Scy} 2429275970Scy 2430275970Scystatic void 2431275970Scyprint_linkprop(show_linkprop_state_t *statep, const char *propname, 2432275970Scy dladm_prop_type_t type, const char *typename, const char *format, 2433285612Sdelphij char **pptr) 2434285612Sdelphij{ 2435298770Sdelphij int i; 2436298770Sdelphij char *ptr, *lim; 2437275970Scy char buf[DLADM_STRSIZE]; 2438275970Scy char *unknown = "?", *notsup = ""; 2439275970Scy char **propvals = statep->ls_propvals; 2440275970Scy uint_t valcnt = MAX_PROP_VALS; 2441294569Sdelphij dladm_status_t status; 2442294569Sdelphij 2443294569Sdelphij status = dladm_get_prop(statep->ls_link, type, propname, 2444275970Scy propvals, &valcnt); 2445275970Scy if (status != DLADM_STATUS_OK) { 2446275970Scy if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) { 2447275970Scy valcnt = 1; 2448275970Scy if (type == DLADM_PROP_VAL_CURRENT) 2449275970Scy propvals = &unknown; 2450294569Sdelphij else 2451294569Sdelphij propvals = ¬sup; 2452294569Sdelphij } else { 2453275970Scy die_dlerr(status, "cannot get link property '%s'", 2454275970Scy propname); 2455275970Scy } 2456275970Scy } 2457275970Scy 2458275970Scy ptr = buf; 2459275970Scy lim = buf + DLADM_STRSIZE; 2460275970Scy for (i = 0; i < valcnt; i++) { 2461275970Scy if (propvals[i][0] == '\0' && !statep->ls_parseable) 2462275970Scy ptr += snprintf(ptr, lim - ptr, "--,"); 2463275970Scy else 2464275970Scy ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 2465275970Scy if (ptr >= lim) 2466275970Scy break; 2467275970Scy } 2468275970Scy if (valcnt > 0) 2469275970Scy buf[strlen(buf) - 1] = '\0'; 2470275970Scy 2471275970Scy lim = statep->ls_line + MAX_PROP_LINE; 2472275970Scy if (statep->ls_parseable) { 2473275970Scy *pptr += snprintf(*pptr, lim - *pptr, 2474275970Scy "%s=\"%s\" ", typename, buf); 2475275970Scy } else { 2476275970Scy *pptr += snprintf(*pptr, lim - *pptr, format, buf); 2477275970Scy } 2478275970Scy} 2479275970Scy 2480275970Scystatic boolean_t 2481275970Scyshow_linkprop(void *arg, const char *propname) 2482275970Scy{ 2483275970Scy show_linkprop_state_t *statep = arg; 2484275970Scy char *ptr = statep->ls_line; 2485275970Scy char *lim = ptr + MAX_PROP_LINE; 2486275970Scy 2487275970Scy if (statep->ls_persist && dladm_is_prop_temponly(propname, NULL)) 2488275970Scy return (B_TRUE); 2489275970Scy 2490275970Scy if (statep->ls_parseable) 2491275970Scy ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 2492275970Scy statep->ls_link); 2493275970Scy else 2494275970Scy ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 2495275970Scy 2496275970Scy if (statep->ls_parseable) 2497275970Scy ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 2498275970Scy else 2499275970Scy ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 2500275970Scy 2501275970Scy print_linkprop(statep, propname, 2502275970Scy statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 2503275970Scy DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 2504275970Scy print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 2505275970Scy "DEFAULT", "%-14s ", &ptr); 2506275970Scy print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2507275970Scy "POSSIBLE", "%-20s ", &ptr); 2508275970Scy 2509275970Scy if (statep->ls_header) { 2510275970Scy statep->ls_header = B_FALSE; 2511275970Scy if (!statep->ls_parseable) 2512275970Scy print_linkprop_head(); 2513275970Scy } 2514275970Scy (void) printf("%s\n", statep->ls_line); 2515275970Scy return (B_TRUE); 2516275970Scy} 2517275970Scy 2518275970Scystatic void 2519275970Scydo_show_linkprop(int argc, char **argv) 2520275970Scy{ 2521275970Scy int option; 2522275970Scy prop_list_t *proplist = NULL; 2523275970Scy show_linkprop_state_t state; 2524275970Scy 2525275970Scy opterr = 0; 2526294569Sdelphij state.ls_link = NULL; 2527294569Sdelphij state.ls_propvals = NULL; 2528294569Sdelphij state.ls_line = NULL; 2529294569Sdelphij state.ls_parseable = B_FALSE; 2530294569Sdelphij state.ls_persist = B_FALSE; 2531294569Sdelphij state.ls_header = B_TRUE; 2532294569Sdelphij while ((option = getopt_long(argc, argv, ":p:cP", 2533294569Sdelphij prop_longopts, NULL)) != -1) { 2534294569Sdelphij switch (option) { 2535294569Sdelphij case 'p': 2536294569Sdelphij if (parse_props(optarg, &proplist, B_TRUE) < 0) 2537294569Sdelphij die("invalid link properties specified"); 2538294569Sdelphij break; 2539294569Sdelphij case 'c': 2540294569Sdelphij state.ls_parseable = B_TRUE; 2541294569Sdelphij break; 2542294569Sdelphij case 'P': 2543294569Sdelphij state.ls_persist = B_TRUE; 2544294569Sdelphij break; 2545294569Sdelphij default: 2546294569Sdelphij die_opterr(optopt, option); 2547294569Sdelphij break; 2548294569Sdelphij } 2549294569Sdelphij } 2550294569Sdelphij 2551294569Sdelphij if (optind == (argc - 1)) 2552294569Sdelphij state.ls_link = argv[optind]; 2553294569Sdelphij else if (optind != argc) 2554294569Sdelphij usage(); 2555294569Sdelphij 2556294569Sdelphij state.ls_proplist = proplist; 2557294569Sdelphij 2558294569Sdelphij if (state.ls_link == NULL) { 2559294569Sdelphij (void) dladm_walk(show_linkprop_onelink, &state); 2560294569Sdelphij } else { 2561294569Sdelphij show_linkprop_onelink(&state, state.ls_link); 2562294569Sdelphij } 2563294569Sdelphij free_props(proplist); 2564294569Sdelphij} 2565294569Sdelphij 2566294569Sdelphijstatic void 2567294569Sdelphijshow_linkprop_onelink(void *arg, const char *link) 2568294569Sdelphij{ 2569294569Sdelphij int i, fd; 2570294569Sdelphij char linkname[MAXPATHLEN]; 2571294569Sdelphij char *buf; 2572294569Sdelphij dladm_status_t status; 2573294569Sdelphij prop_list_t *proplist = NULL; 2574294569Sdelphij show_linkprop_state_t *statep; 2575294569Sdelphij const char *savep; 2576294569Sdelphij 2577294569Sdelphij statep = (show_linkprop_state_t *)arg; 2578294569Sdelphij savep = statep->ls_link; 2579294569Sdelphij statep->ls_link = link; 2580294569Sdelphij proplist = statep->ls_proplist; 2581294569Sdelphij 2582294569Sdelphij /* 2583294569Sdelphij * When some WiFi links are opened for the first time, their hardware 2584294569Sdelphij * automatically scans for APs and does other slow operations. Thus, 2585294569Sdelphij * if there are no open links, the retrieval of link properties 2586294569Sdelphij * (below) will proceed slowly unless we hold the link open. 2587275970Scy */ 2588275970Scy (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 2589275970Scy if ((fd = open(linkname, O_RDWR)) < 0) 2590275970Scy die("cannot open %s: %s", link, strerror(errno)); 2591275970Scy 2592275970Scy buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 2593275970Scy MAX_PROP_LINE); 2594275970Scy if (buf == NULL) 2595275970Scy die("insufficient memory"); 2596275970Scy 2597275970Scy statep->ls_propvals = (char **)(void *)buf; 2598275970Scy for (i = 0; i < MAX_PROP_VALS; i++) { 2599285612Sdelphij statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 2600285612Sdelphij i * DLADM_PROP_VAL_MAX; 2601285612Sdelphij } 2602285612Sdelphij statep->ls_line = buf + 2603285612Sdelphij (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 2604285612Sdelphij 2605285612Sdelphij if (proplist != NULL) { 2606285612Sdelphij for (i = 0; i < proplist->pl_count; i++) { 2607285612Sdelphij if (!show_linkprop(statep, 2608285612Sdelphij proplist->pl_info[i].pi_name)) 2609285612Sdelphij break; 2610285612Sdelphij } 2611285612Sdelphij } else { 2612275970Scy status = dladm_walk_prop(link, statep, show_linkprop); 2613275970Scy if (status != DLADM_STATUS_OK) 2614275970Scy die_dlerr(status, "show-linkprop"); 2615275970Scy } 2616275970Scy (void) close(fd); 2617275970Scy free(buf); 2618275970Scy statep->ls_link = savep; 2619275970Scy} 2620275970Scy 2621275970Scystatic dladm_status_t 2622275970Scyset_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 2623275970Scy uint_t val_cnt, boolean_t reset) 2624275970Scy{ 2625275970Scy dladm_status_t status; 2626275970Scy char *errprop; 2627275970Scy 2628275970Scy status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 2629275970Scy DLADM_OPT_PERSIST, &errprop); 2630275970Scy 2631275970Scy if (status != DLADM_STATUS_OK) { 2632275970Scy if (reset) { 2633275970Scy warn_dlerr(status, "cannot persistently reset link " 2634275970Scy "property '%s' on '%s'", errprop, link); 2635275970Scy } else { 2636275970Scy warn_dlerr(status, "cannot persistently set link " 2637275970Scy "property '%s' on '%s'", errprop, link); 2638275970Scy } 2639275970Scy } 2640275970Scy return (status); 2641275970Scy} 2642275970Scy 2643275970Scystatic void 2644275970Scyset_linkprop(int argc, char **argv, boolean_t reset) 2645275970Scy{ 2646275970Scy int i, option; 2647275970Scy char errmsg[DLADM_STRSIZE]; 2648275970Scy const char *link = NULL; 2649275970Scy prop_list_t *proplist = NULL; 2650275970Scy boolean_t temp = B_FALSE; 2651275970Scy dladm_status_t status = DLADM_STATUS_OK; 2652275970Scy 2653275970Scy opterr = 0; 2654275970Scy while ((option = getopt_long(argc, argv, ":p:R:t", 2655275970Scy prop_longopts, NULL)) != -1) { 2656275970Scy switch (option) { 2657275970Scy case 'p': 2658275970Scy if (parse_props(optarg, &proplist, reset) < 0) 2659275970Scy die("invalid link properties specified"); 2660275970Scy break; 2661275970Scy case 't': 2662275970Scy temp = B_TRUE; 2663275970Scy break; 2664275970Scy case 'R': 2665275970Scy status = dladm_set_rootdir(optarg); 2666275970Scy if (status != DLADM_STATUS_OK) { 2667275970Scy die_dlerr(status, "invalid directory " 2668275970Scy "specified"); 2669275970Scy } 2670275970Scy break; 2671275970Scy default: 2672275970Scy die_opterr(optopt, option); 2673275970Scy break; 2674275970Scy } 2675298770Sdelphij } 2676298770Sdelphij 2677275970Scy if (optind == (argc - 1)) 2678275970Scy link = argv[optind]; 2679275970Scy else if (optind != argc) 2680275970Scy usage(); 2681275970Scy 2682275970Scy if (link == NULL) 2683275970Scy die("link name must be specified"); 2684275970Scy 2685275970Scy if (proplist == NULL) { 2686275970Scy char *errprop; 2687275970Scy 2688275970Scy if (!reset) 2689275970Scy die("link property must be specified"); 2690275970Scy 2691275970Scy status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP, 2692275970Scy &errprop); 2693275970Scy if (status != DLADM_STATUS_OK) { 2694275970Scy warn_dlerr(status, "cannot reset link property '%s' " 2695275970Scy "on '%s'", errprop, link); 2696275970Scy } 2697275970Scy if (!temp) { 2698275970Scy dladm_status_t s; 2699275970Scy 2700298770Sdelphij s = set_linkprop_persist(link, NULL, NULL, 0, reset); 2701298770Sdelphij if (s != DLADM_STATUS_OK) 2702298770Sdelphij status = s; 2703275970Scy } 2704275970Scy goto done; 2705275970Scy } 2706275970Scy 2707275970Scy for (i = 0; i < proplist->pl_count; i++) { 2708275970Scy prop_info_t *pip = &proplist->pl_info[i]; 2709275970Scy char **val; 2710275970Scy uint_t count; 2711275970Scy dladm_status_t s; 2712275970Scy 2713275970Scy if (reset) { 2714275970Scy val = NULL; 2715275970Scy count = 0; 2716275970Scy } else { 2717275970Scy val = pip->pi_val; 2718275970Scy count = pip->pi_count; 2719275970Scy if (count == 0) { 2720275970Scy warn("no value specified for '%s'", 2721275970Scy pip->pi_name); 2722275970Scy status = DLADM_STATUS_BADARG; 2723275970Scy continue; 2724275970Scy } 2725275970Scy } 2726275970Scy s = dladm_set_prop(link, pip->pi_name, val, count, 2727275970Scy DLADM_OPT_TEMP, NULL); 2728275970Scy if (s == DLADM_STATUS_OK) { 2729275970Scy if (!temp) { 2730275970Scy s = set_linkprop_persist(link, 2731275970Scy pip->pi_name, val, count, reset); 2732275970Scy if (s != DLADM_STATUS_OK) 2733275970Scy status = s; 2734275970Scy } 2735275970Scy continue; 2736275970Scy } 2737275970Scy status = s; 2738275970Scy switch (s) { 2739275970Scy case DLADM_STATUS_NOTFOUND: 2740275970Scy warn("invalid link property '%s'", pip->pi_name); 2741275970Scy break; 2742275970Scy case DLADM_STATUS_BADVAL: { 2743275970Scy int j; 2744275970Scy char *ptr, *lim; 2745275970Scy char **propvals = NULL; 2746275970Scy uint_t valcnt = MAX_PROP_VALS; 2747275970Scy 2748285612Sdelphij ptr = malloc((sizeof (char *) + 2749285612Sdelphij DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 2750285612Sdelphij MAX_PROP_LINE); 2751275970Scy 2752275970Scy propvals = (char **)(void *)ptr; 2753275970Scy if (propvals == NULL) 2754275970Scy die("insufficient memory"); 2755275970Scy 2756275970Scy for (j = 0; j < MAX_PROP_VALS; j++) { 2757275970Scy propvals[j] = ptr + sizeof (char *) * 2758275970Scy MAX_PROP_VALS + 2759275970Scy j * DLADM_PROP_VAL_MAX; 2760275970Scy } 2761275970Scy s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 2762275970Scy pip->pi_name, propvals, &valcnt); 2763275970Scy 2764275970Scy ptr = errmsg; 2765275970Scy lim = ptr + DLADM_STRSIZE; 2766275970Scy *ptr = '\0'; 2767275970Scy for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 2768275970Scy ptr += snprintf(ptr, lim - ptr, "%s,", 2769275970Scy propvals[j]); 2770275970Scy if (ptr >= lim) 2771275970Scy break; 2772275970Scy } 2773275970Scy if (ptr > errmsg) { 2774275970Scy *(ptr - 1) = '\0'; 2775275970Scy warn("link property '%s' must be one of: %s", 2776275970Scy pip->pi_name, errmsg); 2777275970Scy } else 2778275970Scy warn("invalid link property '%s'", *val); 2779275970Scy free(propvals); 2780275970Scy break; 2781275970Scy } 2782275970Scy default: 2783275970Scy if (reset) { 2784275970Scy warn_dlerr(status, "cannot reset link property " 2785275970Scy "'%s' on '%s'", pip->pi_name, link); 2786275970Scy } else { 2787275970Scy warn_dlerr(status, "cannot set link property " 2788275970Scy "'%s' on '%s'", pip->pi_name, link); 2789275970Scy } 2790275970Scy break; 2791275970Scy } 2792275970Scy } 2793275970Scydone: 2794275970Scy free_props(proplist); 2795275970Scy if (status != DLADM_STATUS_OK) 2796275970Scy exit(1); 2797275970Scy} 2798275970Scy 2799275970Scystatic void 2800275970Scydo_set_linkprop(int argc, char **argv) 2801275970Scy{ 2802275970Scy set_linkprop(argc, argv, B_FALSE); 2803275970Scy} 2804275970Scy 2805275970Scystatic void 2806275970Scydo_reset_linkprop(int argc, char **argv) 2807275970Scy{ 2808275970Scy set_linkprop(argc, argv, B_TRUE); 2809275970Scy} 2810285612Sdelphij 2811285612Sdelphijstatic int 2812285612Sdelphijconvert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 2813285612Sdelphij dladm_secobj_class_t class) 2814285612Sdelphij{ 2815285612Sdelphij int error = 0; 2816285612Sdelphij 2817285612Sdelphij if (class != DLADM_SECOBJ_CLASS_WEP) 2818285612Sdelphij return (ENOENT); 2819285612Sdelphij 2820285612Sdelphij switch (len) { 2821285612Sdelphij case 5: /* ASCII key sizes */ 2822285612Sdelphij case 13: 2823275970Scy (void) memcpy(obj_val, buf, len); 2824275970Scy *obj_lenp = len; 2825275970Scy break; 2826275970Scy case 10: /* Hex key sizes, not preceded by 0x */ 2827275970Scy case 26: 2828275970Scy error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 2829275970Scy break; 2830275970Scy case 12: /* Hex key sizes, preceded by 0x */ 2831275970Scy case 28: 2832275970Scy if (strncmp(buf, "0x", 2) != 0) 2833275970Scy return (EINVAL); 2834275970Scy error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 2835275970Scy break; 2836275970Scy default: 2837275970Scy return (EINVAL); 2838275970Scy } 2839289997Sglebius return (error); 2840289997Sglebius} 2841289997Sglebius 2842275970Scy/* ARGSUSED */ 2843275970Scystatic void 2844275970Scydefersig(int sig) 2845289997Sglebius{ 2846289997Sglebius signalled = sig; 2847289997Sglebius} 2848275970Scy 2849275970Scystatic int 2850275970Scyget_secobj_from_tty(uint_t try, const char *objname, char *buf) 2851275970Scy{ 2852275970Scy uint_t len = 0; 2853285612Sdelphij int c; 2854298770Sdelphij struct termios stored, current; 2855298770Sdelphij void (*sigfunc)(int); 2856275970Scy 2857275970Scy /* 2858275970Scy * Turn off echo -- but before we do so, defer SIGINT handling 2859275970Scy * so that a ^C doesn't leave the terminal corrupted. 2860275970Scy */ 2861275970Scy sigfunc = signal(SIGINT, defersig); 2862275970Scy (void) fflush(stdin); 2863275970Scy (void) tcgetattr(0, &stored); 2864275970Scy current = stored; 2865275970Scy current.c_lflag &= ~(ICANON|ECHO); 2866275970Scy current.c_cc[VTIME] = 0; 2867275970Scy current.c_cc[VMIN] = 1; 2868275970Scy (void) tcsetattr(0, TCSANOW, ¤t); 2869275970Scyagain: 2870275970Scy if (try == 1) 2871275970Scy (void) printf(gettext("provide value for '%s': "), objname); 2872275970Scy else 2873275970Scy (void) printf(gettext("confirm value for '%s': "), objname); 2874275970Scy 2875275970Scy (void) fflush(stdout); 2876275970Scy while (signalled == 0) { 2877275970Scy c = getchar(); 2878275970Scy if (c == '\n' || c == '\r') { 2879275970Scy if (len != 0) 2880275970Scy break; 2881275970Scy (void) putchar('\n'); 2882275970Scy goto again; 2883275970Scy } 2884275970Scy 2885275970Scy buf[len++] = c; 2886275970Scy if (len >= DLADM_SECOBJ_VAL_MAX - 1) 2887275970Scy break; 2888275970Scy (void) putchar('*'); 2889275970Scy } 2890275970Scy 2891275970Scy (void) putchar('\n'); 2892275970Scy (void) fflush(stdin); 2893275970Scy 2894275970Scy /* 2895275970Scy * Restore terminal setting and handle deferred signals. 2896275970Scy */ 2897275970Scy (void) tcsetattr(0, TCSANOW, &stored); 2898275970Scy 2899275970Scy (void) signal(SIGINT, sigfunc); 2900275970Scy if (signalled != 0) 2901275970Scy (void) kill(getpid(), signalled); 2902275970Scy 2903275970Scy return (len); 2904275970Scy} 2905275970Scy 2906275970Scystatic int 2907275970Scyget_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 2908275970Scy dladm_secobj_class_t class, FILE *filep) 2909275970Scy{ 2910275970Scy int rval; 2911275970Scy uint_t len, len2; 2912275970Scy char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 2913275970Scy 2914275970Scy if (filep == NULL) { 2915275970Scy len = get_secobj_from_tty(1, obj_name, buf); 2916275970Scy rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 2917275970Scy if (rval == 0) { 2918275970Scy len2 = get_secobj_from_tty(2, obj_name, buf2); 2919275970Scy if (len != len2 || memcmp(buf, buf2, len) != 0) 2920275970Scy rval = ENOTSUP; 2921275970Scy } 2922275970Scy return (rval); 2923275970Scy } else { 2924275970Scy for (;;) { 2925275970Scy if (fgets(buf, sizeof (buf), filep) == NULL) 2926275970Scy break; 2927275970Scy if (isspace(buf[0])) 2928275970Scy continue; 2929275970Scy 2930275970Scy len = strlen(buf); 2931275970Scy if (buf[len - 1] == '\n') { 2932275970Scy buf[len - 1] = '\0'; 2933275970Scy len--; 2934275970Scy } 2935275970Scy break; 2936275970Scy } 2937275970Scy (void) fclose(filep); 2938275970Scy } 2939275970Scy return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 2940275970Scy} 2941275970Scy 2942275970Scystatic boolean_t 2943275970Scycheck_auth(const char *auth) 2944275970Scy{ 2945275970Scy struct passwd *pw; 2946275970Scy 2947280849Scy if ((pw = getpwuid(getuid())) == NULL) 2948275970Scy return (B_FALSE); 2949294569Sdelphij 2950275970Scy return (chkauthattr(auth, pw->pw_name) != 0); 2951275970Scy} 2952275970Scy 2953275970Scystatic void 2954275970Scyaudit_secobj(char *auth, char *class, char *obj, 2955275970Scy boolean_t success, boolean_t create) 2956275970Scy{ 2957275970Scy adt_session_data_t *ah; 2958275970Scy adt_event_data_t *event; 2959275970Scy au_event_t flag; 2960275970Scy char *errstr; 2961275970Scy 2962275970Scy if (create) { 2963275970Scy flag = ADT_dladm_create_secobj; 2964275970Scy errstr = "ADT_dladm_create_secobj"; 2965275970Scy } else { 2966275970Scy flag = ADT_dladm_delete_secobj; 2967275970Scy errstr = "ADT_dladm_delete_secobj"; 2968275970Scy } 2969 2970 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 2971 die("adt_start_session: %s", strerror(errno)); 2972 2973 if ((event = adt_alloc_event(ah, flag)) == NULL) 2974 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 2975 2976 /* fill in audit info */ 2977 if (create) { 2978 event->adt_dladm_create_secobj.auth_used = auth; 2979 event->adt_dladm_create_secobj.obj_class = class; 2980 event->adt_dladm_create_secobj.obj_name = obj; 2981 } else { 2982 event->adt_dladm_delete_secobj.auth_used = auth; 2983 event->adt_dladm_delete_secobj.obj_class = class; 2984 event->adt_dladm_delete_secobj.obj_name = obj; 2985 } 2986 2987 if (success) { 2988 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 2989 die("adt_put_event (%s, success): %s", errstr, 2990 strerror(errno)); 2991 } 2992 } else { 2993 if (adt_put_event(event, ADT_FAILURE, 2994 ADT_FAIL_VALUE_AUTH) != 0) { 2995 die("adt_put_event: (%s, failure): %s", errstr, 2996 strerror(errno)); 2997 } 2998 } 2999 3000 adt_free_event(event); 3001 (void) adt_end_session(ah); 3002} 3003 3004#define MAX_SECOBJS 32 3005#define MAX_SECOBJ_NAMELEN 32 3006static void 3007do_create_secobj(int argc, char **argv) 3008{ 3009 int option, rval; 3010 FILE *filep = NULL; 3011 char *obj_name = NULL; 3012 char *class_name = NULL; 3013 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3014 uint_t obj_len; 3015 boolean_t success, temp = B_FALSE; 3016 dladm_status_t status; 3017 dladm_secobj_class_t class = -1; 3018 uid_t euid; 3019 3020 opterr = 0; 3021 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 3022 while ((option = getopt_long(argc, argv, ":f:c:R:t", 3023 wifi_longopts, NULL)) != -1) { 3024 switch (option) { 3025 case 'f': 3026 euid = geteuid(); 3027 (void) seteuid(getuid()); 3028 filep = fopen(optarg, "r"); 3029 if (filep == NULL) { 3030 die("cannot open %s: %s", optarg, 3031 strerror(errno)); 3032 } 3033 (void) seteuid(euid); 3034 break; 3035 case 'c': 3036 class_name = optarg; 3037 status = dladm_str2secobjclass(optarg, &class); 3038 if (status != DLADM_STATUS_OK) { 3039 die("invalid secure object class '%s', " 3040 "valid values are: wep", optarg); 3041 } 3042 break; 3043 case 't': 3044 temp = B_TRUE; 3045 break; 3046 case 'R': 3047 status = dladm_set_rootdir(optarg); 3048 if (status != DLADM_STATUS_OK) { 3049 die_dlerr(status, "invalid directory " 3050 "specified"); 3051 } 3052 break; 3053 default: 3054 die_opterr(optopt, option); 3055 break; 3056 } 3057 } 3058 3059 if (optind == (argc - 1)) 3060 obj_name = argv[optind]; 3061 else if (optind != argc) 3062 usage(); 3063 3064 if (class == -1) 3065 die("secure object class required"); 3066 3067 if (obj_name == NULL) 3068 die("secure object name required"); 3069 3070 success = check_auth(LINK_SEC_AUTH); 3071 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 3072 if (!success) 3073 die("authorization '%s' is required", LINK_SEC_AUTH); 3074 3075 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 3076 if (rval != 0) { 3077 switch (rval) { 3078 case ENOENT: 3079 die("invalid secure object class"); 3080 break; 3081 case EINVAL: 3082 die("invalid secure object value"); 3083 break; 3084 case ENOTSUP: 3085 die("verification failed"); 3086 break; 3087 default: 3088 die("invalid secure object: %s", strerror(rval)); 3089 break; 3090 } 3091 } 3092 3093 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3094 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 3095 if (status != DLADM_STATUS_OK) { 3096 die_dlerr(status, "could not create secure object '%s'", 3097 obj_name); 3098 } 3099 if (temp) 3100 return; 3101 3102 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 3103 DLADM_OPT_PERSIST); 3104 if (status != DLADM_STATUS_OK) { 3105 warn_dlerr(status, "could not persistently create secure " 3106 "object '%s'", obj_name); 3107 } 3108} 3109 3110static void 3111do_delete_secobj(int argc, char **argv) 3112{ 3113 int i, option; 3114 boolean_t temp = B_FALSE; 3115 split_t *sp = NULL; 3116 boolean_t success; 3117 dladm_status_t status, pstatus; 3118 3119 opterr = 0; 3120 status = pstatus = DLADM_STATUS_OK; 3121 while ((option = getopt_long(argc, argv, ":R:t", 3122 wifi_longopts, NULL)) != -1) { 3123 switch (option) { 3124 case 't': 3125 temp = B_TRUE; 3126 break; 3127 case 'R': 3128 status = dladm_set_rootdir(optarg); 3129 if (status != DLADM_STATUS_OK) { 3130 die_dlerr(status, "invalid directory " 3131 "specified"); 3132 } 3133 break; 3134 default: 3135 die_opterr(optopt, option); 3136 break; 3137 } 3138 } 3139 3140 if (optind == (argc - 1)) { 3141 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3142 if (sp == NULL) { 3143 die("invalid secure object name(s): '%s'", 3144 argv[optind]); 3145 } 3146 } else if (optind != argc) 3147 usage(); 3148 3149 if (sp == NULL || sp->s_nfields < 1) 3150 die("secure object name required"); 3151 3152 success = check_auth(LINK_SEC_AUTH); 3153 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 3154 if (!success) 3155 die("authorization '%s' is required", LINK_SEC_AUTH); 3156 3157 for (i = 0; i < sp->s_nfields; i++) { 3158 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 3159 if (!temp) { 3160 pstatus = dladm_unset_secobj(sp->s_fields[i], 3161 DLADM_OPT_PERSIST); 3162 } else { 3163 pstatus = DLADM_STATUS_OK; 3164 } 3165 3166 if (status != DLADM_STATUS_OK) { 3167 warn_dlerr(status, "could not delete secure object " 3168 "'%s'", sp->s_fields[i]); 3169 } 3170 if (pstatus != DLADM_STATUS_OK) { 3171 warn_dlerr(pstatus, "could not persistently delete " 3172 "secure object '%s'", sp->s_fields[i]); 3173 } 3174 } 3175 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 3176 exit(1); 3177} 3178 3179typedef struct show_secobj_state { 3180 boolean_t ss_persist; 3181 boolean_t ss_parseable; 3182 boolean_t ss_debug; 3183 boolean_t ss_header; 3184} show_secobj_state_t; 3185 3186static void 3187print_secobj_head(show_secobj_state_t *statep) 3188{ 3189 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 3190 if (statep->ss_debug) 3191 (void) printf("%-30s", "VALUE"); 3192 (void) putchar('\n'); 3193} 3194 3195static boolean_t 3196show_secobj(void *arg, const char *obj_name) 3197{ 3198 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 3199 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 3200 char buf[DLADM_STRSIZE]; 3201 uint_t flags = 0; 3202 dladm_secobj_class_t class; 3203 show_secobj_state_t *statep = arg; 3204 dladm_status_t status; 3205 3206 if (statep->ss_persist) 3207 flags |= DLADM_OPT_PERSIST; 3208 3209 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 3210 if (status != DLADM_STATUS_OK) 3211 die_dlerr(status, "cannot get secure object '%s'", obj_name); 3212 3213 if (statep->ss_header) { 3214 statep->ss_header = B_FALSE; 3215 if (!statep->ss_parseable) 3216 print_secobj_head(statep); 3217 } 3218 3219 if (statep->ss_parseable) { 3220 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 3221 dladm_secobjclass2str(class, buf)); 3222 } else { 3223 (void) printf("%-20s %-20s ", obj_name, 3224 dladm_secobjclass2str(class, buf)); 3225 } 3226 3227 if (statep->ss_debug) { 3228 char val[DLADM_SECOBJ_VAL_MAX * 2]; 3229 uint_t len = sizeof (val); 3230 3231 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 3232 if (statep->ss_parseable) 3233 (void) printf("VALUE=\"0x%s\"", val); 3234 else 3235 (void) printf("0x%-30s", val); 3236 } 3237 } 3238 (void) putchar('\n'); 3239 return (B_TRUE); 3240} 3241 3242static void 3243do_show_secobj(int argc, char **argv) 3244{ 3245 int option; 3246 show_secobj_state_t state; 3247 dladm_status_t status; 3248 uint_t i; 3249 split_t *sp; 3250 uint_t flags; 3251 3252 opterr = 0; 3253 state.ss_persist = B_FALSE; 3254 state.ss_parseable = B_FALSE; 3255 state.ss_debug = B_FALSE; 3256 state.ss_header = B_TRUE; 3257 while ((option = getopt_long(argc, argv, ":pPd", 3258 wifi_longopts, NULL)) != -1) { 3259 switch (option) { 3260 case 'p': 3261 state.ss_parseable = B_TRUE; 3262 break; 3263 case 'P': 3264 state.ss_persist = B_TRUE; 3265 break; 3266 case 'd': 3267 if (getuid() != 0) 3268 die("insufficient privileges"); 3269 state.ss_debug = B_TRUE; 3270 break; 3271 default: 3272 die_opterr(optopt, option); 3273 break; 3274 } 3275 } 3276 3277 if (optind == (argc - 1)) { 3278 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 3279 if (sp == NULL) { 3280 die("invalid secure object name(s): '%s'", 3281 argv[optind]); 3282 } 3283 for (i = 0; i < sp->s_nfields; i++) { 3284 if (!show_secobj(&state, sp->s_fields[i])) 3285 break; 3286 } 3287 splitfree(sp); 3288 return; 3289 } else if (optind != argc) 3290 usage(); 3291 3292 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 3293 status = dladm_walk_secobj(&state, show_secobj, flags); 3294 if (status != DLADM_STATUS_OK) 3295 die_dlerr(status, "show-secobj"); 3296} 3297 3298/* ARGSUSED */ 3299static void 3300do_init_linkprop(int argc, char **argv) 3301{ 3302 dladm_status_t status; 3303 3304 status = dladm_init_linkprop(); 3305 if (status != DLADM_STATUS_OK) 3306 die_dlerr(status, "link property initialization failed"); 3307} 3308 3309/* ARGSUSED */ 3310static void 3311do_init_secobj(int argc, char **argv) 3312{ 3313 dladm_status_t status; 3314 3315 status = dladm_init_secobj(); 3316 if (status != DLADM_STATUS_OK) 3317 die_dlerr(status, "secure object initialization failed"); 3318} 3319 3320static boolean_t 3321str2int(const char *str, int *valp) 3322{ 3323 int val; 3324 char *endp = NULL; 3325 3326 errno = 0; 3327 val = strtol(str, &endp, 10); 3328 if (errno != 0 || *endp != '\0') 3329 return (B_FALSE); 3330 3331 *valp = val; 3332 return (B_TRUE); 3333} 3334 3335/* PRINTFLIKE1 */ 3336static void 3337warn(const char *format, ...) 3338{ 3339 va_list alist; 3340 3341 format = gettext(format); 3342 (void) fprintf(stderr, "%s: warning: ", progname); 3343 3344 va_start(alist, format); 3345 (void) vfprintf(stderr, format, alist); 3346 va_end(alist); 3347 3348 (void) putchar('\n'); 3349} 3350 3351/* PRINTFLIKE2 */ 3352static void 3353warn_wlerr(wladm_status_t err, const char *format, ...) 3354{ 3355 va_list alist; 3356 char errmsg[WLADM_STRSIZE]; 3357 3358 format = gettext(format); 3359 (void) fprintf(stderr, gettext("%s: warning: "), progname); 3360 3361 va_start(alist, format); 3362 (void) vfprintf(stderr, format, alist); 3363 va_end(alist); 3364 (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 3365} 3366 3367/* PRINTFLIKE2 */ 3368static void 3369warn_dlerr(dladm_status_t err, const char *format, ...) 3370{ 3371 va_list alist; 3372 char errmsg[DLADM_STRSIZE]; 3373 3374 format = gettext(format); 3375 (void) fprintf(stderr, gettext("%s: warning: "), progname); 3376 3377 va_start(alist, format); 3378 (void) vfprintf(stderr, format, alist); 3379 va_end(alist); 3380 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3381} 3382 3383/* PRINTFLIKE2 */ 3384static void 3385die_laerr(laadm_diag_t diag, const char *format, ...) 3386{ 3387 va_list alist; 3388 char *errstr = strerror(errno); 3389 3390 format = gettext(format); 3391 (void) fprintf(stderr, "%s: ", progname); 3392 3393 va_start(alist, format); 3394 (void) vfprintf(stderr, format, alist); 3395 va_end(alist); 3396 3397 if (diag == 0) 3398 (void) fprintf(stderr, ": %s\n", errstr); 3399 else 3400 (void) fprintf(stderr, ": %s (%s)\n", errstr, laadm_diag(diag)); 3401 3402 exit(EXIT_FAILURE); 3403} 3404 3405/* PRINTFLIKE2 */ 3406static void 3407die_wlerr(wladm_status_t err, const char *format, ...) 3408{ 3409 va_list alist; 3410 char errmsg[WLADM_STRSIZE]; 3411 3412 format = gettext(format); 3413 (void) fprintf(stderr, "%s: ", progname); 3414 3415 va_start(alist, format); 3416 (void) vfprintf(stderr, format, alist); 3417 va_end(alist); 3418 (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 3419 3420 exit(EXIT_FAILURE); 3421} 3422 3423/* PRINTFLIKE2 */ 3424static void 3425die_dlerr(dladm_status_t err, const char *format, ...) 3426{ 3427 va_list alist; 3428 char errmsg[DLADM_STRSIZE]; 3429 3430 format = gettext(format); 3431 (void) fprintf(stderr, "%s: ", progname); 3432 3433 va_start(alist, format); 3434 (void) vfprintf(stderr, format, alist); 3435 va_end(alist); 3436 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3437 3438 exit(EXIT_FAILURE); 3439} 3440 3441/* PRINTFLIKE1 */ 3442static void 3443die(const char *format, ...) 3444{ 3445 va_list alist; 3446 3447 format = gettext(format); 3448 (void) fprintf(stderr, "%s: ", progname); 3449 3450 va_start(alist, format); 3451 (void) vfprintf(stderr, format, alist); 3452 va_end(alist); 3453 3454 (void) putchar('\n'); 3455 exit(EXIT_FAILURE); 3456} 3457 3458static void 3459die_optdup(int opt) 3460{ 3461 die("the option -%c cannot be specified more than once", opt); 3462} 3463 3464static void 3465die_opterr(int opt, int opterr) 3466{ 3467 switch (opterr) { 3468 case ':': 3469 die("option '-%c' requires a value", opt); 3470 break; 3471 case '?': 3472 default: 3473 die("unrecognized option '-%c'", opt); 3474 break; 3475 } 3476} 3477