17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5219a2a31Shl157128 * Common Development and Distribution License (the "License"). 6219a2a31Shl157128 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22f4b3ec61Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 290ba2cbe9Sxc151355 #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <locale.h> 310ba2cbe9Sxc151355 #include <signal.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <stropts.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <kstat.h> 397c478bd9Sstevel@tonic-gate #include <strings.h> 407c478bd9Sstevel@tonic-gate #include <getopt.h> 417c478bd9Sstevel@tonic-gate #include <unistd.h> 42cd93090eSericheng #include <priv.h> 430ba2cbe9Sxc151355 #include <termios.h> 440ba2cbe9Sxc151355 #include <pwd.h> 450ba2cbe9Sxc151355 #include <auth_attr.h> 460ba2cbe9Sxc151355 #include <auth_list.h> 477c478bd9Sstevel@tonic-gate #include <libintl.h> 487c478bd9Sstevel@tonic-gate #include <libdlpi.h> 49f595a68aSyz147064 #include <libdllink.h> 50f595a68aSyz147064 #include <libdlaggr.h> 51f595a68aSyz147064 #include <libdlwlan.h> 520ba2cbe9Sxc151355 #include <libinetutil.h> 530ba2cbe9Sxc151355 #include <bsm/adt.h> 540ba2cbe9Sxc151355 #include <bsm/adt_event.h> 557c478bd9Sstevel@tonic-gate 56ba2e4443Sseb #define AGGR_DRV "aggr" 577c478bd9Sstevel@tonic-gate #define MAXPORT 256 587c478bd9Sstevel@tonic-gate #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 597c478bd9Sstevel@tonic-gate "%-5s %-4s %-4s %-9s %-7s\n" 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate typedef struct pktsum_s { 627c478bd9Sstevel@tonic-gate uint64_t ipackets; 637c478bd9Sstevel@tonic-gate uint64_t opackets; 647c478bd9Sstevel@tonic-gate uint64_t rbytes; 657c478bd9Sstevel@tonic-gate uint64_t obytes; 667c478bd9Sstevel@tonic-gate uint32_t ierrors; 677c478bd9Sstevel@tonic-gate uint32_t oerrors; 687c478bd9Sstevel@tonic-gate } pktsum_t; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate typedef struct show_link_state { 717c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 727c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 737c478bd9Sstevel@tonic-gate boolean_t ls_stats; 747c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 757c478bd9Sstevel@tonic-gate boolean_t ls_parseable; 767c478bd9Sstevel@tonic-gate } show_link_state_t; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 797c478bd9Sstevel@tonic-gate uint32_t gs_key; 807c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 817c478bd9Sstevel@tonic-gate boolean_t gs_found; 827c478bd9Sstevel@tonic-gate boolean_t gs_stats; 837c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 847c478bd9Sstevel@tonic-gate pktsum_t gs_prevstats[MAXPORT]; 857c478bd9Sstevel@tonic-gate boolean_t gs_parseable; 867c478bd9Sstevel@tonic-gate } show_grp_state_t; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate typedef struct show_mac_state { 897c478bd9Sstevel@tonic-gate boolean_t ms_firstonly; 907c478bd9Sstevel@tonic-gate boolean_t ms_donefirst; 917c478bd9Sstevel@tonic-gate pktsum_t ms_prevstats; 927c478bd9Sstevel@tonic-gate boolean_t ms_parseable; 937c478bd9Sstevel@tonic-gate } show_mac_state_t; 947c478bd9Sstevel@tonic-gate 950ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **); 960ba2cbe9Sxc151355 970ba2cbe9Sxc151355 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 980ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 990ba2cbe9Sxc151355 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 1000ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 1010ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 1020ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 1030ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 1047c478bd9Sstevel@tonic-gate 105f4b3ec61Sdh155122 static void show_linkprop_onelink(void *, const char *); 106f4b3ec61Sdh155122 10733343a97Smeem static void link_stats(const char *, uint_t); 10833343a97Smeem static void aggr_stats(uint32_t, uint_t); 1097c478bd9Sstevel@tonic-gate static void dev_stats(const char *dev, uint32_t); 1107c478bd9Sstevel@tonic-gate 111ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 1127c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 113ba2e4443Sseb static uint64_t mac_ifspeed(const char *); 1147c478bd9Sstevel@tonic-gate static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 1157c478bd9Sstevel@tonic-gate static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 116*3a62633bSyz147064 static const char *mac_link_state(const char *, char *); 117*3a62633bSyz147064 static const char *mac_link_duplex(const char *, char *); 1187c478bd9Sstevel@tonic-gate 11933343a97Smeem static boolean_t str2int(const char *, int *); 12033343a97Smeem static void die(const char *, ...); 12133343a97Smeem static void die_optdup(int); 12233343a97Smeem static void die_opterr(int, int); 12333343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 12433343a97Smeem static void warn(const char *, ...); 12533343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 12633343a97Smeem 1277c478bd9Sstevel@tonic-gate typedef struct cmd { 1287c478bd9Sstevel@tonic-gate char *c_name; 1290ba2cbe9Sxc151355 cmdfunc_t *c_fn; 1307c478bd9Sstevel@tonic-gate } cmd_t; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 1337c478bd9Sstevel@tonic-gate { "show-link", do_show_link }, 134210db224Sericheng { "show-dev", do_show_dev }, 1357c478bd9Sstevel@tonic-gate { "create-aggr", do_create_aggr }, 1367c478bd9Sstevel@tonic-gate { "delete-aggr", do_delete_aggr }, 1377c478bd9Sstevel@tonic-gate { "add-aggr", do_add_aggr }, 1387c478bd9Sstevel@tonic-gate { "remove-aggr", do_remove_aggr }, 1397c478bd9Sstevel@tonic-gate { "modify-aggr", do_modify_aggr }, 1407c478bd9Sstevel@tonic-gate { "show-aggr", do_show_aggr }, 1417c478bd9Sstevel@tonic-gate { "up-aggr", do_up_aggr }, 1420ba2cbe9Sxc151355 { "down-aggr", do_down_aggr }, 1430ba2cbe9Sxc151355 { "scan-wifi", do_scan_wifi }, 1440ba2cbe9Sxc151355 { "connect-wifi", do_connect_wifi }, 1450ba2cbe9Sxc151355 { "disconnect-wifi", do_disconnect_wifi }, 1460ba2cbe9Sxc151355 { "show-wifi", do_show_wifi }, 1470ba2cbe9Sxc151355 { "show-linkprop", do_show_linkprop }, 1480ba2cbe9Sxc151355 { "set-linkprop", do_set_linkprop }, 1490ba2cbe9Sxc151355 { "reset-linkprop", do_reset_linkprop }, 1500ba2cbe9Sxc151355 { "create-secobj", do_create_secobj }, 1510ba2cbe9Sxc151355 { "delete-secobj", do_delete_secobj }, 1520ba2cbe9Sxc151355 { "show-secobj", do_show_secobj }, 1530ba2cbe9Sxc151355 { "init-linkprop", do_init_linkprop }, 1540ba2cbe9Sxc151355 { "init-secobj", do_init_secobj } 1557c478bd9Sstevel@tonic-gate }; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static const struct option longopts[] = { 1587c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v' }, 1597c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd' }, 1607c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P' }, 1617c478bd9Sstevel@tonic-gate {"lacp-mode", required_argument, 0, 'l' }, 1627c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T' }, 1637c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u' }, 1647c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's' }, 1657c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i' }, 1667c478bd9Sstevel@tonic-gate {"lacp", no_argument, 0, 'L' }, 1677c478bd9Sstevel@tonic-gate {"temporary", no_argument, 0, 't' }, 1687c478bd9Sstevel@tonic-gate {"root-dir", required_argument, 0, 'r' }, 1697c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p' }, 1707c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 1717c478bd9Sstevel@tonic-gate }; 1727c478bd9Sstevel@tonic-gate 1730ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 1740ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 1750ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 1760ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 1770ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 1780ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 1790ba2cbe9Sxc151355 { 0, 0, 0, 0 } 1800ba2cbe9Sxc151355 }; 1810ba2cbe9Sxc151355 1820ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 1830ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 1840ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 1850ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 1860ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 1870ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 1880ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 1890ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 1900ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 1910ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 1920ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 1930ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 1940ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 1950ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 1960ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 1970ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 1980ba2cbe9Sxc151355 { 0, 0, 0, 0 } 1990ba2cbe9Sxc151355 }; 2000ba2cbe9Sxc151355 2017c478bd9Sstevel@tonic-gate static char *progname; 2020ba2cbe9Sxc151355 static sig_atomic_t signalled; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate static void 2057c478bd9Sstevel@tonic-gate usage(void) 2067c478bd9Sstevel@tonic-gate { 2070ba2cbe9Sxc151355 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 2080ba2cbe9Sxc151355 "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 2090ba2cbe9Sxc151355 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 2100ba2cbe9Sxc151355 "\n" 2110ba2cbe9Sxc151355 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2120ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 2130ba2cbe9Sxc151355 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2140ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] <key>\n" 2150ba2cbe9Sxc151355 "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 2160ba2cbe9Sxc151355 "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2170ba2cbe9Sxc151355 "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2180ba2cbe9Sxc151355 "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 2190ba2cbe9Sxc151355 "\n" 2200ba2cbe9Sxc151355 "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 2210ba2cbe9Sxc151355 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 2220ba2cbe9Sxc151355 " [-s wep]\n" 2230ba2cbe9Sxc151355 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 2240ba2cbe9Sxc151355 "\t [-T <time>] [<name>]\n" 2250ba2cbe9Sxc151355 "\tdisconnect-wifi [-a] [<name>]\n" 2260ba2cbe9Sxc151355 "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 2270ba2cbe9Sxc151355 "\n" 2280ba2cbe9Sxc151355 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 2290ba2cbe9Sxc151355 " <name>\n" 2300ba2cbe9Sxc151355 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 2310ba2cbe9Sxc151355 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 2320ba2cbe9Sxc151355 "\n" 2330ba2cbe9Sxc151355 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 2340ba2cbe9Sxc151355 " <secobj>\n" 2350ba2cbe9Sxc151355 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 2360ba2cbe9Sxc151355 "\tshow-secobj [-pP][<secobj>,...]\n")); 2377c478bd9Sstevel@tonic-gate exit(1); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate int 2417c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate int i; 2447c478bd9Sstevel@tonic-gate cmd_t *cmdp; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2477c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2487c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2497c478bd9Sstevel@tonic-gate #endif 2507c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate progname = argv[0]; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (argc < 2) 2557c478bd9Sstevel@tonic-gate usage(); 2567c478bd9Sstevel@tonic-gate 257cd93090eSericheng if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 25833343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 25933343a97Smeem die("insufficient privileges"); 260cd93090eSericheng 2617c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 2627c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 2637c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 2647c478bd9Sstevel@tonic-gate cmdp->c_fn(argc - 1, &argv[1]); 2657c478bd9Sstevel@tonic-gate exit(0); 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 2707c478bd9Sstevel@tonic-gate progname, argv[1]); 2717c478bd9Sstevel@tonic-gate usage(); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate return (0); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate static void 2777c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[]) 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate char option; 28033343a97Smeem int key; 2817c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 2827c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2837c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 284f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 2857c478bd9Sstevel@tonic-gate uint_t nport = 0; 2867c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 2877c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 2887c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 2897c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 2907c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 2917c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 2927c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 2937c478bd9Sstevel@tonic-gate char *altroot = NULL; 294f595a68aSyz147064 dladm_status_t status; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate opterr = 0; 2977c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 2987c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 2997c478bd9Sstevel@tonic-gate switch (option) { 3007c478bd9Sstevel@tonic-gate case 'd': 30133343a97Smeem if (nport >= MAXPORT) 30233343a97Smeem die("too many <dev> arguments"); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 30533343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 30633343a97Smeem die("device name too long"); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate nport++; 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate case 'P': 31133343a97Smeem if (P_arg) 31233343a97Smeem die_optdup(option); 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 315f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 31633343a97Smeem die("invalid policy '%s'", optarg); 3177c478bd9Sstevel@tonic-gate break; 3187c478bd9Sstevel@tonic-gate case 'u': 31933343a97Smeem if (u_arg) 32033343a97Smeem die_optdup(option); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 323f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 32433343a97Smeem mac_addr)) 32533343a97Smeem die("invalid MAC address '%s'", optarg); 3267c478bd9Sstevel@tonic-gate break; 3277c478bd9Sstevel@tonic-gate case 'l': 32833343a97Smeem if (l_arg) 32933343a97Smeem die_optdup(option); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 332f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 33333343a97Smeem die("invalid LACP mode '%s'", optarg); 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate case 'T': 33633343a97Smeem if (T_arg) 33733343a97Smeem die_optdup(option); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 340f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 34133343a97Smeem die("invalid LACP timer value '%s'", optarg); 3427c478bd9Sstevel@tonic-gate break; 3437c478bd9Sstevel@tonic-gate case 't': 3447c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 3457c478bd9Sstevel@tonic-gate break; 3467c478bd9Sstevel@tonic-gate case 'R': 3477c478bd9Sstevel@tonic-gate altroot = optarg; 3487c478bd9Sstevel@tonic-gate break; 3497c478bd9Sstevel@tonic-gate default: 35033343a97Smeem die_opterr(optopt, option); 35133343a97Smeem break; 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate if (nport == 0) 3567c478bd9Sstevel@tonic-gate usage(); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 3597c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 3607c478bd9Sstevel@tonic-gate usage(); 3617c478bd9Sstevel@tonic-gate 36233343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 36333343a97Smeem die("invalid key value '%s'", argv[optind]); 3647c478bd9Sstevel@tonic-gate 365f595a68aSyz147064 status = dladm_aggr_create(key, nport, port, policy, mac_addr_fixed, 366f595a68aSyz147064 mac_addr, lacp_mode, lacp_timer, t_arg, altroot); 367f595a68aSyz147064 if (status != DLADM_STATUS_OK) 368f595a68aSyz147064 die_dlerr(status, "create operation failed"); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate static void 3727c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[]) 3737c478bd9Sstevel@tonic-gate { 37433343a97Smeem int key; 3757c478bd9Sstevel@tonic-gate char option; 3767c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3777c478bd9Sstevel@tonic-gate char *altroot = NULL; 378f595a68aSyz147064 dladm_status_t status; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate opterr = 0; 3817c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":R:t", longopts, 3827c478bd9Sstevel@tonic-gate NULL)) != -1) { 3837c478bd9Sstevel@tonic-gate switch (option) { 3847c478bd9Sstevel@tonic-gate case 't': 3857c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 3867c478bd9Sstevel@tonic-gate break; 3877c478bd9Sstevel@tonic-gate case 'R': 3887c478bd9Sstevel@tonic-gate altroot = optarg; 3897c478bd9Sstevel@tonic-gate break; 3907c478bd9Sstevel@tonic-gate default: 39133343a97Smeem die_opterr(optopt, option); 3927c478bd9Sstevel@tonic-gate break; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 3977c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 3987c478bd9Sstevel@tonic-gate usage(); 3997c478bd9Sstevel@tonic-gate 40033343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 40133343a97Smeem die("invalid key value '%s'", argv[optind]); 4027c478bd9Sstevel@tonic-gate 403f595a68aSyz147064 status = dladm_aggr_delete(key, t_arg, altroot); 404f595a68aSyz147064 if (status != DLADM_STATUS_OK) 405f595a68aSyz147064 die_dlerr(status, "delete operation failed"); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate static void 4097c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[]) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate char option; 41233343a97Smeem int key; 413f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 4147c478bd9Sstevel@tonic-gate uint_t nport = 0; 4157c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4167c478bd9Sstevel@tonic-gate char *altroot = NULL; 417f595a68aSyz147064 dladm_status_t status; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate opterr = 0; 4207c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 4217c478bd9Sstevel@tonic-gate NULL)) != -1) { 4227c478bd9Sstevel@tonic-gate switch (option) { 4237c478bd9Sstevel@tonic-gate case 'd': 42433343a97Smeem if (nport >= MAXPORT) 42533343a97Smeem die("too many <dev> arguments"); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 42833343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 42933343a97Smeem die("device name too long"); 43033343a97Smeem 4317c478bd9Sstevel@tonic-gate nport++; 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case 't': 4347c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate case 'R': 4377c478bd9Sstevel@tonic-gate altroot = optarg; 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate default: 44033343a97Smeem die_opterr(optopt, option); 44133343a97Smeem break; 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (nport == 0) 4467c478bd9Sstevel@tonic-gate usage(); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4497c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4507c478bd9Sstevel@tonic-gate usage(); 4517c478bd9Sstevel@tonic-gate 45233343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 45333343a97Smeem die("invalid key value '%s'", argv[optind]); 4547c478bd9Sstevel@tonic-gate 455f595a68aSyz147064 status = dladm_aggr_add(key, nport, port, t_arg, altroot); 456f595a68aSyz147064 if (status != DLADM_STATUS_OK) { 457219a2a31Shl157128 /* 458f595a68aSyz147064 * checking DLADM_STATUS_NOTSUP is a temporary workaround 459219a2a31Shl157128 * and should be removed once 6399681 is fixed. 460219a2a31Shl157128 */ 461f595a68aSyz147064 if (status == DLADM_STATUS_NOTSUP) { 462219a2a31Shl157128 (void) fprintf(stderr, 463219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 464219a2a31Shl157128 progname, 465219a2a31Shl157128 gettext("device capabilities don't match")); 466219a2a31Shl157128 exit(ENOTSUP); 467219a2a31Shl157128 } 468f595a68aSyz147064 die_dlerr(status, "add operation failed"); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate static void 4737c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[]) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate char option; 47633343a97Smeem int key; 477f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 4787c478bd9Sstevel@tonic-gate uint_t nport = 0; 4797c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4807c478bd9Sstevel@tonic-gate char *altroot = NULL; 481f595a68aSyz147064 dladm_status_t status; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate opterr = 0; 4847c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", 4857c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 4867c478bd9Sstevel@tonic-gate switch (option) { 4877c478bd9Sstevel@tonic-gate case 'd': 48833343a97Smeem if (nport >= MAXPORT) 48933343a97Smeem die("too many <dev> arguments"); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 49233343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 49333343a97Smeem die("device name too long"); 49433343a97Smeem 4957c478bd9Sstevel@tonic-gate nport++; 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate case 't': 4987c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4997c478bd9Sstevel@tonic-gate break; 5007c478bd9Sstevel@tonic-gate case 'R': 5017c478bd9Sstevel@tonic-gate altroot = optarg; 5027c478bd9Sstevel@tonic-gate break; 5037c478bd9Sstevel@tonic-gate default: 50433343a97Smeem die_opterr(optopt, option); 50533343a97Smeem break; 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (nport == 0) 5107c478bd9Sstevel@tonic-gate usage(); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 5137c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 5147c478bd9Sstevel@tonic-gate usage(); 5157c478bd9Sstevel@tonic-gate 51633343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 51733343a97Smeem die("invalid key value '%s'", argv[optind]); 5187c478bd9Sstevel@tonic-gate 519f595a68aSyz147064 status = dladm_aggr_remove(key, nport, port, t_arg, altroot); 520f595a68aSyz147064 if (status != DLADM_STATUS_OK) 521f595a68aSyz147064 die_dlerr(status, "remove operation failed"); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate static void 5257c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[]) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate char option; 52833343a97Smeem int key; 5297c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 5307c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 5317c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 5327c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 5337c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 5347c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 5357c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 5367c478bd9Sstevel@tonic-gate char *altroot = NULL; 537f595a68aSyz147064 dladm_status_t status; 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate opterr = 0; 5407c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 5417c478bd9Sstevel@tonic-gate NULL)) != -1) { 5427c478bd9Sstevel@tonic-gate switch (option) { 5437c478bd9Sstevel@tonic-gate case 'P': 544f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 54533343a97Smeem die_optdup(option); 5467c478bd9Sstevel@tonic-gate 547f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 5487c478bd9Sstevel@tonic-gate 549f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 55033343a97Smeem die("invalid policy '%s'", optarg); 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case 'u': 553f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 55433343a97Smeem die_optdup(option); 5557c478bd9Sstevel@tonic-gate 556f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_MAC; 5577c478bd9Sstevel@tonic-gate 558f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 55933343a97Smeem mac_addr)) 56033343a97Smeem die("invalid MAC address '%s'", optarg); 5617c478bd9Sstevel@tonic-gate break; 5627c478bd9Sstevel@tonic-gate case 'l': 563f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 56433343a97Smeem die_optdup(option); 5657c478bd9Sstevel@tonic-gate 566f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 5677c478bd9Sstevel@tonic-gate 568f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 56933343a97Smeem die("invalid LACP mode '%s'", optarg); 5707c478bd9Sstevel@tonic-gate break; 5717c478bd9Sstevel@tonic-gate case 'T': 572f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 57333343a97Smeem die_optdup(option); 5747c478bd9Sstevel@tonic-gate 575f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 5767c478bd9Sstevel@tonic-gate 577f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 57833343a97Smeem die("invalid LACP timer value '%s'", optarg); 5797c478bd9Sstevel@tonic-gate break; 5807c478bd9Sstevel@tonic-gate case 't': 5817c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5827c478bd9Sstevel@tonic-gate break; 5837c478bd9Sstevel@tonic-gate case 'R': 5847c478bd9Sstevel@tonic-gate altroot = optarg; 5857c478bd9Sstevel@tonic-gate break; 5867c478bd9Sstevel@tonic-gate default: 58733343a97Smeem die_opterr(optopt, option); 58833343a97Smeem break; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 59233343a97Smeem if (modify_mask == 0) 59333343a97Smeem die("at least one of the -PulT options must be specified"); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 5967c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 5977c478bd9Sstevel@tonic-gate usage(); 5987c478bd9Sstevel@tonic-gate 59933343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 60033343a97Smeem die("invalid key value '%s'", argv[optind]); 6017c478bd9Sstevel@tonic-gate 602f595a68aSyz147064 status = dladm_aggr_modify(key, modify_mask, policy, mac_addr_fixed, 603f595a68aSyz147064 mac_addr, lacp_mode, lacp_timer, t_arg, altroot); 604f595a68aSyz147064 if (status != DLADM_STATUS_OK) 605f595a68aSyz147064 die_dlerr(status, "modify operation failed"); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate static void 6097c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[]) 6107c478bd9Sstevel@tonic-gate { 61133343a97Smeem int key = 0; 612f595a68aSyz147064 dladm_status_t status; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6157c478bd9Sstevel@tonic-gate if (argc == 2) { 61633343a97Smeem if (!str2int(argv[1], &key) || key < 1) 61733343a97Smeem die("invalid key value '%s'", argv[1]); 6187c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6197c478bd9Sstevel@tonic-gate usage(); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 622f595a68aSyz147064 if ((status = dladm_aggr_up(key, NULL)) != DLADM_STATUS_OK) { 6237c478bd9Sstevel@tonic-gate if (key != 0) { 624f595a68aSyz147064 die_dlerr(status, "could not bring up aggregation '%u'", 62533343a97Smeem key); 6267c478bd9Sstevel@tonic-gate } else { 627f595a68aSyz147064 die_dlerr(status, "could not bring aggregations up"); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate static void 6337c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[]) 6347c478bd9Sstevel@tonic-gate { 635f595a68aSyz147064 dladm_status_t status; 63633343a97Smeem int key = 0; 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6397c478bd9Sstevel@tonic-gate if (argc == 2) { 64033343a97Smeem if (!str2int(argv[1], &key) || key < 1) 64133343a97Smeem die("invalid key value '%s'", argv[1]); 6427c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6437c478bd9Sstevel@tonic-gate usage(); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 646f595a68aSyz147064 if ((status = dladm_aggr_down(key)) != DLADM_STATUS_OK) { 6477c478bd9Sstevel@tonic-gate if (key != 0) { 648f595a68aSyz147064 die_dlerr(status, 649f595a68aSyz147064 "could not bring down aggregation '%u'", key); 6507c478bd9Sstevel@tonic-gate } else { 651f595a68aSyz147064 die_dlerr(status, "could not bring down aggregations"); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate #define TYPE_WIDTH 10 657210db224Sericheng 658210db224Sericheng static void 659210db224Sericheng print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 660210db224Sericheng { 661210db224Sericheng char type[TYPE_WIDTH]; 662210db224Sericheng 663210db224Sericheng if (!legacy) { 664c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 665c7e4935fSss150715 uint_t instance; 666ba2e4443Sseb 667210db224Sericheng if (dap->da_vid != 0) { 668210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "vlan %u", 669210db224Sericheng dap->da_vid); 670210db224Sericheng } else { 671210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 672210db224Sericheng } 673c7e4935fSss150715 674c7e4935fSss150715 if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS) 675ba2e4443Sseb return; 676c7e4935fSss150715 677ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 678210db224Sericheng (void) printf("%s type=%s mtu=%d key=%u\n", 679ba2e4443Sseb name, type, dap->da_max_sdu, instance); 680210db224Sericheng } else { 681210db224Sericheng (void) printf("%s type=%s mtu=%d device=%s\n", 682210db224Sericheng name, type, dap->da_max_sdu, dap->da_dev); 683210db224Sericheng } 684210db224Sericheng } else { 685210db224Sericheng (void) printf("%s type=legacy mtu=%d device=%s\n", 686210db224Sericheng name, dap->da_max_sdu, name); 687210db224Sericheng } 688210db224Sericheng } 689210db224Sericheng 690210db224Sericheng static void 691210db224Sericheng print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 692210db224Sericheng { 693210db224Sericheng char type[TYPE_WIDTH]; 694210db224Sericheng 695210db224Sericheng if (!legacy) { 696c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 697c7e4935fSss150715 uint_t instance; 698ba2e4443Sseb 699210db224Sericheng if (dap->da_vid != 0) { 700210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 701210db224Sericheng dap->da_vid); 702210db224Sericheng } else { 703210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 704210db224Sericheng } 705c7e4935fSss150715 706c7e4935fSss150715 if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS) 707ba2e4443Sseb return; 708ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 709210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 710210db224Sericheng "\taggregation: key %u\n"), name, type, 711ba2e4443Sseb dap->da_max_sdu, instance); 712210db224Sericheng } else { 713210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: " 714210db224Sericheng "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 715210db224Sericheng dap->da_dev); 716210db224Sericheng } 717210db224Sericheng } else { 718210db224Sericheng (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 719210db224Sericheng "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 720210db224Sericheng } 721210db224Sericheng } 722210db224Sericheng 723210db224Sericheng static int 724210db224Sericheng get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 725210db224Sericheng { 726210db224Sericheng int err; 727210db224Sericheng 728210db224Sericheng if ((err = dladm_info(name, dlattrp)) == 0) { 729210db224Sericheng *legacy = B_FALSE; 730210db224Sericheng } else if (err < 0 && errno == ENODEV) { 731c7e4935fSss150715 dlpi_handle_t dh; 732c7e4935fSss150715 dlpi_info_t dlinfo; 733210db224Sericheng 734210db224Sericheng /* 735210db224Sericheng * A return value of ENODEV means that the specified 736210db224Sericheng * device is not gldv3. 737210db224Sericheng */ 738c7e4935fSss150715 if (dlpi_open(name, &dh, 0) != DLPI_SUCCESS) { 739210db224Sericheng errno = ENOENT; 740210db224Sericheng return (-1); 741210db224Sericheng } 742c7e4935fSss150715 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 743c7e4935fSss150715 dlpi_close(dh); 744c7e4935fSss150715 errno = EINVAL; 745c7e4935fSss150715 return (-1); 746c7e4935fSss150715 } 747c7e4935fSss150715 dlpi_close(dh); 748c7e4935fSss150715 *legacy = B_TRUE; 749c7e4935fSss150715 bzero(dlattrp, sizeof (*dlattrp)); 750c7e4935fSss150715 dlattrp->da_max_sdu = dlinfo.di_max_sdu; 751c7e4935fSss150715 752210db224Sericheng } else { 753210db224Sericheng /* 754210db224Sericheng * If the return value is not ENODEV, this means that 755210db224Sericheng * user is either passing in a bogus interface name 756210db224Sericheng * or a vlan interface name that doesn't exist yet. 757210db224Sericheng */ 758210db224Sericheng errno = ENOENT; 759210db224Sericheng return (-1); 760210db224Sericheng } 761210db224Sericheng return (0); 762210db224Sericheng } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7657c478bd9Sstevel@tonic-gate static void 7667c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name) 7677c478bd9Sstevel@tonic-gate { 7687c478bd9Sstevel@tonic-gate dladm_attr_t dlattr; 769210db224Sericheng boolean_t legacy = B_TRUE; 7707c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7717c478bd9Sstevel@tonic-gate 77233343a97Smeem if (get_if_info(name, &dlattr, &legacy) < 0) 77333343a97Smeem die("invalid link '%s'", name); 7747c478bd9Sstevel@tonic-gate 775210db224Sericheng if (state->ls_parseable) { 776210db224Sericheng print_link_parseable(name, &dlattr, legacy); 7777c478bd9Sstevel@tonic-gate } else { 778210db224Sericheng print_link(name, &dlattr, legacy); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate static void 7837c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7867c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 7897c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 7907c478bd9Sstevel@tonic-gate return; 7917c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 7927c478bd9Sstevel@tonic-gate } else { 7937c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate get_link_stats(name, &stats); 7977c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ls_prevstats); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate (void) printf("%s", name); 8007c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 8017c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 8027c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 8037c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 8047c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 8057c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate static void 811f595a68aSyz147064 dump_grp(dladm_aggr_grp_attr_t *grp, boolean_t parseable) 8127c478bd9Sstevel@tonic-gate { 813f595a68aSyz147064 char buf[DLADM_STRSIZE]; 8147c478bd9Sstevel@tonic-gate char addr_str[ETHERADDRL * 3]; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (!parseable) { 8177c478bd9Sstevel@tonic-gate (void) printf(gettext("key: %d (0x%04x)"), 8187c478bd9Sstevel@tonic-gate grp->lg_key, grp->lg_key); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate (void) printf(gettext("\tpolicy: %s"), 821f595a68aSyz147064 dladm_aggr_policy2str(grp->lg_policy, buf)); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate (void) printf(gettext("\taddress: %s (%s)\n"), 824f595a68aSyz147064 dladm_aggr_macaddr2str(grp->lg_mac, addr_str), 8257c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 8267c478bd9Sstevel@tonic-gate } else { 8277c478bd9Sstevel@tonic-gate (void) printf("aggr key=%d", grp->lg_key); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate (void) printf(" policy=%s", 830f595a68aSyz147064 dladm_aggr_policy2str(grp->lg_policy, buf)); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate (void) printf(" address=%s", 833f595a68aSyz147064 dladm_aggr_macaddr2str(grp->lg_mac, addr_str)); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate (void) printf(" address-type=%s\n", 8367c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? "fixed" : "auto"); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate static void 841f595a68aSyz147064 dump_grp_lacp(dladm_aggr_grp_attr_t *grp, boolean_t parseable) 8427c478bd9Sstevel@tonic-gate { 843f595a68aSyz147064 char lacp_mode_str[DLADM_STRSIZE]; 844f595a68aSyz147064 char lacp_timer_str[DLADM_STRSIZE]; 845f595a68aSyz147064 846f595a68aSyz147064 (void) dladm_aggr_lacpmode2str(grp->lg_lacp_mode, lacp_mode_str); 847f595a68aSyz147064 (void) dladm_aggr_lacptimer2str(grp->lg_lacp_timer, lacp_timer_str); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (!parseable) { 8507c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 8517c478bd9Sstevel@tonic-gate (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 8527c478bd9Sstevel@tonic-gate } else { 8537c478bd9Sstevel@tonic-gate (void) printf(" lacp-mode=%s", lacp_mode_str); 8547c478bd9Sstevel@tonic-gate (void) printf(" lacp-timer=%s\n", lacp_timer_str); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate static void 859f595a68aSyz147064 dump_grp_stats(dladm_aggr_grp_attr_t *grp) 8607c478bd9Sstevel@tonic-gate { 8617c478bd9Sstevel@tonic-gate (void) printf("key: %d", grp->lg_key); 8627c478bd9Sstevel@tonic-gate (void) printf("\tipackets rbytes opackets obytes "); 8637c478bd9Sstevel@tonic-gate (void) printf("%%ipkts %%opkts\n"); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate static void 8677c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 8707c478bd9Sstevel@tonic-gate gettext("timeout"), gettext("aggregatable"), gettext("sync"), 8717c478bd9Sstevel@tonic-gate gettext("coll"), gettext("dist"), gettext("defaulted"), 8727c478bd9Sstevel@tonic-gate gettext("expired")); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate static void 8767c478bd9Sstevel@tonic-gate dump_ports_head(void) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 8797c478bd9Sstevel@tonic-gate "state\n")); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate static void 883f595a68aSyz147064 dump_port(dladm_aggr_port_attr_t *port, boolean_t parseable) 8847c478bd9Sstevel@tonic-gate { 8857c478bd9Sstevel@tonic-gate char *dev = port->lp_devname; 886f595a68aSyz147064 char mac_addr[ETHERADDRL * 3]; 887f595a68aSyz147064 char buf[DLADM_STRSIZE]; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate if (!parseable) { 890f595a68aSyz147064 (void) printf(" %-9s\t%s", dev, dladm_aggr_macaddr2str( 891f595a68aSyz147064 port->lp_mac, mac_addr)); 89233343a97Smeem (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) / 8937c478bd9Sstevel@tonic-gate 1000000ull)); 894*3a62633bSyz147064 (void) printf("\t%s", mac_link_duplex(dev, buf)); 895*3a62633bSyz147064 (void) printf("\t%s", mac_link_state(dev, buf)); 896f595a68aSyz147064 (void) printf("\t%s\n", 897f595a68aSyz147064 dladm_aggr_portstate2str(port->lp_state, buf)); 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate } else { 9007c478bd9Sstevel@tonic-gate (void) printf(" device=%s address=%s", dev, 901f595a68aSyz147064 dladm_aggr_macaddr2str(port->lp_mac, mac_addr)); 902ba2e4443Sseb (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 9037c478bd9Sstevel@tonic-gate 1000000ull)); 904*3a62633bSyz147064 (void) printf(" duplex=%s", mac_link_duplex(dev, buf)); 905*3a62633bSyz147064 (void) printf(" link=%s", mac_link_state(dev, buf)); 906f595a68aSyz147064 (void) printf(" port=%s", 907f595a68aSyz147064 dladm_aggr_portstate2str(port->lp_state, buf)); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate static void 912f595a68aSyz147064 dump_port_lacp(dladm_aggr_port_attr_t *port) 9137c478bd9Sstevel@tonic-gate { 9147c478bd9Sstevel@tonic-gate aggr_lacp_state_t *state = &port->lp_lacp_state; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, 9177c478bd9Sstevel@tonic-gate port->lp_devname, state->bit.activity ? "active" : "passive", 9187c478bd9Sstevel@tonic-gate state->bit.timeout ? "short" : "long", 9197c478bd9Sstevel@tonic-gate state->bit.aggregation ? "yes" : "no", 9207c478bd9Sstevel@tonic-gate state->bit.sync ? "yes" : "no", 9217c478bd9Sstevel@tonic-gate state->bit.collecting ? "yes" : "no", 9227c478bd9Sstevel@tonic-gate state->bit.distributing ? "yes" : "no", 9237c478bd9Sstevel@tonic-gate state->bit.defaulted ? "yes" : "no", 9247c478bd9Sstevel@tonic-gate state->bit.expired ? "yes" : "no"); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate static void 9287c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 9297c478bd9Sstevel@tonic-gate pktsum_t *tot_stats) 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate pktsum_t diff_stats; 9327c478bd9Sstevel@tonic-gate pktsum_t *old_stats = &state->gs_prevstats[index]; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, port_stats, old_stats); 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", diff_stats.ipackets); 9377c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 9387c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 9397c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate if (tot_stats->ipackets == 0) 9427c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9437c478bd9Sstevel@tonic-gate else 9447c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 9457c478bd9Sstevel@tonic-gate (double)tot_stats->ipackets * 100); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if (tot_stats->opackets == 0) 9487c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9497c478bd9Sstevel@tonic-gate else 9507c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 9517c478bd9Sstevel@tonic-gate (double)tot_stats->opackets * 100); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate (void) printf("\n"); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate *old_stats = *port_stats; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate static int 959f595a68aSyz147064 show_key(void *arg, dladm_aggr_grp_attr_t *grp) 9607c478bd9Sstevel@tonic-gate { 9617c478bd9Sstevel@tonic-gate show_grp_state_t *state = (show_grp_state_t *)arg; 9627c478bd9Sstevel@tonic-gate int i; 9637c478bd9Sstevel@tonic-gate pktsum_t pktsumtot, port_stat; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate if (state->gs_key != 0 && state->gs_key != grp->lg_key) 9667c478bd9Sstevel@tonic-gate return (0); 9677c478bd9Sstevel@tonic-gate if (state->gs_firstonly) { 9687c478bd9Sstevel@tonic-gate if (state->gs_found) 9697c478bd9Sstevel@tonic-gate return (0); 9707c478bd9Sstevel@tonic-gate } else { 9717c478bd9Sstevel@tonic-gate bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate state->gs_found = B_TRUE; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate if (state->gs_stats) { 9777c478bd9Sstevel@tonic-gate /* show statistics */ 9787c478bd9Sstevel@tonic-gate dump_grp_stats(grp); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 9817c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 9827c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 983ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 9847c478bd9Sstevel@tonic-gate stats_total(&pktsumtot, &port_stat, 9857c478bd9Sstevel@tonic-gate &state->gs_prevstats[i]); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate (void) printf(" Total"); 9897c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", pktsumtot.ipackets); 9907c478bd9Sstevel@tonic-gate (void) printf("%-12llu", pktsumtot.rbytes); 9917c478bd9Sstevel@tonic-gate (void) printf("%-10llu", pktsumtot.opackets); 9927c478bd9Sstevel@tonic-gate (void) printf("%-12llu\n", pktsumtot.obytes); 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 995ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 9967c478bd9Sstevel@tonic-gate (void) printf(" %s", grp->lg_ports[i].lp_devname); 9977c478bd9Sstevel@tonic-gate dump_port_stat(i, state, &port_stat, &pktsumtot); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate } else if (state->gs_lacp) { 10007c478bd9Sstevel@tonic-gate /* show LACP info */ 10017c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10027c478bd9Sstevel@tonic-gate dump_grp_lacp(grp, state->gs_parseable); 10037c478bd9Sstevel@tonic-gate dump_ports_lacp_head(); 10047c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) 10057c478bd9Sstevel@tonic-gate dump_port_lacp(&grp->lg_ports[i]); 10067c478bd9Sstevel@tonic-gate } else { 10077c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10087c478bd9Sstevel@tonic-gate if (!state->gs_parseable) 10097c478bd9Sstevel@tonic-gate dump_ports_head(); 10107c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 10117c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10127c478bd9Sstevel@tonic-gate (void) printf("dev key=%d", grp->lg_key); 10137c478bd9Sstevel@tonic-gate dump_port(&grp->lg_ports[i], state->gs_parseable); 10147c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10157c478bd9Sstevel@tonic-gate (void) printf("\n"); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate return (0); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate static int 10237c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 10247c478bd9Sstevel@tonic-gate { 10257c478bd9Sstevel@tonic-gate kstat_named_t *knp; 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 10287c478bd9Sstevel@tonic-gate return (-1); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (knp->data_type != type) 10317c478bd9Sstevel@tonic-gate return (-1); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate switch (type) { 10347c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT64: 10357c478bd9Sstevel@tonic-gate *(uint64_t *)buf = knp->value.ui64; 10367c478bd9Sstevel@tonic-gate break; 10377c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT32: 10387c478bd9Sstevel@tonic-gate *(uint32_t *)buf = knp->value.ui32; 10397c478bd9Sstevel@tonic-gate break; 10407c478bd9Sstevel@tonic-gate default: 10417c478bd9Sstevel@tonic-gate return (-1); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate return (0); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate static void 1048210db224Sericheng show_dev(void *arg, const char *dev) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 1051*3a62633bSyz147064 char buf[DLADM_STRSIZE]; 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate if (!state->ms_parseable) { 10567c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tlink: %s"), 1057*3a62633bSyz147064 mac_link_state(dev, buf)); 105833343a97Smeem (void) printf(gettext("\tspeed: %5uMb"), 1059ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 10607c478bd9Sstevel@tonic-gate (void) printf(gettext("\tduplex: %s\n"), 1061*3a62633bSyz147064 mac_link_duplex(dev, buf)); 10627c478bd9Sstevel@tonic-gate } else { 1063*3a62633bSyz147064 (void) printf(" link=%s", mac_link_state(dev, buf)); 10647c478bd9Sstevel@tonic-gate (void) printf(" speed=%u", 1065ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1066*3a62633bSyz147064 (void) printf(" duplex=%s\n", mac_link_duplex(dev, buf)); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10717c478bd9Sstevel@tonic-gate static void 1072210db224Sericheng show_dev_stats(void *arg, const char *dev) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10757c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate if (state->ms_firstonly) { 10787c478bd9Sstevel@tonic-gate if (state->ms_donefirst) 10797c478bd9Sstevel@tonic-gate return; 10807c478bd9Sstevel@tonic-gate state->ms_donefirst = B_TRUE; 10817c478bd9Sstevel@tonic-gate } else { 10827c478bd9Sstevel@tonic-gate bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 1085ba2e4443Sseb get_mac_stats(dev, &stats); 10867c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ms_prevstats); 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 10897c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 10907c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 10917c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 10927c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 10937c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 10947c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate state->ms_prevstats = stats; 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate static void 11007c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[]) 11017c478bd9Sstevel@tonic-gate { 11027c478bd9Sstevel@tonic-gate char *name = NULL; 11037c478bd9Sstevel@tonic-gate int option; 11047c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11057c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 110633343a97Smeem int interval = 0; 11077c478bd9Sstevel@tonic-gate show_link_state_t state; 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate state.ls_stats = B_FALSE; 11107c478bd9Sstevel@tonic-gate state.ls_parseable = B_FALSE; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate opterr = 0; 11137c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 11147c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11157c478bd9Sstevel@tonic-gate switch (option) { 11167c478bd9Sstevel@tonic-gate case 'p': 11177c478bd9Sstevel@tonic-gate state.ls_parseable = B_TRUE; 11187c478bd9Sstevel@tonic-gate break; 11197c478bd9Sstevel@tonic-gate case 's': 112033343a97Smeem if (s_arg) 112133343a97Smeem die_optdup(option); 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 11247c478bd9Sstevel@tonic-gate break; 11257c478bd9Sstevel@tonic-gate case 'i': 112633343a97Smeem if (i_arg) 112733343a97Smeem die_optdup(option); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 113033343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 113133343a97Smeem die("invalid interval value '%s'", optarg); 11327c478bd9Sstevel@tonic-gate break; 11337c478bd9Sstevel@tonic-gate default: 113433343a97Smeem die_opterr(optopt, option); 113533343a97Smeem break; 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 113933343a97Smeem if (i_arg && !s_arg) 114033343a97Smeem die("the option -i can be used only with -s"); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 11437c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 11447c478bd9Sstevel@tonic-gate name = argv[optind]; 11457c478bd9Sstevel@tonic-gate else if (optind != argc) 11467c478bd9Sstevel@tonic-gate usage(); 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate if (s_arg) { 11497c478bd9Sstevel@tonic-gate link_stats(name, interval); 11507c478bd9Sstevel@tonic-gate return; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 1153210db224Sericheng if (name == NULL) { 11547c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link, &state); 1155210db224Sericheng } else { 11567c478bd9Sstevel@tonic-gate show_link(&state, name); 11577c478bd9Sstevel@tonic-gate } 1158210db224Sericheng } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate static void 11617c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[]) 11627c478bd9Sstevel@tonic-gate { 11637c478bd9Sstevel@tonic-gate int option; 116433343a97Smeem int key = 0; 11657c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 11667c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11677c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 11687c478bd9Sstevel@tonic-gate show_grp_state_t state; 116933343a97Smeem int interval = 0; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate state.gs_stats = B_FALSE; 11727c478bd9Sstevel@tonic-gate state.gs_lacp = B_FALSE; 11737c478bd9Sstevel@tonic-gate state.gs_parseable = B_FALSE; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate opterr = 0; 11767c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":Lpsi:", 11777c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11787c478bd9Sstevel@tonic-gate switch (option) { 11797c478bd9Sstevel@tonic-gate case 'L': 118033343a97Smeem if (L_arg) 118133343a97Smeem die_optdup(option); 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate if (s_arg || i_arg) { 118433343a97Smeem die("the option -L cannot be used with -i " 118533343a97Smeem "or -s"); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 11897c478bd9Sstevel@tonic-gate state.gs_lacp = B_TRUE; 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate case 'p': 11927c478bd9Sstevel@tonic-gate state.gs_parseable = B_TRUE; 11937c478bd9Sstevel@tonic-gate break; 11947c478bd9Sstevel@tonic-gate case 's': 119533343a97Smeem if (s_arg) 119633343a97Smeem die_optdup(option); 11977c478bd9Sstevel@tonic-gate 119833343a97Smeem if (L_arg) 119913994ee8Sxz162242 die("the option -s cannot be used with -L"); 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12027c478bd9Sstevel@tonic-gate break; 12037c478bd9Sstevel@tonic-gate case 'i': 120433343a97Smeem if (i_arg) 120533343a97Smeem die_optdup(option); 12067c478bd9Sstevel@tonic-gate 120733343a97Smeem if (L_arg) 120833343a97Smeem die("the option -i cannot be used with -L"); 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 121133343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 121233343a97Smeem die("invalid interval value '%s'", optarg); 12137c478bd9Sstevel@tonic-gate break; 12147c478bd9Sstevel@tonic-gate default: 121533343a97Smeem die_opterr(optopt, option); 121633343a97Smeem break; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 122033343a97Smeem if (i_arg && !s_arg) 122133343a97Smeem die("the option -i can be used only with -s"); 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 12247c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 122533343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 122633343a97Smeem die("invalid key value '%s'", argv[optind]); 12277c478bd9Sstevel@tonic-gate } else if (optind != argc) { 12287c478bd9Sstevel@tonic-gate usage(); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate if (s_arg) { 12327c478bd9Sstevel@tonic-gate aggr_stats(key, interval); 12337c478bd9Sstevel@tonic-gate return; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate state.gs_key = key; 12377c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 12387c478bd9Sstevel@tonic-gate 1239f595a68aSyz147064 (void) dladm_aggr_walk(show_key, &state); 12407c478bd9Sstevel@tonic-gate 124133343a97Smeem if (key != 0 && !state.gs_found) 124233343a97Smeem die("non-existent aggregation key '%u'", key); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate static void 12467c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[]) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate int option; 12497c478bd9Sstevel@tonic-gate char *dev = NULL; 12507c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 12517c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 125233343a97Smeem int interval = 0; 12537c478bd9Sstevel@tonic-gate show_mac_state_t state; 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate state.ms_parseable = B_FALSE; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate opterr = 0; 12587c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 12597c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 12607c478bd9Sstevel@tonic-gate switch (option) { 12617c478bd9Sstevel@tonic-gate case 'p': 12627c478bd9Sstevel@tonic-gate state.ms_parseable = B_TRUE; 12637c478bd9Sstevel@tonic-gate break; 12647c478bd9Sstevel@tonic-gate case 's': 126533343a97Smeem if (s_arg) 126633343a97Smeem die_optdup(option); 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12697c478bd9Sstevel@tonic-gate break; 12707c478bd9Sstevel@tonic-gate case 'i': 127133343a97Smeem if (i_arg) 127233343a97Smeem die_optdup(option); 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 127533343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 127633343a97Smeem die("invalid interval value '%s'", optarg); 12777c478bd9Sstevel@tonic-gate break; 12787c478bd9Sstevel@tonic-gate default: 127933343a97Smeem die_opterr(optopt, option); 128033343a97Smeem break; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 128433343a97Smeem if (i_arg && !s_arg) 128533343a97Smeem die("the option -i can be used only with -s"); 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate /* get dev name (optional last argument) */ 12887c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 12897c478bd9Sstevel@tonic-gate dev = argv[optind]; 12907c478bd9Sstevel@tonic-gate else if (optind != argc) 12917c478bd9Sstevel@tonic-gate usage(); 12927c478bd9Sstevel@tonic-gate 1293cd93090eSericheng if (dev != NULL) { 1294c7e4935fSss150715 uint_t ppa; 1295c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 1296cd93090eSericheng dladm_attr_t dlattr; 1297cd93090eSericheng boolean_t legacy; 1298cd93090eSericheng 1299cd93090eSericheng /* 1300cd93090eSericheng * Check for invalid devices. 1301cd93090eSericheng * aggregations and vlans are not considered devices. 1302cd93090eSericheng */ 1303c7e4935fSss150715 if (dlpi_parselink(dev, drv, &ppa) != DLPI_SUCCESS || 1304c7e4935fSss150715 strcmp(drv, "aggr") == 0 || ppa >= 1000 || 1305c7e4935fSss150715 get_if_info(dev, &dlattr, &legacy) < 0) 130633343a97Smeem die("invalid device '%s'", dev); 1307cd93090eSericheng } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (s_arg) { 13107c478bd9Sstevel@tonic-gate dev_stats(dev, interval); 13117c478bd9Sstevel@tonic-gate return; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if (dev == NULL) 1315f595a68aSyz147064 (void) dladm_mac_walk(show_dev, &state); 13167c478bd9Sstevel@tonic-gate else 1317210db224Sericheng show_dev(&state, dev); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13217c478bd9Sstevel@tonic-gate static void 132233343a97Smeem link_stats(const char *link, uint_t interval) 13237c478bd9Sstevel@tonic-gate { 1324210db224Sericheng dladm_attr_t dlattr; 1325210db224Sericheng boolean_t legacy; 13267c478bd9Sstevel@tonic-gate show_link_state_t state; 13277c478bd9Sstevel@tonic-gate 132833343a97Smeem if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 132933343a97Smeem die("invalid link '%s'", link); 133033343a97Smeem 13317c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* 13347c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13357c478bd9Sstevel@tonic-gate * only for the first MAC port. 13367c478bd9Sstevel@tonic-gate */ 13377c478bd9Sstevel@tonic-gate state.ls_firstonly = (interval != 0); 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate for (;;) { 13407c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 13417c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate state.ls_donefirst = B_FALSE; 13447c478bd9Sstevel@tonic-gate if (link == NULL) 13457c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link_stats, &state); 13467c478bd9Sstevel@tonic-gate else 13477c478bd9Sstevel@tonic-gate show_link_stats(&state, link); 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate if (interval == 0) 13507c478bd9Sstevel@tonic-gate break; 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate (void) sleep(interval); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13577c478bd9Sstevel@tonic-gate static void 135833343a97Smeem aggr_stats(uint32_t key, uint_t interval) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate show_grp_state_t state; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13637c478bd9Sstevel@tonic-gate state.gs_stats = B_TRUE; 13647c478bd9Sstevel@tonic-gate state.gs_key = key; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13687c478bd9Sstevel@tonic-gate * only for the first group. 13697c478bd9Sstevel@tonic-gate */ 13707c478bd9Sstevel@tonic-gate state.gs_firstonly = (interval != 0); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate for (;;) { 13737c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 1374f595a68aSyz147064 (void) dladm_aggr_walk(show_key, &state); 137533343a97Smeem if (state.gs_key != 0 && !state.gs_found) 137633343a97Smeem die("non-existent aggregation key '%u'", key); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate if (interval == 0) 13797c478bd9Sstevel@tonic-gate break; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate (void) sleep(interval); 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13867c478bd9Sstevel@tonic-gate static void 13877c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval) 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate show_mac_state_t state; 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13957c478bd9Sstevel@tonic-gate * only for the first MAC port. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate state.ms_firstonly = (interval != 0); 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate for (;;) { 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 14027c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate state.ms_donefirst = B_FALSE; 1405210db224Sericheng if (dev == NULL) 1406f595a68aSyz147064 (void) dladm_mac_walk(show_dev_stats, &state); 1407210db224Sericheng else 1408210db224Sericheng show_dev_stats(&state, dev); 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (interval == 0) 14117c478bd9Sstevel@tonic-gate break; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate (void) sleep(interval); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */ 14187c478bd9Sstevel@tonic-gate static void 14197c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate s1->ipackets += (s2->ipackets - s3->ipackets); 14227c478bd9Sstevel@tonic-gate s1->opackets += (s2->opackets - s3->opackets); 14237c478bd9Sstevel@tonic-gate s1->rbytes += (s2->rbytes - s3->rbytes); 14247c478bd9Sstevel@tonic-gate s1->obytes += (s2->obytes - s3->obytes); 14257c478bd9Sstevel@tonic-gate s1->ierrors += (s2->ierrors - s3->ierrors); 14267c478bd9Sstevel@tonic-gate s1->oerrors += (s2->oerrors - s3->oerrors); 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */ 14307c478bd9Sstevel@tonic-gate static void 14317c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate s1->ipackets = s2->ipackets - s3->ipackets; 14347c478bd9Sstevel@tonic-gate s1->opackets = s2->opackets - s3->opackets; 14357c478bd9Sstevel@tonic-gate s1->rbytes = s2->rbytes - s3->rbytes; 14367c478bd9Sstevel@tonic-gate s1->obytes = s2->obytes - s3->obytes; 14377c478bd9Sstevel@tonic-gate s1->ierrors = s2->ierrors - s3->ierrors; 14387c478bd9Sstevel@tonic-gate s1->oerrors = s2->oerrors - s3->oerrors; 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate 1441cd93090eSericheng /* 1442ba2e4443Sseb * In the following routines, we do the first kstat_lookup() assuming that 1443ba2e4443Sseb * the device is gldv3-based and that the kstat name is the one passed in 1444ba2e4443Sseb * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1445ba2e4443Sseb * omitting the kstat name. This second lookup is needed for getting kstats 1446ba2e4443Sseb * from legacy devices. This can fail too if the device is not attached or 1447ba2e4443Sseb * the device is legacy and doesn't export the kstats we need. 1448cd93090eSericheng */ 14497c478bd9Sstevel@tonic-gate static void 14507c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats) 14517c478bd9Sstevel@tonic-gate { 14527c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 14537c478bd9Sstevel@tonic-gate kstat_t *ksp; 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 145633343a97Smeem warn("kstat open operation failed"); 14577c478bd9Sstevel@tonic-gate return; 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 1460cd93090eSericheng if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1461ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 14647c478bd9Sstevel@tonic-gate * driver was already detached. 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 14677c478bd9Sstevel@tonic-gate return; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) 14717c478bd9Sstevel@tonic-gate goto bail; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 14747c478bd9Sstevel@tonic-gate &stats->ipackets) < 0) 14757c478bd9Sstevel@tonic-gate goto bail; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 14787c478bd9Sstevel@tonic-gate &stats->opackets) < 0) 14797c478bd9Sstevel@tonic-gate goto bail; 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 14827c478bd9Sstevel@tonic-gate &stats->rbytes) < 0) 14837c478bd9Sstevel@tonic-gate goto bail; 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 14867c478bd9Sstevel@tonic-gate &stats->obytes) < 0) 14877c478bd9Sstevel@tonic-gate goto bail; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 14907c478bd9Sstevel@tonic-gate &stats->ierrors) < 0) 14917c478bd9Sstevel@tonic-gate goto bail; 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 14947c478bd9Sstevel@tonic-gate &stats->oerrors) < 0) 14957c478bd9Sstevel@tonic-gate goto bail; 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 14987c478bd9Sstevel@tonic-gate return; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate bail: 15017c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate static void 1505ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats) 15067c478bd9Sstevel@tonic-gate { 1507c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1508c7e4935fSss150715 uint_t instance; 15097c478bd9Sstevel@tonic-gate 1510c7e4935fSss150715 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 1511ba2e4443Sseb return; 15127c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1513ba2e4443Sseb get_stats(module, instance, "mac", stats); 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate static void 15177c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 15187c478bd9Sstevel@tonic-gate { 1519c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1520c7e4935fSss150715 uint_t instance; 1521ba2e4443Sseb 1522c7e4935fSss150715 if (dlpi_parselink(link, module, &instance) != DLPI_SUCCESS) 1523ba2e4443Sseb return; 15247c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1525ba2e4443Sseb get_stats(module, instance, (char *)link, stats); 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate 1528ba2e4443Sseb static int 1529ba2e4443Sseb get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1530ba2e4443Sseb void *val) 15317c478bd9Sstevel@tonic-gate { 1532c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1533c7e4935fSss150715 uint_t instance; 15347c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 15357c478bd9Sstevel@tonic-gate kstat_t *ksp; 15367c478bd9Sstevel@tonic-gate 1537c7e4935fSss150715 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 1538c7e4935fSss150715 return (-1); 1539c7e4935fSss150715 15407c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 154133343a97Smeem warn("kstat open operation failed"); 1542ba2e4443Sseb return (-1); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate 1545ba2e4443Sseb if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1546ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 15477c478bd9Sstevel@tonic-gate /* 15487c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 15497c478bd9Sstevel@tonic-gate * driver was already detached. 15507c478bd9Sstevel@tonic-gate */ 15517c478bd9Sstevel@tonic-gate goto bail; 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 155533343a97Smeem warn("kstat read failed"); 15567c478bd9Sstevel@tonic-gate goto bail; 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 1559ba2e4443Sseb if (kstat_value(ksp, name, type, val) < 0) 15607c478bd9Sstevel@tonic-gate goto bail; 1561ba2e4443Sseb 1562ba2e4443Sseb (void) kstat_close(kcp); 1563ba2e4443Sseb return (0); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate bail: 15667c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 1567ba2e4443Sseb return (-1); 1568ba2e4443Sseb } 1569ba2e4443Sseb 1570ba2e4443Sseb static uint64_t 1571ba2e4443Sseb mac_ifspeed(const char *dev) 1572ba2e4443Sseb { 1573ba2e4443Sseb uint64_t ifspeed = 0; 1574ba2e4443Sseb 1575ba2e4443Sseb (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 15767c478bd9Sstevel@tonic-gate return (ifspeed); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 1579f595a68aSyz147064 static const char * 1580*3a62633bSyz147064 mac_link_state(const char *dev, char *buf) 15817c478bd9Sstevel@tonic-gate { 15827c478bd9Sstevel@tonic-gate link_state_t link_state; 15837c478bd9Sstevel@tonic-gate 1584ba2e4443Sseb if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1585ba2e4443Sseb &link_state) != 0) { 1586*3a62633bSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 1587*3a62633bSyz147064 return (buf); 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate 1590f595a68aSyz147064 return (dladm_linkstate2str(link_state, buf)); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 1593f595a68aSyz147064 static const char * 1594*3a62633bSyz147064 mac_link_duplex(const char *dev, char *buf) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate link_duplex_t link_duplex; 15977c478bd9Sstevel@tonic-gate 1598ba2e4443Sseb if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1599ba2e4443Sseb &link_duplex) != 0) { 1600*3a62633bSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 1601*3a62633bSyz147064 return (buf); 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 1604f595a68aSyz147064 return (dladm_linkduplex2str(link_duplex, buf)); 16057c478bd9Sstevel@tonic-gate } 16060ba2cbe9Sxc151355 16070ba2cbe9Sxc151355 #define WIFI_CMD_SCAN 0x00000001 16080ba2cbe9Sxc151355 #define WIFI_CMD_SHOW 0x00000002 16090ba2cbe9Sxc151355 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 16100ba2cbe9Sxc151355 typedef struct wifi_field { 16110ba2cbe9Sxc151355 const char *wf_name; 16120ba2cbe9Sxc151355 const char *wf_header; 16130ba2cbe9Sxc151355 uint_t wf_width; 16140ba2cbe9Sxc151355 uint_t wf_mask; 16150ba2cbe9Sxc151355 uint_t wf_cmdtype; 16160ba2cbe9Sxc151355 } wifi_field_t; 16170ba2cbe9Sxc151355 16180ba2cbe9Sxc151355 static wifi_field_t wifi_fields[] = { 16190ba2cbe9Sxc151355 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 1620f595a68aSyz147064 { "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 1621f595a68aSyz147064 { "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 1622f595a68aSyz147064 { "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 1623f595a68aSyz147064 { "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 1624f595a68aSyz147064 { "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 1625f595a68aSyz147064 { "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 1626f595a68aSyz147064 { "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 1627f595a68aSyz147064 { "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 1628f595a68aSyz147064 { "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, 1629f595a68aSyz147064 { "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 16300ba2cbe9Sxc151355 ; 16310ba2cbe9Sxc151355 16320ba2cbe9Sxc151355 static char *all_scan_wifi_fields = 163313994ee8Sxz162242 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 16340ba2cbe9Sxc151355 static char *all_show_wifi_fields = 16350ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 16360ba2cbe9Sxc151355 static char *def_scan_wifi_fields = 16370ba2cbe9Sxc151355 "link,essid,bssid,sec,strength,mode,speed"; 16380ba2cbe9Sxc151355 static char *def_show_wifi_fields = 16390ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed"; 16400ba2cbe9Sxc151355 16410ba2cbe9Sxc151355 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 16420ba2cbe9Sxc151355 #define WIFI_MAX_FIELD_LEN 32 16430ba2cbe9Sxc151355 16440ba2cbe9Sxc151355 typedef struct { 16450ba2cbe9Sxc151355 char *s_buf; 16460ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 16470ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 16480ba2cbe9Sxc151355 } split_t; 16490ba2cbe9Sxc151355 16500ba2cbe9Sxc151355 /* 16510ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 16520ba2cbe9Sxc151355 */ 16530ba2cbe9Sxc151355 static void 16540ba2cbe9Sxc151355 splitfree(split_t *sp) 16550ba2cbe9Sxc151355 { 16560ba2cbe9Sxc151355 free(sp->s_buf); 16570ba2cbe9Sxc151355 free(sp->s_fields); 16580ba2cbe9Sxc151355 free(sp); 16590ba2cbe9Sxc151355 } 16600ba2cbe9Sxc151355 16610ba2cbe9Sxc151355 /* 16620ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 16630ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 16640ba2cbe9Sxc151355 * on failure. 16650ba2cbe9Sxc151355 */ 16660ba2cbe9Sxc151355 static split_t * 16670ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 16680ba2cbe9Sxc151355 { 16690ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 16700ba2cbe9Sxc151355 split_t *sp; 16710ba2cbe9Sxc151355 16720ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 16730ba2cbe9Sxc151355 return (NULL); 16740ba2cbe9Sxc151355 16750ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 16760ba2cbe9Sxc151355 if (sp == NULL) 16770ba2cbe9Sxc151355 return (NULL); 16780ba2cbe9Sxc151355 16790ba2cbe9Sxc151355 sp->s_buf = strdup(str); 16800ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 16810ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 16820ba2cbe9Sxc151355 goto fail; 16830ba2cbe9Sxc151355 16840ba2cbe9Sxc151355 token = sp->s_buf; 16850ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 16860ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 16870ba2cbe9Sxc151355 goto fail; 16880ba2cbe9Sxc151355 token = NULL; 16890ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 16900ba2cbe9Sxc151355 } 16910ba2cbe9Sxc151355 return (sp); 16920ba2cbe9Sxc151355 fail: 16930ba2cbe9Sxc151355 splitfree(sp); 16940ba2cbe9Sxc151355 return (NULL); 16950ba2cbe9Sxc151355 } 16960ba2cbe9Sxc151355 16970ba2cbe9Sxc151355 static int 16980ba2cbe9Sxc151355 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 16990ba2cbe9Sxc151355 uint_t cmdtype) 17000ba2cbe9Sxc151355 { 17010ba2cbe9Sxc151355 uint_t i, j; 17020ba2cbe9Sxc151355 wifi_field_t **wf = NULL; 17030ba2cbe9Sxc151355 split_t *sp; 17040ba2cbe9Sxc151355 boolean_t good_match = B_FALSE; 17050ba2cbe9Sxc151355 17060ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 17070ba2cbe9Sxc151355 if (str == NULL) 17080ba2cbe9Sxc151355 str = def_scan_wifi_fields; 17090ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17100ba2cbe9Sxc151355 str = all_scan_wifi_fields; 17110ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 17120ba2cbe9Sxc151355 if (str == NULL) 17130ba2cbe9Sxc151355 str = def_show_wifi_fields; 17140ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17150ba2cbe9Sxc151355 str = all_show_wifi_fields; 17160ba2cbe9Sxc151355 } else { 17170ba2cbe9Sxc151355 return (-1); 17180ba2cbe9Sxc151355 } 17190ba2cbe9Sxc151355 17200ba2cbe9Sxc151355 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 17210ba2cbe9Sxc151355 if (sp == NULL) 17220ba2cbe9Sxc151355 return (-1); 17230ba2cbe9Sxc151355 17240ba2cbe9Sxc151355 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 17250ba2cbe9Sxc151355 if (wf == NULL) 17260ba2cbe9Sxc151355 goto fail; 17270ba2cbe9Sxc151355 17280ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 17290ba2cbe9Sxc151355 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 17300ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 17310ba2cbe9Sxc151355 wifi_fields[j].wf_name) == 0) { 173213994ee8Sxz162242 good_match = wifi_fields[j]. 17330ba2cbe9Sxc151355 wf_cmdtype & cmdtype; 17340ba2cbe9Sxc151355 break; 17350ba2cbe9Sxc151355 } 17360ba2cbe9Sxc151355 } 17370ba2cbe9Sxc151355 if (!good_match) 17380ba2cbe9Sxc151355 goto fail; 17390ba2cbe9Sxc151355 17400ba2cbe9Sxc151355 good_match = B_FALSE; 17410ba2cbe9Sxc151355 wf[i] = &wifi_fields[j]; 17420ba2cbe9Sxc151355 } 17430ba2cbe9Sxc151355 *countp = i; 17440ba2cbe9Sxc151355 *fields = wf; 17450ba2cbe9Sxc151355 splitfree(sp); 17460ba2cbe9Sxc151355 return (0); 17470ba2cbe9Sxc151355 fail: 17480ba2cbe9Sxc151355 free(wf); 17490ba2cbe9Sxc151355 splitfree(sp); 17500ba2cbe9Sxc151355 return (-1); 17510ba2cbe9Sxc151355 } 17520ba2cbe9Sxc151355 17530ba2cbe9Sxc151355 typedef struct print_wifi_state { 17540ba2cbe9Sxc151355 const char *ws_link; 17550ba2cbe9Sxc151355 boolean_t ws_parseable; 17560ba2cbe9Sxc151355 boolean_t ws_header; 17570ba2cbe9Sxc151355 wifi_field_t **ws_fields; 17580ba2cbe9Sxc151355 uint_t ws_nfields; 17590ba2cbe9Sxc151355 boolean_t ws_lastfield; 17600ba2cbe9Sxc151355 uint_t ws_overflow; 17610ba2cbe9Sxc151355 } print_wifi_state_t; 17620ba2cbe9Sxc151355 17630ba2cbe9Sxc151355 static void 17640ba2cbe9Sxc151355 print_wifi_head(print_wifi_state_t *statep) 17650ba2cbe9Sxc151355 { 17660ba2cbe9Sxc151355 int i; 17670ba2cbe9Sxc151355 wifi_field_t *wfp; 17680ba2cbe9Sxc151355 17690ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 17700ba2cbe9Sxc151355 wfp = statep->ws_fields[i]; 17710ba2cbe9Sxc151355 if (i + 1 < statep->ws_nfields) 17720ba2cbe9Sxc151355 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 17730ba2cbe9Sxc151355 else 17740ba2cbe9Sxc151355 (void) printf("%s", wfp->wf_header); 17750ba2cbe9Sxc151355 } 17760ba2cbe9Sxc151355 (void) printf("\n"); 17770ba2cbe9Sxc151355 } 17780ba2cbe9Sxc151355 17790ba2cbe9Sxc151355 static void 17800ba2cbe9Sxc151355 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 17810ba2cbe9Sxc151355 const char *value) 17820ba2cbe9Sxc151355 { 17830ba2cbe9Sxc151355 uint_t width = wfp->wf_width; 17840ba2cbe9Sxc151355 uint_t valwidth = strlen(value); 17850ba2cbe9Sxc151355 uint_t compress; 17860ba2cbe9Sxc151355 17870ba2cbe9Sxc151355 if (statep->ws_parseable) { 17880ba2cbe9Sxc151355 (void) printf("%s=\"%s\"", wfp->wf_header, value); 17890ba2cbe9Sxc151355 } else { 17900ba2cbe9Sxc151355 if (value[0] == '\0') 17910ba2cbe9Sxc151355 value = "--"; 17920ba2cbe9Sxc151355 if (statep->ws_lastfield) { 17930ba2cbe9Sxc151355 (void) printf("%s", value); 17940ba2cbe9Sxc151355 return; 17950ba2cbe9Sxc151355 } 17960ba2cbe9Sxc151355 17970ba2cbe9Sxc151355 if (valwidth > width) { 17980ba2cbe9Sxc151355 statep->ws_overflow += valwidth - width; 17990ba2cbe9Sxc151355 } else if (valwidth < width && statep->ws_overflow > 0) { 18000ba2cbe9Sxc151355 compress = min(statep->ws_overflow, width - valwidth); 18010ba2cbe9Sxc151355 statep->ws_overflow -= compress; 18020ba2cbe9Sxc151355 width -= compress; 18030ba2cbe9Sxc151355 } 18040ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 18050ba2cbe9Sxc151355 } 18060ba2cbe9Sxc151355 18070ba2cbe9Sxc151355 if (!statep->ws_lastfield) 18080ba2cbe9Sxc151355 (void) putchar(' '); 18090ba2cbe9Sxc151355 } 18100ba2cbe9Sxc151355 18110ba2cbe9Sxc151355 static void 18120ba2cbe9Sxc151355 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 1813f595a68aSyz147064 dladm_wlan_attr_t *attrp) 18140ba2cbe9Sxc151355 { 1815f595a68aSyz147064 char buf[DLADM_STRSIZE]; 18160ba2cbe9Sxc151355 const char *str = ""; 18170ba2cbe9Sxc151355 18180ba2cbe9Sxc151355 if (wfp->wf_mask == 0) { 18190ba2cbe9Sxc151355 print_wifi_field(statep, wfp, statep->ws_link); 18200ba2cbe9Sxc151355 return; 18210ba2cbe9Sxc151355 } 18220ba2cbe9Sxc151355 18230ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 18240ba2cbe9Sxc151355 print_wifi_field(statep, wfp, ""); 18250ba2cbe9Sxc151355 return; 18260ba2cbe9Sxc151355 } 18270ba2cbe9Sxc151355 18280ba2cbe9Sxc151355 switch (wfp->wf_mask) { 1829f595a68aSyz147064 case DLADM_WLAN_ATTR_ESSID: 1830f595a68aSyz147064 str = dladm_wlan_essid2str(&attrp->wa_essid, buf); 18310ba2cbe9Sxc151355 break; 1832f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSID: 1833f595a68aSyz147064 str = dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 18340ba2cbe9Sxc151355 break; 1835f595a68aSyz147064 case DLADM_WLAN_ATTR_SECMODE: 1836f595a68aSyz147064 str = dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 18370ba2cbe9Sxc151355 break; 1838f595a68aSyz147064 case DLADM_WLAN_ATTR_STRENGTH: 1839f595a68aSyz147064 str = dladm_wlan_strength2str(&attrp->wa_strength, buf); 18400ba2cbe9Sxc151355 break; 1841f595a68aSyz147064 case DLADM_WLAN_ATTR_MODE: 1842f595a68aSyz147064 str = dladm_wlan_mode2str(&attrp->wa_mode, buf); 18430ba2cbe9Sxc151355 break; 1844f595a68aSyz147064 case DLADM_WLAN_ATTR_SPEED: 1845f595a68aSyz147064 str = dladm_wlan_speed2str(&attrp->wa_speed, buf); 18460ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 18470ba2cbe9Sxc151355 break; 1848f595a68aSyz147064 case DLADM_WLAN_ATTR_AUTH: 1849f595a68aSyz147064 str = dladm_wlan_auth2str(&attrp->wa_auth, buf); 18500ba2cbe9Sxc151355 break; 1851f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSTYPE: 1852f595a68aSyz147064 str = dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 18530ba2cbe9Sxc151355 break; 18540ba2cbe9Sxc151355 } 18550ba2cbe9Sxc151355 18560ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 18570ba2cbe9Sxc151355 } 18580ba2cbe9Sxc151355 18590ba2cbe9Sxc151355 static boolean_t 1860f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 18610ba2cbe9Sxc151355 { 18620ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 18630ba2cbe9Sxc151355 int i; 18640ba2cbe9Sxc151355 18650ba2cbe9Sxc151355 if (statep->ws_header) { 18660ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 18670ba2cbe9Sxc151355 if (!statep->ws_parseable) 18680ba2cbe9Sxc151355 print_wifi_head(statep); 18690ba2cbe9Sxc151355 } 18700ba2cbe9Sxc151355 18710ba2cbe9Sxc151355 statep->ws_overflow = 0; 18720ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 18730ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 18740ba2cbe9Sxc151355 print_wlan_attr(statep, statep->ws_fields[i], attrp); 18750ba2cbe9Sxc151355 } 18760ba2cbe9Sxc151355 (void) putchar('\n'); 18770ba2cbe9Sxc151355 return (B_TRUE); 18780ba2cbe9Sxc151355 } 18790ba2cbe9Sxc151355 18800ba2cbe9Sxc151355 static boolean_t 18810ba2cbe9Sxc151355 scan_wifi(void *arg, const char *link) 18820ba2cbe9Sxc151355 { 18830ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 1884f595a68aSyz147064 dladm_status_t status; 18850ba2cbe9Sxc151355 18860ba2cbe9Sxc151355 statep->ws_link = link; 1887f595a68aSyz147064 status = dladm_wlan_scan(link, statep, print_scan_results); 1888f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1889f595a68aSyz147064 die_dlerr(status, "cannot scan link '%s'", link); 189033343a97Smeem 18910ba2cbe9Sxc151355 return (B_TRUE); 18920ba2cbe9Sxc151355 } 18930ba2cbe9Sxc151355 18940ba2cbe9Sxc151355 static void 18950ba2cbe9Sxc151355 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 1896f595a68aSyz147064 dladm_wlan_linkattr_t *attrp) 18970ba2cbe9Sxc151355 { 1898f595a68aSyz147064 char buf[DLADM_STRSIZE]; 18990ba2cbe9Sxc151355 const char *str = ""; 19000ba2cbe9Sxc151355 19010ba2cbe9Sxc151355 if (strcmp(wfp->wf_name, "status") == 0) { 19020ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->la_valid) != 0) 1903f595a68aSyz147064 str = dladm_wlan_linkstatus2str(&attrp->la_status, buf); 19040ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 19050ba2cbe9Sxc151355 return; 19060ba2cbe9Sxc151355 } 19070ba2cbe9Sxc151355 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 19080ba2cbe9Sxc151355 } 19090ba2cbe9Sxc151355 19100ba2cbe9Sxc151355 static boolean_t 19110ba2cbe9Sxc151355 show_wifi(void *arg, const char *link) 19120ba2cbe9Sxc151355 { 19130ba2cbe9Sxc151355 int i; 19140ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 1915f595a68aSyz147064 dladm_wlan_linkattr_t attr; 1916f595a68aSyz147064 dladm_status_t status; 19170ba2cbe9Sxc151355 1918f595a68aSyz147064 status = dladm_wlan_get_linkattr(link, &attr); 1919f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1920f595a68aSyz147064 die_dlerr(status, "cannot get link attributes for '%s'", link); 19210ba2cbe9Sxc151355 19220ba2cbe9Sxc151355 if (statep->ws_header) { 19230ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19240ba2cbe9Sxc151355 if (!statep->ws_parseable) 19250ba2cbe9Sxc151355 print_wifi_head(statep); 19260ba2cbe9Sxc151355 } 19270ba2cbe9Sxc151355 19280ba2cbe9Sxc151355 statep->ws_link = link; 19290ba2cbe9Sxc151355 statep->ws_overflow = 0; 19300ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19310ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19320ba2cbe9Sxc151355 print_link_attr(statep, statep->ws_fields[i], &attr); 19330ba2cbe9Sxc151355 } 19340ba2cbe9Sxc151355 (void) putchar('\n'); 19350ba2cbe9Sxc151355 return (B_TRUE); 19360ba2cbe9Sxc151355 } 19370ba2cbe9Sxc151355 19380ba2cbe9Sxc151355 static void 19390ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd) 19400ba2cbe9Sxc151355 { 19410ba2cbe9Sxc151355 int option; 19420ba2cbe9Sxc151355 char *fields_str = NULL; 19430ba2cbe9Sxc151355 wifi_field_t **fields; 19440ba2cbe9Sxc151355 boolean_t (*callback)(void *, const char *); 19450ba2cbe9Sxc151355 uint_t nfields; 19460ba2cbe9Sxc151355 print_wifi_state_t state; 1947f595a68aSyz147064 dladm_status_t status; 19480ba2cbe9Sxc151355 19490ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 19500ba2cbe9Sxc151355 callback = scan_wifi; 19510ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 19520ba2cbe9Sxc151355 callback = show_wifi; 19530ba2cbe9Sxc151355 else 19540ba2cbe9Sxc151355 return; 19550ba2cbe9Sxc151355 19560ba2cbe9Sxc151355 state.ws_link = NULL; 19570ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 19580ba2cbe9Sxc151355 state.ws_header = B_TRUE; 19590ba2cbe9Sxc151355 opterr = 0; 19600ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 19610ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 19620ba2cbe9Sxc151355 switch (option) { 19630ba2cbe9Sxc151355 case 'o': 19640ba2cbe9Sxc151355 fields_str = optarg; 19650ba2cbe9Sxc151355 break; 19660ba2cbe9Sxc151355 case 'p': 19670ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 19680ba2cbe9Sxc151355 if (fields_str == NULL) 19690ba2cbe9Sxc151355 fields_str = "all"; 19700ba2cbe9Sxc151355 break; 19710ba2cbe9Sxc151355 default: 197233343a97Smeem die_opterr(optopt, option); 19730ba2cbe9Sxc151355 break; 19740ba2cbe9Sxc151355 } 19750ba2cbe9Sxc151355 } 19760ba2cbe9Sxc151355 19770ba2cbe9Sxc151355 if (optind == (argc - 1)) 19780ba2cbe9Sxc151355 state.ws_link = argv[optind]; 19790ba2cbe9Sxc151355 else if (optind != argc) 19800ba2cbe9Sxc151355 usage(); 19810ba2cbe9Sxc151355 198233343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 198333343a97Smeem die("invalid field(s) specified"); 198433343a97Smeem 19850ba2cbe9Sxc151355 state.ws_fields = fields; 19860ba2cbe9Sxc151355 state.ws_nfields = nfields; 19870ba2cbe9Sxc151355 19880ba2cbe9Sxc151355 if (state.ws_link == NULL) { 1989f595a68aSyz147064 status = dladm_wlan_walk(&state, callback); 1990f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1991f595a68aSyz147064 die_dlerr(status, "cannot walk wifi links"); 19920ba2cbe9Sxc151355 } else { 19930ba2cbe9Sxc151355 (void) (*callback)(&state, state.ws_link); 19940ba2cbe9Sxc151355 } 19950ba2cbe9Sxc151355 free(fields); 19960ba2cbe9Sxc151355 } 19970ba2cbe9Sxc151355 19980ba2cbe9Sxc151355 static void 19990ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv) 20000ba2cbe9Sxc151355 { 20010ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 20020ba2cbe9Sxc151355 } 20030ba2cbe9Sxc151355 20040ba2cbe9Sxc151355 static void 20050ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv) 20060ba2cbe9Sxc151355 { 20070ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 20080ba2cbe9Sxc151355 } 20090ba2cbe9Sxc151355 20100ba2cbe9Sxc151355 typedef struct wlan_count_attr { 20110ba2cbe9Sxc151355 uint_t wc_count; 20120ba2cbe9Sxc151355 const char *wc_link; 20130ba2cbe9Sxc151355 } wlan_count_attr_t; 20140ba2cbe9Sxc151355 20150ba2cbe9Sxc151355 static boolean_t 20160ba2cbe9Sxc151355 do_count_wlan(void *arg, const char *link) 20170ba2cbe9Sxc151355 { 201833343a97Smeem wlan_count_attr_t *cp = arg; 20190ba2cbe9Sxc151355 20200ba2cbe9Sxc151355 if (cp->wc_count == 0) 20210ba2cbe9Sxc151355 cp->wc_link = strdup(link); 20220ba2cbe9Sxc151355 cp->wc_count++; 20230ba2cbe9Sxc151355 return (B_TRUE); 20240ba2cbe9Sxc151355 } 20250ba2cbe9Sxc151355 20260ba2cbe9Sxc151355 static int 2027f595a68aSyz147064 parse_wep_keys(char *str, dladm_wlan_wepkey_t **keys, uint_t *key_countp) 20280ba2cbe9Sxc151355 { 20290ba2cbe9Sxc151355 uint_t i; 20300ba2cbe9Sxc151355 split_t *sp; 2031f595a68aSyz147064 dladm_wlan_wepkey_t *wk; 20320ba2cbe9Sxc151355 2033f595a68aSyz147064 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_WEPKEYNAME_LEN); 20340ba2cbe9Sxc151355 if (sp == NULL) 20350ba2cbe9Sxc151355 return (-1); 20360ba2cbe9Sxc151355 2037f595a68aSyz147064 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_wepkey_t)); 20380ba2cbe9Sxc151355 if (wk == NULL) 20390ba2cbe9Sxc151355 goto fail; 20400ba2cbe9Sxc151355 20410ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 20420ba2cbe9Sxc151355 char *s; 20430ba2cbe9Sxc151355 dladm_secobj_class_t class; 20440ba2cbe9Sxc151355 dladm_status_t status; 20450ba2cbe9Sxc151355 20460ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 2047f595a68aSyz147064 DLADM_WLAN_MAX_WEPKEYNAME_LEN); 20480ba2cbe9Sxc151355 20490ba2cbe9Sxc151355 wk[i].wk_idx = 1; 20500ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 20510ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 20520ba2cbe9Sxc151355 goto fail; 20530ba2cbe9Sxc151355 20540ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 20550ba2cbe9Sxc151355 *s = '\0'; 20560ba2cbe9Sxc151355 } 2057f595a68aSyz147064 wk[i].wk_len = DLADM_WLAN_MAX_WEPKEY_LEN; 20580ba2cbe9Sxc151355 20590ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 20600ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 20610ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 20620ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 20630ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 20640ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 20650ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 20660ba2cbe9Sxc151355 } 20670ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 20680ba2cbe9Sxc151355 goto fail; 20690ba2cbe9Sxc151355 } 20700ba2cbe9Sxc151355 } 20710ba2cbe9Sxc151355 *keys = wk; 20720ba2cbe9Sxc151355 *key_countp = i; 20730ba2cbe9Sxc151355 splitfree(sp); 20740ba2cbe9Sxc151355 return (0); 20750ba2cbe9Sxc151355 fail: 20760ba2cbe9Sxc151355 free(wk); 20770ba2cbe9Sxc151355 splitfree(sp); 20780ba2cbe9Sxc151355 return (-1); 20790ba2cbe9Sxc151355 } 20800ba2cbe9Sxc151355 20810ba2cbe9Sxc151355 static void 20820ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv) 20830ba2cbe9Sxc151355 { 20840ba2cbe9Sxc151355 int option; 2085f595a68aSyz147064 dladm_wlan_attr_t attr, *attrp; 2086f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_OK; 2087f595a68aSyz147064 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 20880ba2cbe9Sxc151355 const char *link = NULL; 2089f595a68aSyz147064 dladm_wlan_wepkey_t *keys = NULL; 20900ba2cbe9Sxc151355 uint_t key_count = 0; 20910ba2cbe9Sxc151355 uint_t flags = 0; 2092f595a68aSyz147064 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 20930ba2cbe9Sxc151355 20940ba2cbe9Sxc151355 opterr = 0; 20950ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 20960ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 20970ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 20980ba2cbe9Sxc151355 switch (option) { 20990ba2cbe9Sxc151355 case 'e': 2100f595a68aSyz147064 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 2101f595a68aSyz147064 if (status != DLADM_STATUS_OK) 210233343a97Smeem die("invalid ESSID '%s'", optarg); 210333343a97Smeem 2104f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 21050ba2cbe9Sxc151355 /* 21060ba2cbe9Sxc151355 * Try to connect without doing a scan. 21070ba2cbe9Sxc151355 */ 2108f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_NOSCAN; 21090ba2cbe9Sxc151355 break; 21100ba2cbe9Sxc151355 case 'i': 2111f595a68aSyz147064 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 2112f595a68aSyz147064 if (status != DLADM_STATUS_OK) 211333343a97Smeem die("invalid BSSID %s", optarg); 211433343a97Smeem 2115f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 21160ba2cbe9Sxc151355 break; 21170ba2cbe9Sxc151355 case 'a': 2118f595a68aSyz147064 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 2119f595a68aSyz147064 if (status != DLADM_STATUS_OK) 212033343a97Smeem die("invalid authentication mode '%s'", optarg); 212133343a97Smeem 2122f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 21230ba2cbe9Sxc151355 break; 21240ba2cbe9Sxc151355 case 'm': 2125f595a68aSyz147064 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 2126f595a68aSyz147064 if (status != DLADM_STATUS_OK) 212733343a97Smeem die("invalid mode '%s'", optarg); 212833343a97Smeem 2129f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 21300ba2cbe9Sxc151355 break; 21310ba2cbe9Sxc151355 case 'b': 2132f595a68aSyz147064 if ((status = dladm_wlan_str2bsstype(optarg, 2133f595a68aSyz147064 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 213433343a97Smeem die("invalid bsstype '%s'", optarg); 2135f595a68aSyz147064 } 213633343a97Smeem 2137f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 21380ba2cbe9Sxc151355 break; 21390ba2cbe9Sxc151355 case 's': 2140f595a68aSyz147064 if ((status = dladm_wlan_str2secmode(optarg, 2141f595a68aSyz147064 &attr.wa_secmode)) != DLADM_STATUS_OK) { 214233343a97Smeem die("invalid security mode '%s'", optarg); 2143f595a68aSyz147064 } 214433343a97Smeem 2145f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 21460ba2cbe9Sxc151355 break; 21470ba2cbe9Sxc151355 case 'k': 214833343a97Smeem if (parse_wep_keys(optarg, &keys, &key_count) < 0) 214933343a97Smeem die("invalid key(s) '%s'", optarg); 215033343a97Smeem 2151f595a68aSyz147064 keysecmode = DLADM_WLAN_SECMODE_WEP; 21520ba2cbe9Sxc151355 break; 21530ba2cbe9Sxc151355 case 'T': 21540ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 21550ba2cbe9Sxc151355 timeout = -1; 21560ba2cbe9Sxc151355 break; 21570ba2cbe9Sxc151355 } 215833343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 215933343a97Smeem die("invalid timeout value '%s'", optarg); 21600ba2cbe9Sxc151355 break; 21610ba2cbe9Sxc151355 case 'c': 2162f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 21630ba2cbe9Sxc151355 break; 21640ba2cbe9Sxc151355 default: 216533343a97Smeem die_opterr(optopt, option); 21660ba2cbe9Sxc151355 break; 21670ba2cbe9Sxc151355 } 21680ba2cbe9Sxc151355 } 21690ba2cbe9Sxc151355 2170f595a68aSyz147064 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 2171f595a68aSyz147064 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 2172f595a68aSyz147064 attr.wa_secmode == DLADM_WLAN_SECMODE_WEP) 217333343a97Smeem die("key required for security mode 'wep'"); 21740ba2cbe9Sxc151355 } else { 2175f595a68aSyz147064 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 217633343a97Smeem attr.wa_secmode != keysecmode) 217733343a97Smeem die("incompatible -s and -k options"); 21780ba2cbe9Sxc151355 } 21790ba2cbe9Sxc151355 attr.wa_secmode = keysecmode; 2180f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 21810ba2cbe9Sxc151355 21820ba2cbe9Sxc151355 if (optind == (argc - 1)) 21830ba2cbe9Sxc151355 link = argv[optind]; 21840ba2cbe9Sxc151355 else if (optind != argc) 21850ba2cbe9Sxc151355 usage(); 21860ba2cbe9Sxc151355 21870ba2cbe9Sxc151355 if (link == NULL) { 21880ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 21890ba2cbe9Sxc151355 21900ba2cbe9Sxc151355 wcattr.wc_link = NULL; 21910ba2cbe9Sxc151355 wcattr.wc_count = 0; 2192f595a68aSyz147064 (void) dladm_wlan_walk(&wcattr, do_count_wlan); 21930ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 219433343a97Smeem die("no wifi links are available"); 21950ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 219633343a97Smeem die("link name is required when more than one wifi " 219733343a97Smeem "link is available"); 21980ba2cbe9Sxc151355 } 21990ba2cbe9Sxc151355 link = wcattr.wc_link; 22000ba2cbe9Sxc151355 } 22010ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 220233343a97Smeem again: 2203f595a68aSyz147064 if ((status = dladm_wlan_connect(link, attrp, timeout, keys, 2204f595a68aSyz147064 key_count, flags)) != DLADM_STATUS_OK) { 2205f595a68aSyz147064 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 22060ba2cbe9Sxc151355 /* 220733343a97Smeem * Try again with scanning and filtering. 22080ba2cbe9Sxc151355 */ 2209f595a68aSyz147064 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 221033343a97Smeem goto again; 22110ba2cbe9Sxc151355 } 221233343a97Smeem 2213f595a68aSyz147064 if (status == DLADM_STATUS_NOTFOUND) { 22140ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 221533343a97Smeem die("no wifi networks are available"); 22160ba2cbe9Sxc151355 } else { 221733343a97Smeem die("no wifi networks with the specified " 221833343a97Smeem "criteria are available"); 22190ba2cbe9Sxc151355 } 22200ba2cbe9Sxc151355 } 2221f595a68aSyz147064 die_dlerr(status, "cannot connect link '%s'", link); 22220ba2cbe9Sxc151355 } 22230ba2cbe9Sxc151355 free(keys); 22240ba2cbe9Sxc151355 } 22250ba2cbe9Sxc151355 22260ba2cbe9Sxc151355 /* ARGSUSED */ 22270ba2cbe9Sxc151355 static boolean_t 22280ba2cbe9Sxc151355 do_all_disconnect_wifi(void *arg, const char *link) 22290ba2cbe9Sxc151355 { 2230f595a68aSyz147064 dladm_status_t status; 22310ba2cbe9Sxc151355 2232f595a68aSyz147064 status = dladm_wlan_disconnect(link); 2233f595a68aSyz147064 if (status != DLADM_STATUS_OK) 2234f595a68aSyz147064 warn_dlerr(status, "cannot disconnect link '%s'", link); 223533343a97Smeem 22360ba2cbe9Sxc151355 return (B_TRUE); 22370ba2cbe9Sxc151355 } 22380ba2cbe9Sxc151355 22390ba2cbe9Sxc151355 static void 22400ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv) 22410ba2cbe9Sxc151355 { 22420ba2cbe9Sxc151355 int option; 22430ba2cbe9Sxc151355 const char *link = NULL; 22440ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 2245f595a68aSyz147064 dladm_status_t status; 22460ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22470ba2cbe9Sxc151355 22480ba2cbe9Sxc151355 opterr = 0; 22490ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 22500ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 22510ba2cbe9Sxc151355 switch (option) { 22520ba2cbe9Sxc151355 case 'a': 22530ba2cbe9Sxc151355 all_links = B_TRUE; 22540ba2cbe9Sxc151355 break; 22550ba2cbe9Sxc151355 default: 225633343a97Smeem die_opterr(optopt, option); 22570ba2cbe9Sxc151355 break; 22580ba2cbe9Sxc151355 } 22590ba2cbe9Sxc151355 } 22600ba2cbe9Sxc151355 22610ba2cbe9Sxc151355 if (optind == (argc - 1)) 22620ba2cbe9Sxc151355 link = argv[optind]; 22630ba2cbe9Sxc151355 else if (optind != argc) 22640ba2cbe9Sxc151355 usage(); 22650ba2cbe9Sxc151355 22660ba2cbe9Sxc151355 if (link == NULL) { 22670ba2cbe9Sxc151355 if (!all_links) { 22680ba2cbe9Sxc151355 wcattr.wc_link = NULL; 22690ba2cbe9Sxc151355 wcattr.wc_count = 0; 2270f595a68aSyz147064 (void) dladm_wlan_walk(&wcattr, do_count_wlan); 22710ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 227233343a97Smeem die("no wifi links are available"); 22730ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 227433343a97Smeem die("link name is required when more than " 227533343a97Smeem "one wifi link is available"); 22760ba2cbe9Sxc151355 } 22770ba2cbe9Sxc151355 link = wcattr.wc_link; 22780ba2cbe9Sxc151355 } else { 2279f595a68aSyz147064 (void) dladm_wlan_walk(&all_links, 2280f595a68aSyz147064 do_all_disconnect_wifi); 22810ba2cbe9Sxc151355 return; 22820ba2cbe9Sxc151355 } 22830ba2cbe9Sxc151355 } 2284f595a68aSyz147064 status = dladm_wlan_disconnect(link); 2285f595a68aSyz147064 if (status != DLADM_STATUS_OK) 2286f595a68aSyz147064 die_dlerr(status, "cannot disconnect link '%s'", link); 22870ba2cbe9Sxc151355 } 22880ba2cbe9Sxc151355 22890ba2cbe9Sxc151355 #define MAX_PROPS 32 22900ba2cbe9Sxc151355 #define MAX_PROP_VALS 32 22910ba2cbe9Sxc151355 #define MAX_PROP_LINE 512 22920ba2cbe9Sxc151355 22930ba2cbe9Sxc151355 typedef struct prop_info { 22940ba2cbe9Sxc151355 char *pi_name; 22950ba2cbe9Sxc151355 char *pi_val[MAX_PROP_VALS]; 22960ba2cbe9Sxc151355 uint_t pi_count; 22970ba2cbe9Sxc151355 } prop_info_t; 22980ba2cbe9Sxc151355 22990ba2cbe9Sxc151355 typedef struct prop_list { 23000ba2cbe9Sxc151355 prop_info_t pl_info[MAX_PROPS]; 23010ba2cbe9Sxc151355 uint_t pl_count; 23020ba2cbe9Sxc151355 char *pl_buf; 23030ba2cbe9Sxc151355 } prop_list_t; 23040ba2cbe9Sxc151355 23050ba2cbe9Sxc151355 typedef struct show_linkprop_state { 23060ba2cbe9Sxc151355 const char *ls_link; 23070ba2cbe9Sxc151355 char *ls_line; 23080ba2cbe9Sxc151355 char **ls_propvals; 2309f4b3ec61Sdh155122 prop_list_t *ls_proplist; 2310f595a68aSyz147064 uint32_t ls_parseable : 1, 2311f595a68aSyz147064 ls_persist : 1, 2312f595a68aSyz147064 ls_header : 1, 2313f595a68aSyz147064 ls_pad_bits : 29; 2314f595a68aSyz147064 dladm_status_t ls_status; 23150ba2cbe9Sxc151355 } show_linkprop_state_t; 23160ba2cbe9Sxc151355 23170ba2cbe9Sxc151355 static void 23180ba2cbe9Sxc151355 free_props(prop_list_t *list) 23190ba2cbe9Sxc151355 { 23200ba2cbe9Sxc151355 if (list != NULL) { 23210ba2cbe9Sxc151355 free(list->pl_buf); 23220ba2cbe9Sxc151355 free(list); 23230ba2cbe9Sxc151355 } 23240ba2cbe9Sxc151355 } 23250ba2cbe9Sxc151355 23260ba2cbe9Sxc151355 static int 23270ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 23280ba2cbe9Sxc151355 { 23290ba2cbe9Sxc151355 prop_list_t *list; 23300ba2cbe9Sxc151355 prop_info_t *pip; 23310ba2cbe9Sxc151355 char *buf, *curr; 23320ba2cbe9Sxc151355 int len, i; 23330ba2cbe9Sxc151355 23340ba2cbe9Sxc151355 list = malloc(sizeof (prop_list_t)); 23350ba2cbe9Sxc151355 if (list == NULL) 23360ba2cbe9Sxc151355 return (-1); 23370ba2cbe9Sxc151355 23380ba2cbe9Sxc151355 list->pl_count = 0; 23390ba2cbe9Sxc151355 list->pl_buf = buf = strdup(str); 23400ba2cbe9Sxc151355 if (buf == NULL) 23410ba2cbe9Sxc151355 goto fail; 23420ba2cbe9Sxc151355 23430ba2cbe9Sxc151355 curr = buf; 23440ba2cbe9Sxc151355 len = strlen(buf); 23450ba2cbe9Sxc151355 pip = NULL; 23460ba2cbe9Sxc151355 for (i = 0; i < len; i++) { 23470ba2cbe9Sxc151355 char c = buf[i]; 23480ba2cbe9Sxc151355 boolean_t match = (c == '=' || c == ','); 23490ba2cbe9Sxc151355 23500ba2cbe9Sxc151355 if (!match && i != len - 1) 23510ba2cbe9Sxc151355 continue; 23520ba2cbe9Sxc151355 23530ba2cbe9Sxc151355 if (match) { 23540ba2cbe9Sxc151355 buf[i] = '\0'; 23550ba2cbe9Sxc151355 if (*curr == '\0') 23560ba2cbe9Sxc151355 goto fail; 23570ba2cbe9Sxc151355 } 23580ba2cbe9Sxc151355 23590ba2cbe9Sxc151355 if (pip != NULL && c != '=') { 23600ba2cbe9Sxc151355 if (pip->pi_count > MAX_PROP_VALS) 23610ba2cbe9Sxc151355 goto fail; 23620ba2cbe9Sxc151355 23630ba2cbe9Sxc151355 if (novalues) 23640ba2cbe9Sxc151355 goto fail; 23650ba2cbe9Sxc151355 23660ba2cbe9Sxc151355 pip->pi_val[pip->pi_count] = curr; 23670ba2cbe9Sxc151355 pip->pi_count++; 23680ba2cbe9Sxc151355 } else { 23690ba2cbe9Sxc151355 if (list->pl_count > MAX_PROPS) 23700ba2cbe9Sxc151355 goto fail; 23710ba2cbe9Sxc151355 23720ba2cbe9Sxc151355 pip = &list->pl_info[list->pl_count]; 23730ba2cbe9Sxc151355 pip->pi_name = curr; 23740ba2cbe9Sxc151355 pip->pi_count = 0; 23750ba2cbe9Sxc151355 list->pl_count++; 23760ba2cbe9Sxc151355 if (c == ',') 23770ba2cbe9Sxc151355 pip = NULL; 23780ba2cbe9Sxc151355 } 23790ba2cbe9Sxc151355 curr = buf + i + 1; 23800ba2cbe9Sxc151355 } 23810ba2cbe9Sxc151355 *listp = list; 23820ba2cbe9Sxc151355 return (0); 23830ba2cbe9Sxc151355 23840ba2cbe9Sxc151355 fail: 23850ba2cbe9Sxc151355 free_props(list); 23860ba2cbe9Sxc151355 return (-1); 23870ba2cbe9Sxc151355 } 23880ba2cbe9Sxc151355 23890ba2cbe9Sxc151355 static void 23900ba2cbe9Sxc151355 print_linkprop_head(void) 23910ba2cbe9Sxc151355 { 2392f4b3ec61Sdh155122 (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 2393f4b3ec61Sdh155122 "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 23940ba2cbe9Sxc151355 } 23950ba2cbe9Sxc151355 23960ba2cbe9Sxc151355 static void 23970ba2cbe9Sxc151355 print_linkprop(show_linkprop_state_t *statep, const char *propname, 23980ba2cbe9Sxc151355 dladm_prop_type_t type, const char *typename, const char *format, 23990ba2cbe9Sxc151355 char **pptr) 24000ba2cbe9Sxc151355 { 24010ba2cbe9Sxc151355 int i; 24020ba2cbe9Sxc151355 char *ptr, *lim; 24030ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 24040ba2cbe9Sxc151355 char *unknown = "?", *notsup = ""; 24050ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 24060ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 24070ba2cbe9Sxc151355 dladm_status_t status; 24080ba2cbe9Sxc151355 24090ba2cbe9Sxc151355 status = dladm_get_prop(statep->ls_link, type, propname, 24100ba2cbe9Sxc151355 propvals, &valcnt); 24110ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2412f595a68aSyz147064 if (status == DLADM_STATUS_TEMPONLY) { 2413f595a68aSyz147064 statep->ls_status = status; 2414f595a68aSyz147064 return; 2415f595a68aSyz147064 } else if (status == DLADM_STATUS_NOTSUP || 2416f595a68aSyz147064 statep->ls_persist) { 24170ba2cbe9Sxc151355 valcnt = 1; 24180ba2cbe9Sxc151355 if (type == DLADM_PROP_VAL_CURRENT) 24190ba2cbe9Sxc151355 propvals = &unknown; 24200ba2cbe9Sxc151355 else 24210ba2cbe9Sxc151355 propvals = ¬sup; 24220ba2cbe9Sxc151355 } else { 2423f595a68aSyz147064 statep->ls_status = status; 2424f595a68aSyz147064 warn_dlerr(status, 2425f595a68aSyz147064 "cannot get link property '%s' for %s", 2426f595a68aSyz147064 propname, statep->ls_link); 2427f595a68aSyz147064 return; 24280ba2cbe9Sxc151355 } 24290ba2cbe9Sxc151355 } 24300ba2cbe9Sxc151355 24310ba2cbe9Sxc151355 ptr = buf; 24320ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 24330ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 24340ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 24350ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "--,"); 24360ba2cbe9Sxc151355 else 24370ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 24380ba2cbe9Sxc151355 if (ptr >= lim) 24390ba2cbe9Sxc151355 break; 24400ba2cbe9Sxc151355 } 24410ba2cbe9Sxc151355 if (valcnt > 0) 24420ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 24430ba2cbe9Sxc151355 24440ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 24450ba2cbe9Sxc151355 if (statep->ls_parseable) { 24460ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 24470ba2cbe9Sxc151355 "%s=\"%s\" ", typename, buf); 24480ba2cbe9Sxc151355 } else { 24490ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 24500ba2cbe9Sxc151355 } 24510ba2cbe9Sxc151355 } 24520ba2cbe9Sxc151355 24530ba2cbe9Sxc151355 static boolean_t 24540ba2cbe9Sxc151355 show_linkprop(void *arg, const char *propname) 24550ba2cbe9Sxc151355 { 24560ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 24570ba2cbe9Sxc151355 char *ptr = statep->ls_line; 24580ba2cbe9Sxc151355 char *lim = ptr + MAX_PROP_LINE; 24590ba2cbe9Sxc151355 2460f4b3ec61Sdh155122 if (statep->ls_parseable) 2461f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 2462f4b3ec61Sdh155122 statep->ls_link); 2463f4b3ec61Sdh155122 else 2464f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 2465f4b3ec61Sdh155122 24660ba2cbe9Sxc151355 if (statep->ls_parseable) 24670ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 24680ba2cbe9Sxc151355 else 24690ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 24700ba2cbe9Sxc151355 24710ba2cbe9Sxc151355 print_linkprop(statep, propname, 24720ba2cbe9Sxc151355 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 24730ba2cbe9Sxc151355 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 2474f595a68aSyz147064 2475f595a68aSyz147064 /* 2476f595a68aSyz147064 * If we failed to query the link property, for example, query 2477f595a68aSyz147064 * the persistent value of a non-persistable link property, simply 2478f595a68aSyz147064 * skip the output. 2479f595a68aSyz147064 */ 2480f595a68aSyz147064 if (statep->ls_status != DLADM_STATUS_OK) 2481f595a68aSyz147064 return (B_TRUE); 2482f595a68aSyz147064 24830ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 24840ba2cbe9Sxc151355 "DEFAULT", "%-14s ", &ptr); 2485f595a68aSyz147064 if (statep->ls_status != DLADM_STATUS_OK) 2486f595a68aSyz147064 return (B_TRUE); 2487f595a68aSyz147064 24880ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2489f4b3ec61Sdh155122 "POSSIBLE", "%-20s ", &ptr); 2490f595a68aSyz147064 if (statep->ls_status != DLADM_STATUS_OK) 2491f595a68aSyz147064 return (B_TRUE); 24920ba2cbe9Sxc151355 24930ba2cbe9Sxc151355 if (statep->ls_header) { 24940ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 24950ba2cbe9Sxc151355 if (!statep->ls_parseable) 24960ba2cbe9Sxc151355 print_linkprop_head(); 24970ba2cbe9Sxc151355 } 24980ba2cbe9Sxc151355 (void) printf("%s\n", statep->ls_line); 24990ba2cbe9Sxc151355 return (B_TRUE); 25000ba2cbe9Sxc151355 } 25010ba2cbe9Sxc151355 25020ba2cbe9Sxc151355 static void 25030ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv) 25040ba2cbe9Sxc151355 { 2505f4b3ec61Sdh155122 int option; 25060ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 25070ba2cbe9Sxc151355 show_linkprop_state_t state; 25080ba2cbe9Sxc151355 25090ba2cbe9Sxc151355 opterr = 0; 25100ba2cbe9Sxc151355 state.ls_link = NULL; 25110ba2cbe9Sxc151355 state.ls_propvals = NULL; 25120ba2cbe9Sxc151355 state.ls_line = NULL; 25130ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 25140ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 25150ba2cbe9Sxc151355 state.ls_header = B_TRUE; 25160ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:cP", 25170ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 25180ba2cbe9Sxc151355 switch (option) { 25190ba2cbe9Sxc151355 case 'p': 252033343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 252113994ee8Sxz162242 die("invalid link properties specified"); 25220ba2cbe9Sxc151355 break; 25230ba2cbe9Sxc151355 case 'c': 25240ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 25250ba2cbe9Sxc151355 break; 25260ba2cbe9Sxc151355 case 'P': 25270ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 25280ba2cbe9Sxc151355 break; 25290ba2cbe9Sxc151355 default: 253033343a97Smeem die_opterr(optopt, option); 25310ba2cbe9Sxc151355 break; 25320ba2cbe9Sxc151355 } 25330ba2cbe9Sxc151355 } 25340ba2cbe9Sxc151355 25350ba2cbe9Sxc151355 if (optind == (argc - 1)) 25360ba2cbe9Sxc151355 state.ls_link = argv[optind]; 25370ba2cbe9Sxc151355 else if (optind != argc) 25380ba2cbe9Sxc151355 usage(); 25390ba2cbe9Sxc151355 2540f4b3ec61Sdh155122 state.ls_proplist = proplist; 2541f595a68aSyz147064 state.ls_status = DLADM_STATUS_OK; 2542f4b3ec61Sdh155122 2543f4b3ec61Sdh155122 if (state.ls_link == NULL) { 2544f4b3ec61Sdh155122 (void) dladm_walk(show_linkprop_onelink, &state); 2545f4b3ec61Sdh155122 } else { 2546f4b3ec61Sdh155122 show_linkprop_onelink(&state, state.ls_link); 2547f4b3ec61Sdh155122 } 2548f4b3ec61Sdh155122 free_props(proplist); 2549f595a68aSyz147064 2550f595a68aSyz147064 if (state.ls_status != DLADM_STATUS_OK) 2551f595a68aSyz147064 exit(EXIT_FAILURE); 2552f4b3ec61Sdh155122 } 2553f4b3ec61Sdh155122 2554f4b3ec61Sdh155122 static void 2555f4b3ec61Sdh155122 show_linkprop_onelink(void *arg, const char *link) 2556f4b3ec61Sdh155122 { 2557f4b3ec61Sdh155122 int i, fd; 2558f4b3ec61Sdh155122 char linkname[MAXPATHLEN]; 2559f4b3ec61Sdh155122 char *buf; 2560f4b3ec61Sdh155122 dladm_status_t status; 2561f4b3ec61Sdh155122 prop_list_t *proplist = NULL; 2562f4b3ec61Sdh155122 show_linkprop_state_t *statep; 2563f4b3ec61Sdh155122 const char *savep; 2564f4b3ec61Sdh155122 2565f4b3ec61Sdh155122 statep = (show_linkprop_state_t *)arg; 2566f4b3ec61Sdh155122 savep = statep->ls_link; 2567f4b3ec61Sdh155122 statep->ls_link = link; 2568f4b3ec61Sdh155122 proplist = statep->ls_proplist; 25690ba2cbe9Sxc151355 25700ba2cbe9Sxc151355 /* 25710ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 25720ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 25730ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 25740ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 25750ba2cbe9Sxc151355 */ 2576f4b3ec61Sdh155122 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 2577f595a68aSyz147064 if ((fd = open(linkname, O_RDWR)) < 0) { 2578f595a68aSyz147064 warn("cannot open %s: %s", link, strerror(errno)); 2579f595a68aSyz147064 statep->ls_status = DLADM_STATUS_NOTFOUND; 2580f595a68aSyz147064 return; 2581f595a68aSyz147064 } 25820ba2cbe9Sxc151355 25830ba2cbe9Sxc151355 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 25840ba2cbe9Sxc151355 MAX_PROP_LINE); 258533343a97Smeem if (buf == NULL) 258633343a97Smeem die("insufficient memory"); 258733343a97Smeem 2588f4b3ec61Sdh155122 statep->ls_propvals = (char **)(void *)buf; 25890ba2cbe9Sxc151355 for (i = 0; i < MAX_PROP_VALS; i++) { 2590f4b3ec61Sdh155122 statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 25910ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 25920ba2cbe9Sxc151355 } 2593f4b3ec61Sdh155122 statep->ls_line = buf + 25940ba2cbe9Sxc151355 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 25950ba2cbe9Sxc151355 25960ba2cbe9Sxc151355 if (proplist != NULL) { 2597f595a68aSyz147064 for (i = 0; i < proplist->pl_count; i++) 2598f595a68aSyz147064 (void) show_linkprop(statep, 2599f595a68aSyz147064 proplist->pl_info[i].pi_name); 26000ba2cbe9Sxc151355 } else { 2601f4b3ec61Sdh155122 status = dladm_walk_prop(link, statep, show_linkprop); 260233343a97Smeem if (status != DLADM_STATUS_OK) 2603f595a68aSyz147064 warn_dlerr(status, "show-linkprop failed for %s", link); 26040ba2cbe9Sxc151355 } 26050ba2cbe9Sxc151355 (void) close(fd); 26060ba2cbe9Sxc151355 free(buf); 2607f4b3ec61Sdh155122 statep->ls_link = savep; 26080ba2cbe9Sxc151355 } 26090ba2cbe9Sxc151355 26100ba2cbe9Sxc151355 static dladm_status_t 26110ba2cbe9Sxc151355 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 26120ba2cbe9Sxc151355 uint_t val_cnt, boolean_t reset) 26130ba2cbe9Sxc151355 { 26140ba2cbe9Sxc151355 dladm_status_t status; 2615f4b3ec61Sdh155122 char *errprop; 26160ba2cbe9Sxc151355 26170ba2cbe9Sxc151355 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 2618f4b3ec61Sdh155122 DLADM_OPT_PERSIST, &errprop); 26190ba2cbe9Sxc151355 26200ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 26210ba2cbe9Sxc151355 if (reset) { 262233343a97Smeem warn_dlerr(status, "cannot persistently reset link " 2623f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26240ba2cbe9Sxc151355 } else { 262533343a97Smeem warn_dlerr(status, "cannot persistently set link " 2626f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26270ba2cbe9Sxc151355 } 26280ba2cbe9Sxc151355 } 26290ba2cbe9Sxc151355 return (status); 26300ba2cbe9Sxc151355 } 26310ba2cbe9Sxc151355 26320ba2cbe9Sxc151355 static void 26330ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset) 26340ba2cbe9Sxc151355 { 26350ba2cbe9Sxc151355 int i, option; 26360ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 26370ba2cbe9Sxc151355 const char *link = NULL; 26380ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 26390ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 26400ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 26410ba2cbe9Sxc151355 26420ba2cbe9Sxc151355 opterr = 0; 26430ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 26440ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 26450ba2cbe9Sxc151355 switch (option) { 26460ba2cbe9Sxc151355 case 'p': 264733343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 264833343a97Smeem die("invalid link properties specified"); 26490ba2cbe9Sxc151355 break; 26500ba2cbe9Sxc151355 case 't': 26510ba2cbe9Sxc151355 temp = B_TRUE; 26520ba2cbe9Sxc151355 break; 26530ba2cbe9Sxc151355 case 'R': 26540ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 26550ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 265633343a97Smeem die_dlerr(status, "invalid directory " 265733343a97Smeem "specified"); 26580ba2cbe9Sxc151355 } 26590ba2cbe9Sxc151355 break; 26600ba2cbe9Sxc151355 default: 266133343a97Smeem die_opterr(optopt, option); 26620ba2cbe9Sxc151355 break; 26630ba2cbe9Sxc151355 } 26640ba2cbe9Sxc151355 } 26650ba2cbe9Sxc151355 26660ba2cbe9Sxc151355 if (optind == (argc - 1)) 26670ba2cbe9Sxc151355 link = argv[optind]; 26680ba2cbe9Sxc151355 else if (optind != argc) 26690ba2cbe9Sxc151355 usage(); 26700ba2cbe9Sxc151355 267133343a97Smeem if (link == NULL) 267233343a97Smeem die("link name must be specified"); 26730ba2cbe9Sxc151355 2674dbc95d79Sxz162242 if (proplist == NULL) { 2675f4b3ec61Sdh155122 char *errprop; 2676f4b3ec61Sdh155122 2677dbc95d79Sxz162242 if (!reset) 267833343a97Smeem die("link property must be specified"); 267933343a97Smeem 2680f4b3ec61Sdh155122 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP, 2681f4b3ec61Sdh155122 &errprop); 26820ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2683f4b3ec61Sdh155122 warn_dlerr(status, "cannot reset link property '%s' " 2684f4b3ec61Sdh155122 "on '%s'", errprop, link); 26850ba2cbe9Sxc151355 } 26860ba2cbe9Sxc151355 if (!temp) { 268713994ee8Sxz162242 dladm_status_t s; 268813994ee8Sxz162242 268913994ee8Sxz162242 s = set_linkprop_persist(link, NULL, NULL, 0, reset); 269013994ee8Sxz162242 if (s != DLADM_STATUS_OK) 269113994ee8Sxz162242 status = s; 26920ba2cbe9Sxc151355 } 26930ba2cbe9Sxc151355 goto done; 26940ba2cbe9Sxc151355 } 26950ba2cbe9Sxc151355 26960ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 26970ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 26980ba2cbe9Sxc151355 char **val; 26990ba2cbe9Sxc151355 uint_t count; 27000ba2cbe9Sxc151355 dladm_status_t s; 27010ba2cbe9Sxc151355 27020ba2cbe9Sxc151355 if (reset) { 27030ba2cbe9Sxc151355 val = NULL; 27040ba2cbe9Sxc151355 count = 0; 27050ba2cbe9Sxc151355 } else { 27060ba2cbe9Sxc151355 val = pip->pi_val; 27070ba2cbe9Sxc151355 count = pip->pi_count; 27080ba2cbe9Sxc151355 if (count == 0) { 270933343a97Smeem warn("no value specified for '%s'", 271033343a97Smeem pip->pi_name); 27110ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 27120ba2cbe9Sxc151355 continue; 27130ba2cbe9Sxc151355 } 27140ba2cbe9Sxc151355 } 27150ba2cbe9Sxc151355 s = dladm_set_prop(link, pip->pi_name, val, count, 2716f4b3ec61Sdh155122 DLADM_OPT_TEMP, NULL); 27170ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 27180ba2cbe9Sxc151355 if (!temp) { 27190ba2cbe9Sxc151355 s = set_linkprop_persist(link, 27200ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 27210ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 27220ba2cbe9Sxc151355 status = s; 27230ba2cbe9Sxc151355 } 27240ba2cbe9Sxc151355 continue; 27250ba2cbe9Sxc151355 } 27260ba2cbe9Sxc151355 status = s; 27270ba2cbe9Sxc151355 switch (s) { 27280ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 272933343a97Smeem warn("invalid link property '%s'", pip->pi_name); 27300ba2cbe9Sxc151355 break; 27310ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 27320ba2cbe9Sxc151355 int j; 27330ba2cbe9Sxc151355 char *ptr, *lim; 27340ba2cbe9Sxc151355 char **propvals = NULL; 27350ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 27360ba2cbe9Sxc151355 27370ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 27380ba2cbe9Sxc151355 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 27390ba2cbe9Sxc151355 MAX_PROP_LINE); 27400ba2cbe9Sxc151355 27410ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 274233343a97Smeem if (propvals == NULL) 274333343a97Smeem die("insufficient memory"); 274433343a97Smeem 27450ba2cbe9Sxc151355 for (j = 0; j < MAX_PROP_VALS; j++) { 27460ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 27470ba2cbe9Sxc151355 MAX_PROP_VALS + 27480ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 27490ba2cbe9Sxc151355 } 27500ba2cbe9Sxc151355 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 27510ba2cbe9Sxc151355 pip->pi_name, propvals, &valcnt); 27520ba2cbe9Sxc151355 27530ba2cbe9Sxc151355 ptr = errmsg; 27540ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 27550ba2cbe9Sxc151355 *ptr = '\0'; 27560ba2cbe9Sxc151355 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 27570ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 27580ba2cbe9Sxc151355 propvals[j]); 27590ba2cbe9Sxc151355 if (ptr >= lim) 27600ba2cbe9Sxc151355 break; 27610ba2cbe9Sxc151355 } 2762f4b3ec61Sdh155122 if (ptr > errmsg) { 27630ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 276433343a97Smeem warn("link property '%s' must be one of: %s", 276533343a97Smeem pip->pi_name, errmsg); 2766f4b3ec61Sdh155122 } else 2767f4b3ec61Sdh155122 warn("invalid link property '%s'", *val); 27680ba2cbe9Sxc151355 free(propvals); 27690ba2cbe9Sxc151355 break; 27700ba2cbe9Sxc151355 } 27710ba2cbe9Sxc151355 default: 27720ba2cbe9Sxc151355 if (reset) { 277333343a97Smeem warn_dlerr(status, "cannot reset link property " 277433343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27750ba2cbe9Sxc151355 } else { 277633343a97Smeem warn_dlerr(status, "cannot set link property " 277733343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27780ba2cbe9Sxc151355 } 27790ba2cbe9Sxc151355 break; 27800ba2cbe9Sxc151355 } 27810ba2cbe9Sxc151355 } 27820ba2cbe9Sxc151355 done: 27830ba2cbe9Sxc151355 free_props(proplist); 27840ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 27850ba2cbe9Sxc151355 exit(1); 27860ba2cbe9Sxc151355 } 27870ba2cbe9Sxc151355 27880ba2cbe9Sxc151355 static void 27890ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 27900ba2cbe9Sxc151355 { 27910ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 27920ba2cbe9Sxc151355 } 27930ba2cbe9Sxc151355 27940ba2cbe9Sxc151355 static void 27950ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 27960ba2cbe9Sxc151355 { 27970ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 27980ba2cbe9Sxc151355 } 27990ba2cbe9Sxc151355 28000ba2cbe9Sxc151355 static int 28010ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 28020ba2cbe9Sxc151355 dladm_secobj_class_t class) 28030ba2cbe9Sxc151355 { 28040ba2cbe9Sxc151355 int error = 0; 28050ba2cbe9Sxc151355 28060ba2cbe9Sxc151355 if (class != DLADM_SECOBJ_CLASS_WEP) 28070ba2cbe9Sxc151355 return (ENOENT); 28080ba2cbe9Sxc151355 28090ba2cbe9Sxc151355 switch (len) { 28100ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 28110ba2cbe9Sxc151355 case 13: 28120ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 28130ba2cbe9Sxc151355 *obj_lenp = len; 28140ba2cbe9Sxc151355 break; 28150ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 28160ba2cbe9Sxc151355 case 26: 28170ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 28180ba2cbe9Sxc151355 break; 28190ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 28200ba2cbe9Sxc151355 case 28: 28210ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 28220ba2cbe9Sxc151355 return (EINVAL); 28230ba2cbe9Sxc151355 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 28240ba2cbe9Sxc151355 break; 28250ba2cbe9Sxc151355 default: 28260ba2cbe9Sxc151355 return (EINVAL); 28270ba2cbe9Sxc151355 } 28280ba2cbe9Sxc151355 return (error); 28290ba2cbe9Sxc151355 } 28300ba2cbe9Sxc151355 28310ba2cbe9Sxc151355 /* ARGSUSED */ 28320ba2cbe9Sxc151355 static void 28330ba2cbe9Sxc151355 defersig(int sig) 28340ba2cbe9Sxc151355 { 28350ba2cbe9Sxc151355 signalled = sig; 28360ba2cbe9Sxc151355 } 28370ba2cbe9Sxc151355 28380ba2cbe9Sxc151355 static int 28390ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 28400ba2cbe9Sxc151355 { 28410ba2cbe9Sxc151355 uint_t len = 0; 28420ba2cbe9Sxc151355 int c; 28430ba2cbe9Sxc151355 struct termios stored, current; 28440ba2cbe9Sxc151355 void (*sigfunc)(int); 28450ba2cbe9Sxc151355 28460ba2cbe9Sxc151355 /* 28470ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 28480ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 28490ba2cbe9Sxc151355 */ 28500ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 28510ba2cbe9Sxc151355 (void) fflush(stdin); 28520ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 28530ba2cbe9Sxc151355 current = stored; 28540ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 28550ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 28560ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 28570ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 28580ba2cbe9Sxc151355 again: 28590ba2cbe9Sxc151355 if (try == 1) 28600ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 28610ba2cbe9Sxc151355 else 28620ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 28630ba2cbe9Sxc151355 28640ba2cbe9Sxc151355 (void) fflush(stdout); 28650ba2cbe9Sxc151355 while (signalled == 0) { 28660ba2cbe9Sxc151355 c = getchar(); 28670ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 28680ba2cbe9Sxc151355 if (len != 0) 28690ba2cbe9Sxc151355 break; 28700ba2cbe9Sxc151355 (void) putchar('\n'); 28710ba2cbe9Sxc151355 goto again; 28720ba2cbe9Sxc151355 } 28730ba2cbe9Sxc151355 28740ba2cbe9Sxc151355 buf[len++] = c; 28750ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 28760ba2cbe9Sxc151355 break; 28770ba2cbe9Sxc151355 (void) putchar('*'); 28780ba2cbe9Sxc151355 } 28790ba2cbe9Sxc151355 28800ba2cbe9Sxc151355 (void) putchar('\n'); 28810ba2cbe9Sxc151355 (void) fflush(stdin); 28820ba2cbe9Sxc151355 28830ba2cbe9Sxc151355 /* 28840ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 28850ba2cbe9Sxc151355 */ 28860ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 28870ba2cbe9Sxc151355 28880ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 28890ba2cbe9Sxc151355 if (signalled != 0) 28900ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 28910ba2cbe9Sxc151355 28920ba2cbe9Sxc151355 return (len); 28930ba2cbe9Sxc151355 } 28940ba2cbe9Sxc151355 28950ba2cbe9Sxc151355 static int 28960ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 28970ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 28980ba2cbe9Sxc151355 { 28990ba2cbe9Sxc151355 int rval; 29000ba2cbe9Sxc151355 uint_t len, len2; 29010ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 29020ba2cbe9Sxc151355 29030ba2cbe9Sxc151355 if (filep == NULL) { 29040ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 29050ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 29060ba2cbe9Sxc151355 if (rval == 0) { 29070ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 29080ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 29090ba2cbe9Sxc151355 rval = ENOTSUP; 29100ba2cbe9Sxc151355 } 29110ba2cbe9Sxc151355 return (rval); 29120ba2cbe9Sxc151355 } else { 29130ba2cbe9Sxc151355 for (;;) { 29140ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 29150ba2cbe9Sxc151355 break; 29160ba2cbe9Sxc151355 if (isspace(buf[0])) 29170ba2cbe9Sxc151355 continue; 29180ba2cbe9Sxc151355 29190ba2cbe9Sxc151355 len = strlen(buf); 29200ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 29210ba2cbe9Sxc151355 buf[len - 1] = '\0'; 29220ba2cbe9Sxc151355 len--; 29230ba2cbe9Sxc151355 } 29240ba2cbe9Sxc151355 break; 29250ba2cbe9Sxc151355 } 29260ba2cbe9Sxc151355 (void) fclose(filep); 29270ba2cbe9Sxc151355 } 29280ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 29290ba2cbe9Sxc151355 } 29300ba2cbe9Sxc151355 29310ba2cbe9Sxc151355 static boolean_t 29320ba2cbe9Sxc151355 check_auth(const char *auth) 29330ba2cbe9Sxc151355 { 29340ba2cbe9Sxc151355 struct passwd *pw; 29350ba2cbe9Sxc151355 29360ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 29370ba2cbe9Sxc151355 return (B_FALSE); 29380ba2cbe9Sxc151355 29390ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 29400ba2cbe9Sxc151355 } 29410ba2cbe9Sxc151355 29420ba2cbe9Sxc151355 static void 29430ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 29440ba2cbe9Sxc151355 boolean_t success, boolean_t create) 29450ba2cbe9Sxc151355 { 29460ba2cbe9Sxc151355 adt_session_data_t *ah; 29470ba2cbe9Sxc151355 adt_event_data_t *event; 29480ba2cbe9Sxc151355 au_event_t flag; 29490ba2cbe9Sxc151355 char *errstr; 29500ba2cbe9Sxc151355 29510ba2cbe9Sxc151355 if (create) { 29520ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 29530ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 29540ba2cbe9Sxc151355 } else { 29550ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 29560ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 29570ba2cbe9Sxc151355 } 29580ba2cbe9Sxc151355 295933343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 296033343a97Smeem die("adt_start_session: %s", strerror(errno)); 29610ba2cbe9Sxc151355 296233343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 296333343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 29640ba2cbe9Sxc151355 29650ba2cbe9Sxc151355 /* fill in audit info */ 29660ba2cbe9Sxc151355 if (create) { 29670ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 29680ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 29690ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 29700ba2cbe9Sxc151355 } else { 29710ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 29720ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 29730ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 29740ba2cbe9Sxc151355 } 29750ba2cbe9Sxc151355 29760ba2cbe9Sxc151355 if (success) { 29770ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 297833343a97Smeem die("adt_put_event (%s, success): %s", errstr, 297933343a97Smeem strerror(errno)); 29800ba2cbe9Sxc151355 } 29810ba2cbe9Sxc151355 } else { 29820ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 29830ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 298433343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 298533343a97Smeem strerror(errno)); 29860ba2cbe9Sxc151355 } 29870ba2cbe9Sxc151355 } 29880ba2cbe9Sxc151355 29890ba2cbe9Sxc151355 adt_free_event(event); 29900ba2cbe9Sxc151355 (void) adt_end_session(ah); 29910ba2cbe9Sxc151355 } 29920ba2cbe9Sxc151355 29930ba2cbe9Sxc151355 #define MAX_SECOBJS 32 29940ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 29950ba2cbe9Sxc151355 static void 29960ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 29970ba2cbe9Sxc151355 { 29980ba2cbe9Sxc151355 int option, rval; 29990ba2cbe9Sxc151355 FILE *filep = NULL; 30000ba2cbe9Sxc151355 char *obj_name = NULL; 30010ba2cbe9Sxc151355 char *class_name = NULL; 30020ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 30030ba2cbe9Sxc151355 uint_t obj_len; 30040ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 30050ba2cbe9Sxc151355 dladm_status_t status; 30060ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 30070ba2cbe9Sxc151355 uid_t euid; 30080ba2cbe9Sxc151355 30090ba2cbe9Sxc151355 opterr = 0; 30100ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 30110ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 30120ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 30130ba2cbe9Sxc151355 switch (option) { 30140ba2cbe9Sxc151355 case 'f': 30150ba2cbe9Sxc151355 euid = geteuid(); 30160ba2cbe9Sxc151355 (void) seteuid(getuid()); 30170ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 30180ba2cbe9Sxc151355 if (filep == NULL) { 301933343a97Smeem die("cannot open %s: %s", optarg, 302033343a97Smeem strerror(errno)); 30210ba2cbe9Sxc151355 } 30220ba2cbe9Sxc151355 (void) seteuid(euid); 30230ba2cbe9Sxc151355 break; 30240ba2cbe9Sxc151355 case 'c': 30250ba2cbe9Sxc151355 class_name = optarg; 30260ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 30270ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 302833343a97Smeem die("invalid secure object class '%s', " 302933343a97Smeem "valid values are: wep", optarg); 30300ba2cbe9Sxc151355 } 30310ba2cbe9Sxc151355 break; 30320ba2cbe9Sxc151355 case 't': 30330ba2cbe9Sxc151355 temp = B_TRUE; 30340ba2cbe9Sxc151355 break; 30350ba2cbe9Sxc151355 case 'R': 30360ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30370ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 303833343a97Smeem die_dlerr(status, "invalid directory " 303933343a97Smeem "specified"); 30400ba2cbe9Sxc151355 } 30410ba2cbe9Sxc151355 break; 30420ba2cbe9Sxc151355 default: 304333343a97Smeem die_opterr(optopt, option); 30440ba2cbe9Sxc151355 break; 30450ba2cbe9Sxc151355 } 30460ba2cbe9Sxc151355 } 30470ba2cbe9Sxc151355 30480ba2cbe9Sxc151355 if (optind == (argc - 1)) 30490ba2cbe9Sxc151355 obj_name = argv[optind]; 30500ba2cbe9Sxc151355 else if (optind != argc) 30510ba2cbe9Sxc151355 usage(); 30520ba2cbe9Sxc151355 305333343a97Smeem if (class == -1) 305433343a97Smeem die("secure object class required"); 30550ba2cbe9Sxc151355 305633343a97Smeem if (obj_name == NULL) 305733343a97Smeem die("secure object name required"); 30580ba2cbe9Sxc151355 30590ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 30600ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 306133343a97Smeem if (!success) 306233343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 30630ba2cbe9Sxc151355 306433343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 306533343a97Smeem if (rval != 0) { 30660ba2cbe9Sxc151355 switch (rval) { 30670ba2cbe9Sxc151355 case ENOENT: 306833343a97Smeem die("invalid secure object class"); 30690ba2cbe9Sxc151355 break; 30700ba2cbe9Sxc151355 case EINVAL: 307133343a97Smeem die("invalid secure object value"); 30720ba2cbe9Sxc151355 break; 30730ba2cbe9Sxc151355 case ENOTSUP: 307433343a97Smeem die("verification failed"); 30750ba2cbe9Sxc151355 break; 30760ba2cbe9Sxc151355 default: 307733343a97Smeem die("invalid secure object: %s", strerror(rval)); 30780ba2cbe9Sxc151355 break; 30790ba2cbe9Sxc151355 } 30800ba2cbe9Sxc151355 } 30810ba2cbe9Sxc151355 30820ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30830ba2cbe9Sxc151355 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 30840ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 308533343a97Smeem die_dlerr(status, "could not create secure object '%s'", 308633343a97Smeem obj_name); 30870ba2cbe9Sxc151355 } 30880ba2cbe9Sxc151355 if (temp) 30890ba2cbe9Sxc151355 return; 30900ba2cbe9Sxc151355 30910ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30920ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 30930ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 309433343a97Smeem warn_dlerr(status, "could not persistently create secure " 309533343a97Smeem "object '%s'", obj_name); 30960ba2cbe9Sxc151355 } 30970ba2cbe9Sxc151355 } 30980ba2cbe9Sxc151355 30990ba2cbe9Sxc151355 static void 31000ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 31010ba2cbe9Sxc151355 { 31020ba2cbe9Sxc151355 int i, option; 31030ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 31040ba2cbe9Sxc151355 split_t *sp = NULL; 31050ba2cbe9Sxc151355 boolean_t success; 31060ba2cbe9Sxc151355 dladm_status_t status, pstatus; 31070ba2cbe9Sxc151355 31080ba2cbe9Sxc151355 opterr = 0; 31090ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 311033343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 31110ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 31120ba2cbe9Sxc151355 switch (option) { 31130ba2cbe9Sxc151355 case 't': 31140ba2cbe9Sxc151355 temp = B_TRUE; 31150ba2cbe9Sxc151355 break; 31160ba2cbe9Sxc151355 case 'R': 31170ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 31180ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 311933343a97Smeem die_dlerr(status, "invalid directory " 312033343a97Smeem "specified"); 31210ba2cbe9Sxc151355 } 31220ba2cbe9Sxc151355 break; 31230ba2cbe9Sxc151355 default: 312433343a97Smeem die_opterr(optopt, option); 31250ba2cbe9Sxc151355 break; 31260ba2cbe9Sxc151355 } 31270ba2cbe9Sxc151355 } 31280ba2cbe9Sxc151355 31290ba2cbe9Sxc151355 if (optind == (argc - 1)) { 31300ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 31310ba2cbe9Sxc151355 if (sp == NULL) { 313233343a97Smeem die("invalid secure object name(s): '%s'", 313333343a97Smeem argv[optind]); 31340ba2cbe9Sxc151355 } 31350ba2cbe9Sxc151355 } else if (optind != argc) 31360ba2cbe9Sxc151355 usage(); 31370ba2cbe9Sxc151355 313833343a97Smeem if (sp == NULL || sp->s_nfields < 1) 313933343a97Smeem die("secure object name required"); 31400ba2cbe9Sxc151355 31410ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 31420ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 314333343a97Smeem if (!success) 314433343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 31450ba2cbe9Sxc151355 31460ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 31470ba2cbe9Sxc151355 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 31480ba2cbe9Sxc151355 if (!temp) { 31490ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 31500ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31510ba2cbe9Sxc151355 } else { 31520ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 31530ba2cbe9Sxc151355 } 31540ba2cbe9Sxc151355 31550ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 315633343a97Smeem warn_dlerr(status, "could not delete secure object " 315733343a97Smeem "'%s'", sp->s_fields[i]); 31580ba2cbe9Sxc151355 } 31590ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 316033343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 316133343a97Smeem "secure object '%s'", sp->s_fields[i]); 31620ba2cbe9Sxc151355 } 31630ba2cbe9Sxc151355 } 31640ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 31650ba2cbe9Sxc151355 exit(1); 31660ba2cbe9Sxc151355 } 31670ba2cbe9Sxc151355 31680ba2cbe9Sxc151355 typedef struct show_secobj_state { 31690ba2cbe9Sxc151355 boolean_t ss_persist; 31700ba2cbe9Sxc151355 boolean_t ss_parseable; 31710ba2cbe9Sxc151355 boolean_t ss_debug; 31720ba2cbe9Sxc151355 boolean_t ss_header; 31730ba2cbe9Sxc151355 } show_secobj_state_t; 31740ba2cbe9Sxc151355 31750ba2cbe9Sxc151355 static void 31760ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep) 31770ba2cbe9Sxc151355 { 31780ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 31790ba2cbe9Sxc151355 if (statep->ss_debug) 31800ba2cbe9Sxc151355 (void) printf("%-30s", "VALUE"); 31810ba2cbe9Sxc151355 (void) putchar('\n'); 31820ba2cbe9Sxc151355 } 31830ba2cbe9Sxc151355 31840ba2cbe9Sxc151355 static boolean_t 31850ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 31860ba2cbe9Sxc151355 { 31870ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 31880ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 31890ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 31900ba2cbe9Sxc151355 uint_t flags = 0; 31910ba2cbe9Sxc151355 dladm_secobj_class_t class; 31920ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 31930ba2cbe9Sxc151355 dladm_status_t status; 31940ba2cbe9Sxc151355 31950ba2cbe9Sxc151355 if (statep->ss_persist) 31960ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 31970ba2cbe9Sxc151355 31980ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 319933343a97Smeem if (status != DLADM_STATUS_OK) 320033343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 32010ba2cbe9Sxc151355 32020ba2cbe9Sxc151355 if (statep->ss_header) { 32030ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 32040ba2cbe9Sxc151355 if (!statep->ss_parseable) 32050ba2cbe9Sxc151355 print_secobj_head(statep); 32060ba2cbe9Sxc151355 } 32070ba2cbe9Sxc151355 32080ba2cbe9Sxc151355 if (statep->ss_parseable) { 32090ba2cbe9Sxc151355 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 32100ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32110ba2cbe9Sxc151355 } else { 32120ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", obj_name, 32130ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32140ba2cbe9Sxc151355 } 32150ba2cbe9Sxc151355 32160ba2cbe9Sxc151355 if (statep->ss_debug) { 32170ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 32180ba2cbe9Sxc151355 uint_t len = sizeof (val); 32190ba2cbe9Sxc151355 32200ba2cbe9Sxc151355 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 32210ba2cbe9Sxc151355 if (statep->ss_parseable) 32220ba2cbe9Sxc151355 (void) printf("VALUE=\"0x%s\"", val); 32230ba2cbe9Sxc151355 else 32240ba2cbe9Sxc151355 (void) printf("0x%-30s", val); 32250ba2cbe9Sxc151355 } 32260ba2cbe9Sxc151355 } 32270ba2cbe9Sxc151355 (void) putchar('\n'); 32280ba2cbe9Sxc151355 return (B_TRUE); 32290ba2cbe9Sxc151355 } 32300ba2cbe9Sxc151355 32310ba2cbe9Sxc151355 static void 32320ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 32330ba2cbe9Sxc151355 { 32340ba2cbe9Sxc151355 int option; 32350ba2cbe9Sxc151355 show_secobj_state_t state; 32360ba2cbe9Sxc151355 dladm_status_t status; 32370ba2cbe9Sxc151355 uint_t i; 32380ba2cbe9Sxc151355 split_t *sp; 32390ba2cbe9Sxc151355 uint_t flags; 32400ba2cbe9Sxc151355 32410ba2cbe9Sxc151355 opterr = 0; 32420ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 32430ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 32440ba2cbe9Sxc151355 state.ss_debug = B_FALSE; 32450ba2cbe9Sxc151355 state.ss_header = B_TRUE; 32460ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":pPd", 32470ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 32480ba2cbe9Sxc151355 switch (option) { 32490ba2cbe9Sxc151355 case 'p': 32500ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 32510ba2cbe9Sxc151355 break; 32520ba2cbe9Sxc151355 case 'P': 32530ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 32540ba2cbe9Sxc151355 break; 32550ba2cbe9Sxc151355 case 'd': 325633343a97Smeem if (getuid() != 0) 325733343a97Smeem die("insufficient privileges"); 32580ba2cbe9Sxc151355 state.ss_debug = B_TRUE; 32590ba2cbe9Sxc151355 break; 32600ba2cbe9Sxc151355 default: 326133343a97Smeem die_opterr(optopt, option); 32620ba2cbe9Sxc151355 break; 32630ba2cbe9Sxc151355 } 32640ba2cbe9Sxc151355 } 32650ba2cbe9Sxc151355 32660ba2cbe9Sxc151355 if (optind == (argc - 1)) { 32670ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 32680ba2cbe9Sxc151355 if (sp == NULL) { 326933343a97Smeem die("invalid secure object name(s): '%s'", 327033343a97Smeem argv[optind]); 32710ba2cbe9Sxc151355 } 32720ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 32730ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 32740ba2cbe9Sxc151355 break; 32750ba2cbe9Sxc151355 } 32760ba2cbe9Sxc151355 splitfree(sp); 32770ba2cbe9Sxc151355 return; 32780ba2cbe9Sxc151355 } else if (optind != argc) 32790ba2cbe9Sxc151355 usage(); 32800ba2cbe9Sxc151355 32810ba2cbe9Sxc151355 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 32820ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 328333343a97Smeem if (status != DLADM_STATUS_OK) 328433343a97Smeem die_dlerr(status, "show-secobj"); 32850ba2cbe9Sxc151355 } 32860ba2cbe9Sxc151355 32870ba2cbe9Sxc151355 /* ARGSUSED */ 32880ba2cbe9Sxc151355 static void 32890ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 32900ba2cbe9Sxc151355 { 32910ba2cbe9Sxc151355 dladm_status_t status; 32920ba2cbe9Sxc151355 32930ba2cbe9Sxc151355 status = dladm_init_linkprop(); 329433343a97Smeem if (status != DLADM_STATUS_OK) 329533343a97Smeem die_dlerr(status, "link property initialization failed"); 32960ba2cbe9Sxc151355 } 32970ba2cbe9Sxc151355 32980ba2cbe9Sxc151355 /* ARGSUSED */ 32990ba2cbe9Sxc151355 static void 33000ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 33010ba2cbe9Sxc151355 { 33020ba2cbe9Sxc151355 dladm_status_t status; 33030ba2cbe9Sxc151355 33040ba2cbe9Sxc151355 status = dladm_init_secobj(); 330533343a97Smeem if (status != DLADM_STATUS_OK) 330633343a97Smeem die_dlerr(status, "secure object initialization failed"); 330733343a97Smeem } 330833343a97Smeem 330933343a97Smeem static boolean_t 331033343a97Smeem str2int(const char *str, int *valp) 331133343a97Smeem { 331233343a97Smeem int val; 331333343a97Smeem char *endp = NULL; 331433343a97Smeem 331533343a97Smeem errno = 0; 331633343a97Smeem val = strtol(str, &endp, 10); 331733343a97Smeem if (errno != 0 || *endp != '\0') 331833343a97Smeem return (B_FALSE); 331933343a97Smeem 332033343a97Smeem *valp = val; 332133343a97Smeem return (B_TRUE); 332233343a97Smeem } 332333343a97Smeem 332433343a97Smeem /* PRINTFLIKE1 */ 332533343a97Smeem static void 332633343a97Smeem warn(const char *format, ...) 332733343a97Smeem { 332833343a97Smeem va_list alist; 332933343a97Smeem 333033343a97Smeem format = gettext(format); 333133343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 333233343a97Smeem 333333343a97Smeem va_start(alist, format); 333433343a97Smeem (void) vfprintf(stderr, format, alist); 333533343a97Smeem va_end(alist); 333633343a97Smeem 333733343a97Smeem (void) putchar('\n'); 333833343a97Smeem } 333933343a97Smeem 334033343a97Smeem /* PRINTFLIKE2 */ 334133343a97Smeem static void 334233343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 334333343a97Smeem { 334433343a97Smeem va_list alist; 334533343a97Smeem char errmsg[DLADM_STRSIZE]; 334633343a97Smeem 334733343a97Smeem format = gettext(format); 334833343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 334933343a97Smeem 335033343a97Smeem va_start(alist, format); 335133343a97Smeem (void) vfprintf(stderr, format, alist); 335233343a97Smeem va_end(alist); 335333343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 335433343a97Smeem } 335533343a97Smeem 335633343a97Smeem /* PRINTFLIKE2 */ 335733343a97Smeem static void 335833343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 335933343a97Smeem { 336033343a97Smeem va_list alist; 336133343a97Smeem char errmsg[DLADM_STRSIZE]; 336233343a97Smeem 336333343a97Smeem format = gettext(format); 336433343a97Smeem (void) fprintf(stderr, "%s: ", progname); 336533343a97Smeem 336633343a97Smeem va_start(alist, format); 336733343a97Smeem (void) vfprintf(stderr, format, alist); 336833343a97Smeem va_end(alist); 336933343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 337033343a97Smeem 337133343a97Smeem exit(EXIT_FAILURE); 337233343a97Smeem } 337333343a97Smeem 337433343a97Smeem /* PRINTFLIKE1 */ 337533343a97Smeem static void 337633343a97Smeem die(const char *format, ...) 337733343a97Smeem { 337833343a97Smeem va_list alist; 337933343a97Smeem 338033343a97Smeem format = gettext(format); 338133343a97Smeem (void) fprintf(stderr, "%s: ", progname); 338233343a97Smeem 338333343a97Smeem va_start(alist, format); 338433343a97Smeem (void) vfprintf(stderr, format, alist); 338533343a97Smeem va_end(alist); 338633343a97Smeem 338733343a97Smeem (void) putchar('\n'); 338833343a97Smeem exit(EXIT_FAILURE); 338933343a97Smeem } 339033343a97Smeem 339133343a97Smeem static void 339233343a97Smeem die_optdup(int opt) 339333343a97Smeem { 339433343a97Smeem die("the option -%c cannot be specified more than once", opt); 339533343a97Smeem } 339633343a97Smeem 339733343a97Smeem static void 339833343a97Smeem die_opterr(int opt, int opterr) 339933343a97Smeem { 340033343a97Smeem switch (opterr) { 340133343a97Smeem case ':': 340233343a97Smeem die("option '-%c' requires a value", opt); 340333343a97Smeem break; 340433343a97Smeem case '?': 340533343a97Smeem default: 340633343a97Smeem die("unrecognized option '-%c'", opt); 340733343a97Smeem break; 34080ba2cbe9Sxc151355 } 34090ba2cbe9Sxc151355 } 3410