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 /* 22219a2a31Shl157128 * Copyright 2006 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> 3533343a97Smeem #include <stdarg.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <stropts.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include <kstat.h> 407c478bd9Sstevel@tonic-gate #include <strings.h> 417c478bd9Sstevel@tonic-gate #include <getopt.h> 427c478bd9Sstevel@tonic-gate #include <unistd.h> 43cd93090eSericheng #include <priv.h> 440ba2cbe9Sxc151355 #include <termios.h> 450ba2cbe9Sxc151355 #include <pwd.h> 460ba2cbe9Sxc151355 #include <auth_attr.h> 470ba2cbe9Sxc151355 #include <auth_list.h> 487c478bd9Sstevel@tonic-gate #include <libintl.h> 497c478bd9Sstevel@tonic-gate #include <libdlpi.h> 507c478bd9Sstevel@tonic-gate #include <libdladm.h> 517c478bd9Sstevel@tonic-gate #include <liblaadm.h> 527c478bd9Sstevel@tonic-gate #include <libmacadm.h> 530ba2cbe9Sxc151355 #include <libwladm.h> 540ba2cbe9Sxc151355 #include <libinetutil.h> 550ba2cbe9Sxc151355 #include <bsm/adt.h> 560ba2cbe9Sxc151355 #include <bsm/adt_event.h> 577c478bd9Sstevel@tonic-gate 58ba2e4443Sseb #define AGGR_DRV "aggr" 597c478bd9Sstevel@tonic-gate #define MAXPORT 256 607c478bd9Sstevel@tonic-gate #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 617c478bd9Sstevel@tonic-gate "%-5s %-4s %-4s %-9s %-7s\n" 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate typedef struct pktsum_s { 647c478bd9Sstevel@tonic-gate uint64_t ipackets; 657c478bd9Sstevel@tonic-gate uint64_t opackets; 667c478bd9Sstevel@tonic-gate uint64_t rbytes; 677c478bd9Sstevel@tonic-gate uint64_t obytes; 687c478bd9Sstevel@tonic-gate uint32_t ierrors; 697c478bd9Sstevel@tonic-gate uint32_t oerrors; 707c478bd9Sstevel@tonic-gate } pktsum_t; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate typedef struct show_link_state { 737c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 747c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 757c478bd9Sstevel@tonic-gate boolean_t ls_stats; 767c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 777c478bd9Sstevel@tonic-gate boolean_t ls_parseable; 787c478bd9Sstevel@tonic-gate } show_link_state_t; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 817c478bd9Sstevel@tonic-gate uint32_t gs_key; 827c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 837c478bd9Sstevel@tonic-gate boolean_t gs_found; 847c478bd9Sstevel@tonic-gate boolean_t gs_stats; 857c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 867c478bd9Sstevel@tonic-gate pktsum_t gs_prevstats[MAXPORT]; 877c478bd9Sstevel@tonic-gate boolean_t gs_parseable; 887c478bd9Sstevel@tonic-gate } show_grp_state_t; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate typedef struct show_mac_state { 917c478bd9Sstevel@tonic-gate boolean_t ms_firstonly; 927c478bd9Sstevel@tonic-gate boolean_t ms_donefirst; 937c478bd9Sstevel@tonic-gate pktsum_t ms_prevstats; 947c478bd9Sstevel@tonic-gate boolean_t ms_parseable; 957c478bd9Sstevel@tonic-gate } show_mac_state_t; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate typedef struct port_state { 987c478bd9Sstevel@tonic-gate char *state_name; 997c478bd9Sstevel@tonic-gate aggr_port_state_t state_num; 1007c478bd9Sstevel@tonic-gate } port_state_t; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static port_state_t port_states[] = { 1037c478bd9Sstevel@tonic-gate {"standby", AGGR_PORT_STATE_STANDBY }, 1047c478bd9Sstevel@tonic-gate {"attached", AGGR_PORT_STATE_ATTACHED } 1057c478bd9Sstevel@tonic-gate }; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 1087c478bd9Sstevel@tonic-gate 1090ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **); 1100ba2cbe9Sxc151355 1110ba2cbe9Sxc151355 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 1120ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 1130ba2cbe9Sxc151355 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 1140ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 1150ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 1160ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 1170ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 1187c478bd9Sstevel@tonic-gate 11933343a97Smeem static void link_stats(const char *, uint_t); 12033343a97Smeem static void aggr_stats(uint32_t, uint_t); 1217c478bd9Sstevel@tonic-gate static void dev_stats(const char *dev, uint32_t); 1227c478bd9Sstevel@tonic-gate 123ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 1247c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 125ba2e4443Sseb static uint64_t mac_ifspeed(const char *); 126ba2e4443Sseb static char *mac_link_state(const char *); 127ba2e4443Sseb static char *mac_link_duplex(const char *); 1287c478bd9Sstevel@tonic-gate static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 1297c478bd9Sstevel@tonic-gate static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 1307c478bd9Sstevel@tonic-gate 13133343a97Smeem static boolean_t str2int(const char *, int *); 13233343a97Smeem static void die(const char *, ...); 13333343a97Smeem static void die_optdup(int); 13433343a97Smeem static void die_opterr(int, int); 13533343a97Smeem static void die_laerr(laadm_diag_t, const char *, ...); 13633343a97Smeem static void die_wlerr(wladm_status_t, const char *, ...); 13733343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 13833343a97Smeem static void warn(const char *, ...); 13933343a97Smeem static void warn_wlerr(wladm_status_t, const char *, ...); 14033343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 14133343a97Smeem 1427c478bd9Sstevel@tonic-gate typedef struct cmd { 1437c478bd9Sstevel@tonic-gate char *c_name; 1440ba2cbe9Sxc151355 cmdfunc_t *c_fn; 1457c478bd9Sstevel@tonic-gate } cmd_t; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 1487c478bd9Sstevel@tonic-gate { "show-link", do_show_link }, 149210db224Sericheng { "show-dev", do_show_dev }, 1507c478bd9Sstevel@tonic-gate { "create-aggr", do_create_aggr }, 1517c478bd9Sstevel@tonic-gate { "delete-aggr", do_delete_aggr }, 1527c478bd9Sstevel@tonic-gate { "add-aggr", do_add_aggr }, 1537c478bd9Sstevel@tonic-gate { "remove-aggr", do_remove_aggr }, 1547c478bd9Sstevel@tonic-gate { "modify-aggr", do_modify_aggr }, 1557c478bd9Sstevel@tonic-gate { "show-aggr", do_show_aggr }, 1567c478bd9Sstevel@tonic-gate { "up-aggr", do_up_aggr }, 1570ba2cbe9Sxc151355 { "down-aggr", do_down_aggr }, 1580ba2cbe9Sxc151355 { "scan-wifi", do_scan_wifi }, 1590ba2cbe9Sxc151355 { "connect-wifi", do_connect_wifi }, 1600ba2cbe9Sxc151355 { "disconnect-wifi", do_disconnect_wifi }, 1610ba2cbe9Sxc151355 { "show-wifi", do_show_wifi }, 1620ba2cbe9Sxc151355 { "show-linkprop", do_show_linkprop }, 1630ba2cbe9Sxc151355 { "set-linkprop", do_set_linkprop }, 1640ba2cbe9Sxc151355 { "reset-linkprop", do_reset_linkprop }, 1650ba2cbe9Sxc151355 { "create-secobj", do_create_secobj }, 1660ba2cbe9Sxc151355 { "delete-secobj", do_delete_secobj }, 1670ba2cbe9Sxc151355 { "show-secobj", do_show_secobj }, 1680ba2cbe9Sxc151355 { "init-linkprop", do_init_linkprop }, 1690ba2cbe9Sxc151355 { "init-secobj", do_init_secobj } 1707c478bd9Sstevel@tonic-gate }; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static const struct option longopts[] = { 1737c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v' }, 1747c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd' }, 1757c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P' }, 1767c478bd9Sstevel@tonic-gate {"lacp-mode", required_argument, 0, 'l' }, 1777c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T' }, 1787c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u' }, 1797c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's' }, 1807c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i' }, 1817c478bd9Sstevel@tonic-gate {"lacp", no_argument, 0, 'L' }, 1827c478bd9Sstevel@tonic-gate {"temporary", no_argument, 0, 't' }, 1837c478bd9Sstevel@tonic-gate {"root-dir", required_argument, 0, 'r' }, 1847c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p' }, 1857c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 1867c478bd9Sstevel@tonic-gate }; 1877c478bd9Sstevel@tonic-gate 1880ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 1890ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 1900ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 1910ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 1920ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 1930ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 1940ba2cbe9Sxc151355 { 0, 0, 0, 0 } 1950ba2cbe9Sxc151355 }; 1960ba2cbe9Sxc151355 1970ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 1980ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 1990ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 2000ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 2010ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 2020ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 2030ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 2040ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 2050ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 2060ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 2070ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 2080ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 2090ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 2100ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 2110ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 2120ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 2130ba2cbe9Sxc151355 { 0, 0, 0, 0 } 2140ba2cbe9Sxc151355 }; 2150ba2cbe9Sxc151355 2167c478bd9Sstevel@tonic-gate static char *progname; 2170ba2cbe9Sxc151355 static sig_atomic_t signalled; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate static void 2207c478bd9Sstevel@tonic-gate usage(void) 2217c478bd9Sstevel@tonic-gate { 2220ba2cbe9Sxc151355 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 2230ba2cbe9Sxc151355 "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 2240ba2cbe9Sxc151355 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 2250ba2cbe9Sxc151355 "\n" 2260ba2cbe9Sxc151355 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2270ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 2280ba2cbe9Sxc151355 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2290ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] <key>\n" 2300ba2cbe9Sxc151355 "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 2310ba2cbe9Sxc151355 "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2320ba2cbe9Sxc151355 "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2330ba2cbe9Sxc151355 "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 2340ba2cbe9Sxc151355 "\n" 2350ba2cbe9Sxc151355 "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 2360ba2cbe9Sxc151355 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 2370ba2cbe9Sxc151355 " [-s wep]\n" 2380ba2cbe9Sxc151355 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 2390ba2cbe9Sxc151355 "\t [-T <time>] [<name>]\n" 2400ba2cbe9Sxc151355 "\tdisconnect-wifi [-a] [<name>]\n" 2410ba2cbe9Sxc151355 "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 2420ba2cbe9Sxc151355 "\n" 2430ba2cbe9Sxc151355 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 2440ba2cbe9Sxc151355 " <name>\n" 2450ba2cbe9Sxc151355 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 2460ba2cbe9Sxc151355 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 2470ba2cbe9Sxc151355 "\n" 2480ba2cbe9Sxc151355 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 2490ba2cbe9Sxc151355 " <secobj>\n" 2500ba2cbe9Sxc151355 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 2510ba2cbe9Sxc151355 "\tshow-secobj [-pP][<secobj>,...]\n")); 2527c478bd9Sstevel@tonic-gate exit(1); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate int 2567c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate int i; 2597c478bd9Sstevel@tonic-gate cmd_t *cmdp; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2627c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2637c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2647c478bd9Sstevel@tonic-gate #endif 2657c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate progname = argv[0]; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (argc < 2) 2707c478bd9Sstevel@tonic-gate usage(); 2717c478bd9Sstevel@tonic-gate 272cd93090eSericheng if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 27333343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 27433343a97Smeem die("insufficient privileges"); 275cd93090eSericheng 2767c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 2777c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 2787c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 2797c478bd9Sstevel@tonic-gate cmdp->c_fn(argc - 1, &argv[1]); 2807c478bd9Sstevel@tonic-gate exit(0); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 2857c478bd9Sstevel@tonic-gate progname, argv[1]); 2867c478bd9Sstevel@tonic-gate usage(); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate return (0); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate static void 2927c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[]) 2937c478bd9Sstevel@tonic-gate { 2947c478bd9Sstevel@tonic-gate char option; 29533343a97Smeem int key; 2967c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 2977c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2987c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 2997c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 3007c478bd9Sstevel@tonic-gate uint_t nport = 0; 3017c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 3027c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 3037c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 3047c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 3057c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3067c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 3077c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 3087c478bd9Sstevel@tonic-gate char *altroot = NULL; 3097c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate opterr = 0; 3127c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 3137c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 3147c478bd9Sstevel@tonic-gate switch (option) { 3157c478bd9Sstevel@tonic-gate case 'd': 31633343a97Smeem if (nport >= MAXPORT) 31733343a97Smeem die("too many <dev> arguments"); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 32033343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 32133343a97Smeem die("device name too long"); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate nport++; 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate case 'P': 32633343a97Smeem if (P_arg) 32733343a97Smeem die_optdup(option); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 33033343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 33133343a97Smeem die("invalid policy '%s'", optarg); 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate case 'u': 33433343a97Smeem if (u_arg) 33533343a97Smeem die_optdup(option); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 3387c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 33933343a97Smeem mac_addr)) 34033343a97Smeem die("invalid MAC address '%s'", optarg); 3417c478bd9Sstevel@tonic-gate break; 3427c478bd9Sstevel@tonic-gate case 'l': 34333343a97Smeem if (l_arg) 34433343a97Smeem die_optdup(option); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 34733343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 34833343a97Smeem die("invalid LACP mode '%s'", optarg); 3497c478bd9Sstevel@tonic-gate break; 3507c478bd9Sstevel@tonic-gate case 'T': 35133343a97Smeem if (T_arg) 35233343a97Smeem die_optdup(option); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 35533343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 35633343a97Smeem die("invalid LACP timer value '%s'", optarg); 3577c478bd9Sstevel@tonic-gate break; 3587c478bd9Sstevel@tonic-gate case 't': 3597c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 3607c478bd9Sstevel@tonic-gate break; 3617c478bd9Sstevel@tonic-gate case 'R': 3627c478bd9Sstevel@tonic-gate altroot = optarg; 3637c478bd9Sstevel@tonic-gate break; 3647c478bd9Sstevel@tonic-gate default: 36533343a97Smeem die_opterr(optopt, option); 36633343a97Smeem break; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (nport == 0) 3717c478bd9Sstevel@tonic-gate usage(); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 3747c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 3757c478bd9Sstevel@tonic-gate usage(); 3767c478bd9Sstevel@tonic-gate 37733343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 37833343a97Smeem die("invalid key value '%s'", argv[optind]); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (laadm_create(key, nport, port, policy, mac_addr_fixed, 38133343a97Smeem mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 38233343a97Smeem die_laerr(diag, "create operation failed"); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate static void 3867c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[]) 3877c478bd9Sstevel@tonic-gate { 38833343a97Smeem int key; 3897c478bd9Sstevel@tonic-gate char option; 3907c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3917c478bd9Sstevel@tonic-gate char *altroot = NULL; 3927c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate opterr = 0; 3957c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":R:t", longopts, 3967c478bd9Sstevel@tonic-gate NULL)) != -1) { 3977c478bd9Sstevel@tonic-gate switch (option) { 3987c478bd9Sstevel@tonic-gate case 't': 3997c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4007c478bd9Sstevel@tonic-gate break; 4017c478bd9Sstevel@tonic-gate case 'R': 4027c478bd9Sstevel@tonic-gate altroot = optarg; 4037c478bd9Sstevel@tonic-gate break; 4047c478bd9Sstevel@tonic-gate default: 40533343a97Smeem die_opterr(optopt, option); 4067c478bd9Sstevel@tonic-gate break; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4117c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4127c478bd9Sstevel@tonic-gate usage(); 4137c478bd9Sstevel@tonic-gate 41433343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 41533343a97Smeem die("invalid key value '%s'", argv[optind]); 4167c478bd9Sstevel@tonic-gate 41733343a97Smeem if (laadm_delete(key, t_arg, altroot, &diag) < 0) 41833343a97Smeem die_laerr(diag, "delete operation failed"); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate static void 4227c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[]) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate char option; 42533343a97Smeem int key; 4267c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4277c478bd9Sstevel@tonic-gate uint_t nport = 0; 4287c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4297c478bd9Sstevel@tonic-gate char *altroot = NULL; 4307c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate opterr = 0; 4337c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 4347c478bd9Sstevel@tonic-gate NULL)) != -1) { 4357c478bd9Sstevel@tonic-gate switch (option) { 4367c478bd9Sstevel@tonic-gate case 'd': 43733343a97Smeem if (nport >= MAXPORT) 43833343a97Smeem die("too many <dev> arguments"); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 44133343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 44233343a97Smeem die("device name too long"); 44333343a97Smeem 4447c478bd9Sstevel@tonic-gate nport++; 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate case 't': 4477c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate case 'R': 4507c478bd9Sstevel@tonic-gate altroot = optarg; 4517c478bd9Sstevel@tonic-gate break; 4527c478bd9Sstevel@tonic-gate default: 45333343a97Smeem die_opterr(optopt, option); 45433343a97Smeem break; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate if (nport == 0) 4597c478bd9Sstevel@tonic-gate usage(); 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4627c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4637c478bd9Sstevel@tonic-gate usage(); 4647c478bd9Sstevel@tonic-gate 46533343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 46633343a97Smeem die("invalid key value '%s'", argv[optind]); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 469219a2a31Shl157128 /* 470219a2a31Shl157128 * checking ENOTSUP is a temporary workaround 471219a2a31Shl157128 * and should be removed once 6399681 is fixed. 472219a2a31Shl157128 */ 473219a2a31Shl157128 if (errno == ENOTSUP) { 474219a2a31Shl157128 (void) fprintf(stderr, 475219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 476219a2a31Shl157128 progname, 477219a2a31Shl157128 gettext("device capabilities don't match")); 478219a2a31Shl157128 exit(ENOTSUP); 479219a2a31Shl157128 } 48033343a97Smeem die_laerr(diag, "add operation failed"); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate static void 4857c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[]) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate char option; 48833343a97Smeem int key; 4897c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4907c478bd9Sstevel@tonic-gate uint_t nport = 0; 4917c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4927c478bd9Sstevel@tonic-gate char *altroot = NULL; 4937c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate opterr = 0; 4967c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", 4977c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 4987c478bd9Sstevel@tonic-gate switch (option) { 4997c478bd9Sstevel@tonic-gate case 'd': 50033343a97Smeem if (nport >= MAXPORT) 50133343a97Smeem die("too many <dev> arguments"); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 50433343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 50533343a97Smeem die("device name too long"); 50633343a97Smeem 5077c478bd9Sstevel@tonic-gate nport++; 5087c478bd9Sstevel@tonic-gate break; 5097c478bd9Sstevel@tonic-gate case 't': 5107c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5117c478bd9Sstevel@tonic-gate break; 5127c478bd9Sstevel@tonic-gate case 'R': 5137c478bd9Sstevel@tonic-gate altroot = optarg; 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate default: 51633343a97Smeem die_opterr(optopt, option); 51733343a97Smeem break; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate if (nport == 0) 5227c478bd9Sstevel@tonic-gate usage(); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 5257c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 5267c478bd9Sstevel@tonic-gate usage(); 5277c478bd9Sstevel@tonic-gate 52833343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 52933343a97Smeem die("invalid key value '%s'", argv[optind]); 5307c478bd9Sstevel@tonic-gate 53133343a97Smeem if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) 53233343a97Smeem die_laerr(diag, "remove operation failed"); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate static void 5367c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[]) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate char option; 53933343a97Smeem int key; 5407c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 5417c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 5427c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 5437c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 5447c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 5457c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 5467c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 5477c478bd9Sstevel@tonic-gate char *altroot = NULL; 5487c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate opterr = 0; 5517c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 5527c478bd9Sstevel@tonic-gate NULL)) != -1) { 5537c478bd9Sstevel@tonic-gate switch (option) { 5547c478bd9Sstevel@tonic-gate case 'P': 55533343a97Smeem if (modify_mask & LAADM_MODIFY_POLICY) 55633343a97Smeem die_optdup(option); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_POLICY; 5597c478bd9Sstevel@tonic-gate 56033343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 56133343a97Smeem die("invalid policy '%s'", optarg); 5627c478bd9Sstevel@tonic-gate break; 5637c478bd9Sstevel@tonic-gate case 'u': 56433343a97Smeem if (modify_mask & LAADM_MODIFY_MAC) 56533343a97Smeem die_optdup(option); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_MAC; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 57033343a97Smeem mac_addr)) 57133343a97Smeem die("invalid MAC address '%s'", optarg); 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate case 'l': 57433343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_MODE) 57533343a97Smeem die_optdup(option); 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_MODE; 5787c478bd9Sstevel@tonic-gate 57933343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 58033343a97Smeem die("invalid LACP mode '%s'", optarg); 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate case 'T': 58333343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_TIMER) 58433343a97Smeem die_optdup(option); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_TIMER; 5877c478bd9Sstevel@tonic-gate 58833343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 58933343a97Smeem die("invalid LACP timer value '%s'", optarg); 5907c478bd9Sstevel@tonic-gate break; 5917c478bd9Sstevel@tonic-gate case 't': 5927c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5937c478bd9Sstevel@tonic-gate break; 5947c478bd9Sstevel@tonic-gate case 'R': 5957c478bd9Sstevel@tonic-gate altroot = optarg; 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate default: 59833343a97Smeem die_opterr(optopt, option); 59933343a97Smeem break; 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 60333343a97Smeem if (modify_mask == 0) 60433343a97Smeem die("at least one of the -PulT options must be specified"); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 6077c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 6087c478bd9Sstevel@tonic-gate usage(); 6097c478bd9Sstevel@tonic-gate 61033343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 61133343a97Smeem die("invalid key value '%s'", argv[optind]); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 61433343a97Smeem lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 61533343a97Smeem die_laerr(diag, "modify operation failed"); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate static void 6197c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[]) 6207c478bd9Sstevel@tonic-gate { 62133343a97Smeem int key = 0; 6227c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6257c478bd9Sstevel@tonic-gate if (argc == 2) { 62633343a97Smeem if (!str2int(argv[1], &key) || key < 1) 62733343a97Smeem die("invalid key value '%s'", argv[1]); 6287c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6297c478bd9Sstevel@tonic-gate usage(); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (laadm_up(key, NULL, &diag) < 0) { 6337c478bd9Sstevel@tonic-gate if (key != 0) { 63433343a97Smeem die_laerr(diag, "could not bring up aggregation '%u'", 63533343a97Smeem key); 6367c478bd9Sstevel@tonic-gate } else { 63733343a97Smeem die_laerr(diag, "could not bring aggregations up"); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate static void 6437c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[]) 6447c478bd9Sstevel@tonic-gate { 64533343a97Smeem int key = 0; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6487c478bd9Sstevel@tonic-gate if (argc == 2) { 64933343a97Smeem if (!str2int(argv[1], &key) || key < 1) 65033343a97Smeem die("invalid key value '%s'", argv[1]); 6517c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6527c478bd9Sstevel@tonic-gate usage(); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (laadm_down(key) < 0) { 6567c478bd9Sstevel@tonic-gate if (key != 0) { 65733343a97Smeem die("could not bring down aggregation '%u': %s", 65833343a97Smeem key, strerror(errno)); 6597c478bd9Sstevel@tonic-gate } else { 66033343a97Smeem die("could not bring down aggregations: %s", 66133343a97Smeem strerror(errno)); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate #define TYPE_WIDTH 10 667210db224Sericheng 668210db224Sericheng static void 669210db224Sericheng print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 670210db224Sericheng { 671210db224Sericheng char type[TYPE_WIDTH]; 672210db224Sericheng 673210db224Sericheng if (!legacy) { 674ba2e4443Sseb char drv[LIFNAMSIZ]; 675ba2e4443Sseb int instance; 676ba2e4443Sseb 677210db224Sericheng if (dap->da_vid != 0) { 678210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "vlan %u", 679210db224Sericheng dap->da_vid); 680210db224Sericheng } else { 681210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 682210db224Sericheng } 683ba2e4443Sseb if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 684ba2e4443Sseb return; 685ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 686210db224Sericheng (void) printf("%s type=%s mtu=%d key=%u\n", 687ba2e4443Sseb name, type, dap->da_max_sdu, instance); 688210db224Sericheng } else { 689210db224Sericheng (void) printf("%s type=%s mtu=%d device=%s\n", 690210db224Sericheng name, type, dap->da_max_sdu, dap->da_dev); 691210db224Sericheng } 692210db224Sericheng } else { 693210db224Sericheng (void) printf("%s type=legacy mtu=%d device=%s\n", 694210db224Sericheng name, dap->da_max_sdu, name); 695210db224Sericheng } 696210db224Sericheng } 697210db224Sericheng 698210db224Sericheng static void 699210db224Sericheng print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 700210db224Sericheng { 701210db224Sericheng char type[TYPE_WIDTH]; 702210db224Sericheng 703210db224Sericheng if (!legacy) { 704ba2e4443Sseb char drv[LIFNAMSIZ]; 705ba2e4443Sseb int instance; 706ba2e4443Sseb 707210db224Sericheng if (dap->da_vid != 0) { 708210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 709210db224Sericheng dap->da_vid); 710210db224Sericheng } else { 711210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 712210db224Sericheng } 713ba2e4443Sseb if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 714ba2e4443Sseb return; 715ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 716210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 717210db224Sericheng "\taggregation: key %u\n"), name, type, 718ba2e4443Sseb dap->da_max_sdu, instance); 719210db224Sericheng } else { 720210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: " 721210db224Sericheng "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 722210db224Sericheng dap->da_dev); 723210db224Sericheng } 724210db224Sericheng } else { 725210db224Sericheng (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 726210db224Sericheng "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 727210db224Sericheng } 728210db224Sericheng } 729210db224Sericheng 730210db224Sericheng static int 731210db224Sericheng get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 732210db224Sericheng { 733210db224Sericheng int err; 734210db224Sericheng 735210db224Sericheng if ((err = dladm_info(name, dlattrp)) == 0) { 736210db224Sericheng *legacy = B_FALSE; 737210db224Sericheng } else if (err < 0 && errno == ENODEV) { 738210db224Sericheng int fd; 739210db224Sericheng dlpi_if_attr_t dia; 740210db224Sericheng dl_info_ack_t dlia; 741210db224Sericheng 742210db224Sericheng /* 743210db224Sericheng * A return value of ENODEV means that the specified 744210db224Sericheng * device is not gldv3. 745210db224Sericheng */ 746210db224Sericheng if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && 747210db224Sericheng dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, 748210db224Sericheng NULL, NULL) != -1) { 749210db224Sericheng (void) dlpi_close(fd); 750210db224Sericheng 751210db224Sericheng *legacy = B_TRUE; 752210db224Sericheng bzero(dlattrp, sizeof (*dlattrp)); 753210db224Sericheng dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; 754210db224Sericheng } else { 755210db224Sericheng errno = ENOENT; 756210db224Sericheng return (-1); 757210db224Sericheng } 758210db224Sericheng } else { 759210db224Sericheng /* 760210db224Sericheng * If the return value is not ENODEV, this means that 761210db224Sericheng * user is either passing in a bogus interface name 762210db224Sericheng * or a vlan interface name that doesn't exist yet. 763210db224Sericheng */ 764210db224Sericheng errno = ENOENT; 765210db224Sericheng return (-1); 766210db224Sericheng } 767210db224Sericheng return (0); 768210db224Sericheng } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7717c478bd9Sstevel@tonic-gate static void 7727c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name) 7737c478bd9Sstevel@tonic-gate { 7747c478bd9Sstevel@tonic-gate dladm_attr_t dlattr; 775210db224Sericheng boolean_t legacy = B_TRUE; 7767c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7777c478bd9Sstevel@tonic-gate 77833343a97Smeem if (get_if_info(name, &dlattr, &legacy) < 0) 77933343a97Smeem die("invalid link '%s'", name); 7807c478bd9Sstevel@tonic-gate 781210db224Sericheng if (state->ls_parseable) { 782210db224Sericheng print_link_parseable(name, &dlattr, legacy); 7837c478bd9Sstevel@tonic-gate } else { 784210db224Sericheng print_link(name, &dlattr, legacy); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static void 7897c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7927c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 7957c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 7967c478bd9Sstevel@tonic-gate return; 7977c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 7987c478bd9Sstevel@tonic-gate } else { 7997c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate get_link_stats(name, &stats); 8037c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ls_prevstats); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate (void) printf("%s", name); 8067c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 8077c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 8087c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 8097c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 8107c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 8117c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate static void 8177c478bd9Sstevel@tonic-gate dump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8187c478bd9Sstevel@tonic-gate { 8197c478bd9Sstevel@tonic-gate char policy_str[LAADM_POLICY_STR_LEN]; 8207c478bd9Sstevel@tonic-gate char addr_str[ETHERADDRL * 3]; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate if (!parseable) { 8237c478bd9Sstevel@tonic-gate (void) printf(gettext("key: %d (0x%04x)"), 8247c478bd9Sstevel@tonic-gate grp->lg_key, grp->lg_key); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate (void) printf(gettext("\tpolicy: %s"), 8277c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate (void) printf(gettext("\taddress: %s (%s)\n"), 8307c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str), 8317c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 8327c478bd9Sstevel@tonic-gate } else { 8337c478bd9Sstevel@tonic-gate (void) printf("aggr key=%d", grp->lg_key); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate (void) printf(" policy=%s", 8367c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate (void) printf(" address=%s", 8397c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate (void) printf(" address-type=%s\n", 8427c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? "fixed" : "auto"); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate static void 8477c478bd9Sstevel@tonic-gate dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 8507c478bd9Sstevel@tonic-gate const char *lacp_timer_str = 8517c478bd9Sstevel@tonic-gate laadm_lacp_timer_to_str(grp->lg_lacp_timer); 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate if (!parseable) { 8547c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 8557c478bd9Sstevel@tonic-gate (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 8567c478bd9Sstevel@tonic-gate } else { 8577c478bd9Sstevel@tonic-gate (void) printf(" lacp-mode=%s", lacp_mode_str); 8587c478bd9Sstevel@tonic-gate (void) printf(" lacp-timer=%s\n", lacp_timer_str); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate static void 8637c478bd9Sstevel@tonic-gate dump_grp_stats(laadm_grp_attr_sys_t *grp) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate (void) printf("key: %d", grp->lg_key); 8667c478bd9Sstevel@tonic-gate (void) printf("\tipackets rbytes opackets obytes "); 8677c478bd9Sstevel@tonic-gate (void) printf("%%ipkts %%opkts\n"); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate static void 8717c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 8747c478bd9Sstevel@tonic-gate gettext("timeout"), gettext("aggregatable"), gettext("sync"), 8757c478bd9Sstevel@tonic-gate gettext("coll"), gettext("dist"), gettext("defaulted"), 8767c478bd9Sstevel@tonic-gate gettext("expired")); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate static void 8807c478bd9Sstevel@tonic-gate dump_ports_head(void) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 8837c478bd9Sstevel@tonic-gate "state\n")); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate static char * 8877c478bd9Sstevel@tonic-gate port_state_to_str(aggr_port_state_t state_num) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate int i; 8907c478bd9Sstevel@tonic-gate port_state_t *state; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate for (i = 0; i < NPORTSTATES; i++) { 8937c478bd9Sstevel@tonic-gate state = &port_states[i]; 8947c478bd9Sstevel@tonic-gate if (state->state_num == state_num) 8957c478bd9Sstevel@tonic-gate return (state->state_name); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate return ("unknown"); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate static void 9027c478bd9Sstevel@tonic-gate dump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 9037c478bd9Sstevel@tonic-gate { 9047c478bd9Sstevel@tonic-gate char *dev = port->lp_devname; 9057c478bd9Sstevel@tonic-gate char buf[ETHERADDRL * 3]; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if (!parseable) { 9087c478bd9Sstevel@tonic-gate (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 9097c478bd9Sstevel@tonic-gate port->lp_mac, buf)); 91033343a97Smeem (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) / 9117c478bd9Sstevel@tonic-gate 1000000ull)); 912ba2e4443Sseb (void) printf("\t%s", mac_link_duplex(dev)); 913ba2e4443Sseb (void) printf("\t%s", mac_link_state(dev)); 9147c478bd9Sstevel@tonic-gate (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate } else { 9177c478bd9Sstevel@tonic-gate (void) printf(" device=%s address=%s", dev, 9187c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(port->lp_mac, buf)); 919ba2e4443Sseb (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 9207c478bd9Sstevel@tonic-gate 1000000ull)); 921ba2e4443Sseb (void) printf(" duplex=%s", mac_link_duplex(dev)); 922ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 9237c478bd9Sstevel@tonic-gate (void) printf(" port=%s", port_state_to_str(port->lp_state)); 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate static void 9287c478bd9Sstevel@tonic-gate dump_port_lacp(laadm_port_attr_sys_t *port) 9297c478bd9Sstevel@tonic-gate { 9307c478bd9Sstevel@tonic-gate aggr_lacp_state_t *state = &port->lp_lacp_state; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, 9337c478bd9Sstevel@tonic-gate port->lp_devname, state->bit.activity ? "active" : "passive", 9347c478bd9Sstevel@tonic-gate state->bit.timeout ? "short" : "long", 9357c478bd9Sstevel@tonic-gate state->bit.aggregation ? "yes" : "no", 9367c478bd9Sstevel@tonic-gate state->bit.sync ? "yes" : "no", 9377c478bd9Sstevel@tonic-gate state->bit.collecting ? "yes" : "no", 9387c478bd9Sstevel@tonic-gate state->bit.distributing ? "yes" : "no", 9397c478bd9Sstevel@tonic-gate state->bit.defaulted ? "yes" : "no", 9407c478bd9Sstevel@tonic-gate state->bit.expired ? "yes" : "no"); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate static void 9447c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 9457c478bd9Sstevel@tonic-gate pktsum_t *tot_stats) 9467c478bd9Sstevel@tonic-gate { 9477c478bd9Sstevel@tonic-gate pktsum_t diff_stats; 9487c478bd9Sstevel@tonic-gate pktsum_t *old_stats = &state->gs_prevstats[index]; 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, port_stats, old_stats); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", diff_stats.ipackets); 9537c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 9547c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 9557c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (tot_stats->ipackets == 0) 9587c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9597c478bd9Sstevel@tonic-gate else 9607c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 9617c478bd9Sstevel@tonic-gate (double)tot_stats->ipackets * 100); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate if (tot_stats->opackets == 0) 9647c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9657c478bd9Sstevel@tonic-gate else 9667c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 9677c478bd9Sstevel@tonic-gate (double)tot_stats->opackets * 100); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate (void) printf("\n"); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate *old_stats = *port_stats; 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate static int 9757c478bd9Sstevel@tonic-gate show_key(void *arg, laadm_grp_attr_sys_t *grp) 9767c478bd9Sstevel@tonic-gate { 9777c478bd9Sstevel@tonic-gate show_grp_state_t *state = (show_grp_state_t *)arg; 9787c478bd9Sstevel@tonic-gate int i; 9797c478bd9Sstevel@tonic-gate pktsum_t pktsumtot, port_stat; 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate if (state->gs_key != 0 && state->gs_key != grp->lg_key) 9827c478bd9Sstevel@tonic-gate return (0); 9837c478bd9Sstevel@tonic-gate if (state->gs_firstonly) { 9847c478bd9Sstevel@tonic-gate if (state->gs_found) 9857c478bd9Sstevel@tonic-gate return (0); 9867c478bd9Sstevel@tonic-gate } else { 9877c478bd9Sstevel@tonic-gate bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate state->gs_found = B_TRUE; 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate if (state->gs_stats) { 9937c478bd9Sstevel@tonic-gate /* show statistics */ 9947c478bd9Sstevel@tonic-gate dump_grp_stats(grp); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 9977c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 9987c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 999ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10007c478bd9Sstevel@tonic-gate stats_total(&pktsumtot, &port_stat, 10017c478bd9Sstevel@tonic-gate &state->gs_prevstats[i]); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate (void) printf(" Total"); 10057c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", pktsumtot.ipackets); 10067c478bd9Sstevel@tonic-gate (void) printf("%-12llu", pktsumtot.rbytes); 10077c478bd9Sstevel@tonic-gate (void) printf("%-10llu", pktsumtot.opackets); 10087c478bd9Sstevel@tonic-gate (void) printf("%-12llu\n", pktsumtot.obytes); 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 1011ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10127c478bd9Sstevel@tonic-gate (void) printf(" %s", grp->lg_ports[i].lp_devname); 10137c478bd9Sstevel@tonic-gate dump_port_stat(i, state, &port_stat, &pktsumtot); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate } else if (state->gs_lacp) { 10167c478bd9Sstevel@tonic-gate /* show LACP info */ 10177c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10187c478bd9Sstevel@tonic-gate dump_grp_lacp(grp, state->gs_parseable); 10197c478bd9Sstevel@tonic-gate dump_ports_lacp_head(); 10207c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) 10217c478bd9Sstevel@tonic-gate dump_port_lacp(&grp->lg_ports[i]); 10227c478bd9Sstevel@tonic-gate } else { 10237c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10247c478bd9Sstevel@tonic-gate if (!state->gs_parseable) 10257c478bd9Sstevel@tonic-gate dump_ports_head(); 10267c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 10277c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10287c478bd9Sstevel@tonic-gate (void) printf("dev key=%d", grp->lg_key); 10297c478bd9Sstevel@tonic-gate dump_port(&grp->lg_ports[i], state->gs_parseable); 10307c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10317c478bd9Sstevel@tonic-gate (void) printf("\n"); 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate return (0); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate static int 10397c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 10407c478bd9Sstevel@tonic-gate { 10417c478bd9Sstevel@tonic-gate kstat_named_t *knp; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 10447c478bd9Sstevel@tonic-gate return (-1); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate if (knp->data_type != type) 10477c478bd9Sstevel@tonic-gate return (-1); 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate switch (type) { 10507c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT64: 10517c478bd9Sstevel@tonic-gate *(uint64_t *)buf = knp->value.ui64; 10527c478bd9Sstevel@tonic-gate break; 10537c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT32: 10547c478bd9Sstevel@tonic-gate *(uint32_t *)buf = knp->value.ui32; 10557c478bd9Sstevel@tonic-gate break; 10567c478bd9Sstevel@tonic-gate default: 10577c478bd9Sstevel@tonic-gate return (-1); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate return (0); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate static void 1064210db224Sericheng show_dev(void *arg, const char *dev) 10657c478bd9Sstevel@tonic-gate { 10667c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate if (!state->ms_parseable) { 10717c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tlink: %s"), 1072ba2e4443Sseb mac_link_state(dev)); 107333343a97Smeem (void) printf(gettext("\tspeed: %5uMb"), 1074ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 10757c478bd9Sstevel@tonic-gate (void) printf(gettext("\tduplex: %s\n"), 1076ba2e4443Sseb mac_link_duplex(dev)); 10777c478bd9Sstevel@tonic-gate } else { 1078ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 10797c478bd9Sstevel@tonic-gate (void) printf(" speed=%u", 1080ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1081ba2e4443Sseb (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10867c478bd9Sstevel@tonic-gate static void 1087210db224Sericheng show_dev_stats(void *arg, const char *dev) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10907c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (state->ms_firstonly) { 10937c478bd9Sstevel@tonic-gate if (state->ms_donefirst) 10947c478bd9Sstevel@tonic-gate return; 10957c478bd9Sstevel@tonic-gate state->ms_donefirst = B_TRUE; 10967c478bd9Sstevel@tonic-gate } else { 10977c478bd9Sstevel@tonic-gate bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 1100ba2e4443Sseb get_mac_stats(dev, &stats); 11017c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ms_prevstats); 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 11047c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 11057c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 11067c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 11077c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 11087c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 11097c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate state->ms_prevstats = stats; 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate static void 11157c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[]) 11167c478bd9Sstevel@tonic-gate { 11177c478bd9Sstevel@tonic-gate char *name = NULL; 11187c478bd9Sstevel@tonic-gate int option; 11197c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11207c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 112133343a97Smeem int interval = 0; 11227c478bd9Sstevel@tonic-gate show_link_state_t state; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate state.ls_stats = B_FALSE; 11257c478bd9Sstevel@tonic-gate state.ls_parseable = B_FALSE; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate opterr = 0; 11287c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 11297c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11307c478bd9Sstevel@tonic-gate switch (option) { 11317c478bd9Sstevel@tonic-gate case 'p': 11327c478bd9Sstevel@tonic-gate state.ls_parseable = B_TRUE; 11337c478bd9Sstevel@tonic-gate break; 11347c478bd9Sstevel@tonic-gate case 's': 113533343a97Smeem if (s_arg) 113633343a97Smeem die_optdup(option); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate case 'i': 114133343a97Smeem if (i_arg) 114233343a97Smeem die_optdup(option); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 114533343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 114633343a97Smeem die("invalid interval value '%s'", optarg); 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate default: 114933343a97Smeem die_opterr(optopt, option); 115033343a97Smeem break; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 115433343a97Smeem if (i_arg && !s_arg) 115533343a97Smeem die("the option -i can be used only with -s"); 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 11587c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 11597c478bd9Sstevel@tonic-gate name = argv[optind]; 11607c478bd9Sstevel@tonic-gate else if (optind != argc) 11617c478bd9Sstevel@tonic-gate usage(); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (s_arg) { 11647c478bd9Sstevel@tonic-gate link_stats(name, interval); 11657c478bd9Sstevel@tonic-gate return; 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 1168210db224Sericheng if (name == NULL) { 11697c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link, &state); 1170210db224Sericheng } else { 11717c478bd9Sstevel@tonic-gate show_link(&state, name); 11727c478bd9Sstevel@tonic-gate } 1173210db224Sericheng } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate static void 11767c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[]) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate int option; 117933343a97Smeem int key = 0; 11807c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 11817c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11827c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 11837c478bd9Sstevel@tonic-gate show_grp_state_t state; 118433343a97Smeem int interval = 0; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate state.gs_stats = B_FALSE; 11877c478bd9Sstevel@tonic-gate state.gs_lacp = B_FALSE; 11887c478bd9Sstevel@tonic-gate state.gs_parseable = B_FALSE; 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate opterr = 0; 11917c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":Lpsi:", 11927c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11937c478bd9Sstevel@tonic-gate switch (option) { 11947c478bd9Sstevel@tonic-gate case 'L': 119533343a97Smeem if (L_arg) 119633343a97Smeem die_optdup(option); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (s_arg || i_arg) { 119933343a97Smeem die("the option -L cannot be used with -i " 120033343a97Smeem "or -s"); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 12047c478bd9Sstevel@tonic-gate state.gs_lacp = B_TRUE; 12057c478bd9Sstevel@tonic-gate break; 12067c478bd9Sstevel@tonic-gate case 'p': 12077c478bd9Sstevel@tonic-gate state.gs_parseable = B_TRUE; 12087c478bd9Sstevel@tonic-gate break; 12097c478bd9Sstevel@tonic-gate case 's': 121033343a97Smeem if (s_arg) 121133343a97Smeem die_optdup(option); 12127c478bd9Sstevel@tonic-gate 121333343a97Smeem if (L_arg) 1214*13994ee8Sxz162242 die("the option -s cannot be used with -L"); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate case 'i': 121933343a97Smeem if (i_arg) 122033343a97Smeem die_optdup(option); 12217c478bd9Sstevel@tonic-gate 122233343a97Smeem if (L_arg) 122333343a97Smeem die("the option -i cannot be used with -L"); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 122633343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 122733343a97Smeem die("invalid interval value '%s'", optarg); 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate default: 123033343a97Smeem die_opterr(optopt, option); 123133343a97Smeem break; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate 123533343a97Smeem if (i_arg && !s_arg) 123633343a97Smeem die("the option -i can be used only with -s"); 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 12397c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 124033343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 124133343a97Smeem die("invalid key value '%s'", argv[optind]); 12427c478bd9Sstevel@tonic-gate } else if (optind != argc) { 12437c478bd9Sstevel@tonic-gate usage(); 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate if (s_arg) { 12477c478bd9Sstevel@tonic-gate aggr_stats(key, interval); 12487c478bd9Sstevel@tonic-gate return; 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate state.gs_key = key; 12527c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 12557c478bd9Sstevel@tonic-gate 125633343a97Smeem if (key != 0 && !state.gs_found) 125733343a97Smeem die("non-existent aggregation key '%u'", key); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate static void 12617c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[]) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate int option; 12647c478bd9Sstevel@tonic-gate char *dev = NULL; 12657c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 12667c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 126733343a97Smeem int interval = 0; 12687c478bd9Sstevel@tonic-gate show_mac_state_t state; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate state.ms_parseable = B_FALSE; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate opterr = 0; 12737c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 12747c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 12757c478bd9Sstevel@tonic-gate switch (option) { 12767c478bd9Sstevel@tonic-gate case 'p': 12777c478bd9Sstevel@tonic-gate state.ms_parseable = B_TRUE; 12787c478bd9Sstevel@tonic-gate break; 12797c478bd9Sstevel@tonic-gate case 's': 128033343a97Smeem if (s_arg) 128133343a97Smeem die_optdup(option); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12847c478bd9Sstevel@tonic-gate break; 12857c478bd9Sstevel@tonic-gate case 'i': 128633343a97Smeem if (i_arg) 128733343a97Smeem die_optdup(option); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 129033343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 129133343a97Smeem die("invalid interval value '%s'", optarg); 12927c478bd9Sstevel@tonic-gate break; 12937c478bd9Sstevel@tonic-gate default: 129433343a97Smeem die_opterr(optopt, option); 129533343a97Smeem break; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 129933343a97Smeem if (i_arg && !s_arg) 130033343a97Smeem die("the option -i can be used only with -s"); 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* get dev name (optional last argument) */ 13037c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 13047c478bd9Sstevel@tonic-gate dev = argv[optind]; 13057c478bd9Sstevel@tonic-gate else if (optind != argc) 13067c478bd9Sstevel@tonic-gate usage(); 13077c478bd9Sstevel@tonic-gate 1308cd93090eSericheng if (dev != NULL) { 1309cd93090eSericheng int index; 1310cd93090eSericheng char drv[LIFNAMSIZ]; 1311cd93090eSericheng dladm_attr_t dlattr; 1312cd93090eSericheng boolean_t legacy; 1313cd93090eSericheng 1314cd93090eSericheng /* 1315cd93090eSericheng * Check for invalid devices. 1316cd93090eSericheng * aggregations and vlans are not considered devices. 1317cd93090eSericheng */ 1318cd93090eSericheng if (strncmp(dev, "aggr", 4) == 0 || 1319cd93090eSericheng dlpi_if_parse(dev, drv, &index) < 0 || 132033343a97Smeem index >= 1000 || get_if_info(dev, &dlattr, &legacy) < 0) 132133343a97Smeem die("invalid device '%s'", dev); 1322cd93090eSericheng } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate if (s_arg) { 13257c478bd9Sstevel@tonic-gate dev_stats(dev, interval); 13267c478bd9Sstevel@tonic-gate return; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate if (dev == NULL) 13307c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev, &state, B_TRUE); 13317c478bd9Sstevel@tonic-gate else 1332210db224Sericheng show_dev(&state, dev); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13367c478bd9Sstevel@tonic-gate static void 133733343a97Smeem link_stats(const char *link, uint_t interval) 13387c478bd9Sstevel@tonic-gate { 1339210db224Sericheng dladm_attr_t dlattr; 1340210db224Sericheng boolean_t legacy; 13417c478bd9Sstevel@tonic-gate show_link_state_t state; 13427c478bd9Sstevel@tonic-gate 134333343a97Smeem if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 134433343a97Smeem die("invalid link '%s'", link); 134533343a97Smeem 13467c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate /* 13497c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13507c478bd9Sstevel@tonic-gate * only for the first MAC port. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate state.ls_firstonly = (interval != 0); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate for (;;) { 13557c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 13567c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate state.ls_donefirst = B_FALSE; 13597c478bd9Sstevel@tonic-gate if (link == NULL) 13607c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link_stats, &state); 13617c478bd9Sstevel@tonic-gate else 13627c478bd9Sstevel@tonic-gate show_link_stats(&state, link); 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate if (interval == 0) 13657c478bd9Sstevel@tonic-gate break; 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate (void) sleep(interval); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13727c478bd9Sstevel@tonic-gate static void 137333343a97Smeem aggr_stats(uint32_t key, uint_t interval) 13747c478bd9Sstevel@tonic-gate { 13757c478bd9Sstevel@tonic-gate show_grp_state_t state; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13787c478bd9Sstevel@tonic-gate state.gs_stats = B_TRUE; 13797c478bd9Sstevel@tonic-gate state.gs_key = key; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13837c478bd9Sstevel@tonic-gate * only for the first group. 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate state.gs_firstonly = (interval != 0); 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate for (;;) { 13887c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 13897c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 139033343a97Smeem if (state.gs_key != 0 && !state.gs_found) 139133343a97Smeem die("non-existent aggregation key '%u'", key); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate if (interval == 0) 13947c478bd9Sstevel@tonic-gate break; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate (void) sleep(interval); 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14017c478bd9Sstevel@tonic-gate static void 14027c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval) 14037c478bd9Sstevel@tonic-gate { 14047c478bd9Sstevel@tonic-gate show_mac_state_t state; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate /* 14097c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 14107c478bd9Sstevel@tonic-gate * only for the first MAC port. 14117c478bd9Sstevel@tonic-gate */ 14127c478bd9Sstevel@tonic-gate state.ms_firstonly = (interval != 0); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate for (;;) { 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 14177c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate state.ms_donefirst = B_FALSE; 1420210db224Sericheng if (dev == NULL) 14217c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1422210db224Sericheng else 1423210db224Sericheng show_dev_stats(&state, dev); 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate if (interval == 0) 14267c478bd9Sstevel@tonic-gate break; 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate (void) sleep(interval); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */ 14337c478bd9Sstevel@tonic-gate static void 14347c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14357c478bd9Sstevel@tonic-gate { 14367c478bd9Sstevel@tonic-gate s1->ipackets += (s2->ipackets - s3->ipackets); 14377c478bd9Sstevel@tonic-gate s1->opackets += (s2->opackets - s3->opackets); 14387c478bd9Sstevel@tonic-gate s1->rbytes += (s2->rbytes - s3->rbytes); 14397c478bd9Sstevel@tonic-gate s1->obytes += (s2->obytes - s3->obytes); 14407c478bd9Sstevel@tonic-gate s1->ierrors += (s2->ierrors - s3->ierrors); 14417c478bd9Sstevel@tonic-gate s1->oerrors += (s2->oerrors - s3->oerrors); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */ 14457c478bd9Sstevel@tonic-gate static void 14467c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14477c478bd9Sstevel@tonic-gate { 14487c478bd9Sstevel@tonic-gate s1->ipackets = s2->ipackets - s3->ipackets; 14497c478bd9Sstevel@tonic-gate s1->opackets = s2->opackets - s3->opackets; 14507c478bd9Sstevel@tonic-gate s1->rbytes = s2->rbytes - s3->rbytes; 14517c478bd9Sstevel@tonic-gate s1->obytes = s2->obytes - s3->obytes; 14527c478bd9Sstevel@tonic-gate s1->ierrors = s2->ierrors - s3->ierrors; 14537c478bd9Sstevel@tonic-gate s1->oerrors = s2->oerrors - s3->oerrors; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 1456cd93090eSericheng /* 1457ba2e4443Sseb * In the following routines, we do the first kstat_lookup() assuming that 1458ba2e4443Sseb * the device is gldv3-based and that the kstat name is the one passed in 1459ba2e4443Sseb * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1460ba2e4443Sseb * omitting the kstat name. This second lookup is needed for getting kstats 1461ba2e4443Sseb * from legacy devices. This can fail too if the device is not attached or 1462ba2e4443Sseb * the device is legacy and doesn't export the kstats we need. 1463cd93090eSericheng */ 14647c478bd9Sstevel@tonic-gate static void 14657c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats) 14667c478bd9Sstevel@tonic-gate { 14677c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 14687c478bd9Sstevel@tonic-gate kstat_t *ksp; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 147133343a97Smeem warn("kstat open operation failed"); 14727c478bd9Sstevel@tonic-gate return; 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate 1475cd93090eSericheng if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1476ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 14777c478bd9Sstevel@tonic-gate /* 14787c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 14797c478bd9Sstevel@tonic-gate * driver was already detached. 14807c478bd9Sstevel@tonic-gate */ 14817c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 14827c478bd9Sstevel@tonic-gate return; 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) 14867c478bd9Sstevel@tonic-gate goto bail; 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 14897c478bd9Sstevel@tonic-gate &stats->ipackets) < 0) 14907c478bd9Sstevel@tonic-gate goto bail; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 14937c478bd9Sstevel@tonic-gate &stats->opackets) < 0) 14947c478bd9Sstevel@tonic-gate goto bail; 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 14977c478bd9Sstevel@tonic-gate &stats->rbytes) < 0) 14987c478bd9Sstevel@tonic-gate goto bail; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 15017c478bd9Sstevel@tonic-gate &stats->obytes) < 0) 15027c478bd9Sstevel@tonic-gate goto bail; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 15057c478bd9Sstevel@tonic-gate &stats->ierrors) < 0) 15067c478bd9Sstevel@tonic-gate goto bail; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 15097c478bd9Sstevel@tonic-gate &stats->oerrors) < 0) 15107c478bd9Sstevel@tonic-gate goto bail; 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15137c478bd9Sstevel@tonic-gate return; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate bail: 15167c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate static void 1520ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats) 15217c478bd9Sstevel@tonic-gate { 1522ba2e4443Sseb char module[LIFNAMSIZ]; 1523ba2e4443Sseb int instance; 15247c478bd9Sstevel@tonic-gate 1525ba2e4443Sseb if (dlpi_if_parse(dev, module, &instance) != 0) 1526ba2e4443Sseb return; 15277c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1528ba2e4443Sseb get_stats(module, instance, "mac", stats); 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate static void 15327c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 15337c478bd9Sstevel@tonic-gate { 1534ba2e4443Sseb char module[LIFNAMSIZ]; 1535ba2e4443Sseb int instance; 1536ba2e4443Sseb 1537ba2e4443Sseb if (dlpi_if_parse(link, module, &instance) != 0) 1538ba2e4443Sseb return; 15397c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1540ba2e4443Sseb get_stats(module, instance, (char *)link, stats); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 1543ba2e4443Sseb static int 1544ba2e4443Sseb get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1545ba2e4443Sseb void *val) 15467c478bd9Sstevel@tonic-gate { 1547ba2e4443Sseb char module[LIFNAMSIZ]; 1548ba2e4443Sseb int instance; 15497c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 15507c478bd9Sstevel@tonic-gate kstat_t *ksp; 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 155333343a97Smeem warn("kstat open operation failed"); 1554ba2e4443Sseb return (-1); 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 1557ba2e4443Sseb if (dlpi_if_parse(dev, module, &instance) != 0) 1558ba2e4443Sseb return (-1); 1559ba2e4443Sseb if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1560ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 15637c478bd9Sstevel@tonic-gate * driver was already detached. 15647c478bd9Sstevel@tonic-gate */ 15657c478bd9Sstevel@tonic-gate goto bail; 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 156933343a97Smeem warn("kstat read failed"); 15707c478bd9Sstevel@tonic-gate goto bail; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 1573ba2e4443Sseb if (kstat_value(ksp, name, type, val) < 0) 15747c478bd9Sstevel@tonic-gate goto bail; 1575ba2e4443Sseb 1576ba2e4443Sseb (void) kstat_close(kcp); 1577ba2e4443Sseb return (0); 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate bail: 15807c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 1581ba2e4443Sseb return (-1); 1582ba2e4443Sseb } 1583ba2e4443Sseb 1584ba2e4443Sseb static uint64_t 1585ba2e4443Sseb mac_ifspeed(const char *dev) 1586ba2e4443Sseb { 1587ba2e4443Sseb uint64_t ifspeed = 0; 1588ba2e4443Sseb 1589ba2e4443Sseb (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 15907c478bd9Sstevel@tonic-gate return (ifspeed); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate static char * 1594ba2e4443Sseb mac_link_state(const char *dev) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate link_state_t link_state; 15977c478bd9Sstevel@tonic-gate char *state_str = "unknown"; 15987c478bd9Sstevel@tonic-gate 1599ba2e4443Sseb if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1600ba2e4443Sseb &link_state) != 0) { 16017c478bd9Sstevel@tonic-gate return (state_str); 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate switch (link_state) { 16057c478bd9Sstevel@tonic-gate case LINK_STATE_UP: 16067c478bd9Sstevel@tonic-gate state_str = "up"; 16077c478bd9Sstevel@tonic-gate break; 16087c478bd9Sstevel@tonic-gate case LINK_STATE_DOWN: 16097c478bd9Sstevel@tonic-gate state_str = "down"; 16107c478bd9Sstevel@tonic-gate break; 16117c478bd9Sstevel@tonic-gate default: 16127c478bd9Sstevel@tonic-gate break; 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate return (state_str); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate static char * 1620ba2e4443Sseb mac_link_duplex(const char *dev) 16217c478bd9Sstevel@tonic-gate { 16227c478bd9Sstevel@tonic-gate link_duplex_t link_duplex; 16237c478bd9Sstevel@tonic-gate char *duplex_str = "unknown"; 16247c478bd9Sstevel@tonic-gate 1625ba2e4443Sseb if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1626ba2e4443Sseb &link_duplex) != 0) { 16277c478bd9Sstevel@tonic-gate return (duplex_str); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate switch (link_duplex) { 16317c478bd9Sstevel@tonic-gate case LINK_DUPLEX_FULL: 16327c478bd9Sstevel@tonic-gate duplex_str = "full"; 16337c478bd9Sstevel@tonic-gate break; 16347c478bd9Sstevel@tonic-gate case LINK_DUPLEX_HALF: 16357c478bd9Sstevel@tonic-gate duplex_str = "half"; 16367c478bd9Sstevel@tonic-gate break; 16377c478bd9Sstevel@tonic-gate default: 16387c478bd9Sstevel@tonic-gate break; 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate return (duplex_str); 16427c478bd9Sstevel@tonic-gate } 16430ba2cbe9Sxc151355 16440ba2cbe9Sxc151355 #define WIFI_CMD_SCAN 0x00000001 16450ba2cbe9Sxc151355 #define WIFI_CMD_SHOW 0x00000002 16460ba2cbe9Sxc151355 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 16470ba2cbe9Sxc151355 typedef struct wifi_field { 16480ba2cbe9Sxc151355 const char *wf_name; 16490ba2cbe9Sxc151355 const char *wf_header; 16500ba2cbe9Sxc151355 uint_t wf_width; 16510ba2cbe9Sxc151355 uint_t wf_mask; 16520ba2cbe9Sxc151355 uint_t wf_cmdtype; 16530ba2cbe9Sxc151355 } wifi_field_t; 16540ba2cbe9Sxc151355 16550ba2cbe9Sxc151355 static wifi_field_t wifi_fields[] = { 16560ba2cbe9Sxc151355 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 16570ba2cbe9Sxc151355 { "essid", "ESSID", 19, WLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 16580ba2cbe9Sxc151355 { "bssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16590ba2cbe9Sxc151355 { "ibssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16600ba2cbe9Sxc151355 { "mode", "MODE", 6, WLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 16610ba2cbe9Sxc151355 { "speed", "SPEED", 6, WLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 1662*13994ee8Sxz162242 { "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 16630ba2cbe9Sxc151355 { "bsstype", "BSSTYPE", 8, WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 16640ba2cbe9Sxc151355 { "sec", "SEC", 6, WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 16650ba2cbe9Sxc151355 { "status", "STATUS", 17, WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW}, 16660ba2cbe9Sxc151355 { "strength", "STRENGTH", 10, WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 16670ba2cbe9Sxc151355 ; 16680ba2cbe9Sxc151355 16690ba2cbe9Sxc151355 static char *all_scan_wifi_fields = 1670*13994ee8Sxz162242 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 16710ba2cbe9Sxc151355 static char *all_show_wifi_fields = 16720ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 16730ba2cbe9Sxc151355 static char *def_scan_wifi_fields = 16740ba2cbe9Sxc151355 "link,essid,bssid,sec,strength,mode,speed"; 16750ba2cbe9Sxc151355 static char *def_show_wifi_fields = 16760ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed"; 16770ba2cbe9Sxc151355 16780ba2cbe9Sxc151355 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 16790ba2cbe9Sxc151355 #define WIFI_MAX_FIELD_LEN 32 16800ba2cbe9Sxc151355 16810ba2cbe9Sxc151355 typedef struct { 16820ba2cbe9Sxc151355 char *s_buf; 16830ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 16840ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 16850ba2cbe9Sxc151355 } split_t; 16860ba2cbe9Sxc151355 16870ba2cbe9Sxc151355 /* 16880ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 16890ba2cbe9Sxc151355 */ 16900ba2cbe9Sxc151355 static void 16910ba2cbe9Sxc151355 splitfree(split_t *sp) 16920ba2cbe9Sxc151355 { 16930ba2cbe9Sxc151355 free(sp->s_buf); 16940ba2cbe9Sxc151355 free(sp->s_fields); 16950ba2cbe9Sxc151355 free(sp); 16960ba2cbe9Sxc151355 } 16970ba2cbe9Sxc151355 16980ba2cbe9Sxc151355 /* 16990ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 17000ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 17010ba2cbe9Sxc151355 * on failure. 17020ba2cbe9Sxc151355 */ 17030ba2cbe9Sxc151355 static split_t * 17040ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 17050ba2cbe9Sxc151355 { 17060ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 17070ba2cbe9Sxc151355 split_t *sp; 17080ba2cbe9Sxc151355 17090ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 17100ba2cbe9Sxc151355 return (NULL); 17110ba2cbe9Sxc151355 17120ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 17130ba2cbe9Sxc151355 if (sp == NULL) 17140ba2cbe9Sxc151355 return (NULL); 17150ba2cbe9Sxc151355 17160ba2cbe9Sxc151355 sp->s_buf = strdup(str); 17170ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 17180ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 17190ba2cbe9Sxc151355 goto fail; 17200ba2cbe9Sxc151355 17210ba2cbe9Sxc151355 token = sp->s_buf; 17220ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 17230ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 17240ba2cbe9Sxc151355 goto fail; 17250ba2cbe9Sxc151355 token = NULL; 17260ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 17270ba2cbe9Sxc151355 } 17280ba2cbe9Sxc151355 return (sp); 17290ba2cbe9Sxc151355 fail: 17300ba2cbe9Sxc151355 splitfree(sp); 17310ba2cbe9Sxc151355 return (NULL); 17320ba2cbe9Sxc151355 } 17330ba2cbe9Sxc151355 17340ba2cbe9Sxc151355 static int 17350ba2cbe9Sxc151355 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 17360ba2cbe9Sxc151355 uint_t cmdtype) 17370ba2cbe9Sxc151355 { 17380ba2cbe9Sxc151355 uint_t i, j; 17390ba2cbe9Sxc151355 wifi_field_t **wf = NULL; 17400ba2cbe9Sxc151355 split_t *sp; 17410ba2cbe9Sxc151355 boolean_t good_match = B_FALSE; 17420ba2cbe9Sxc151355 17430ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 17440ba2cbe9Sxc151355 if (str == NULL) 17450ba2cbe9Sxc151355 str = def_scan_wifi_fields; 17460ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17470ba2cbe9Sxc151355 str = all_scan_wifi_fields; 17480ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 17490ba2cbe9Sxc151355 if (str == NULL) 17500ba2cbe9Sxc151355 str = def_show_wifi_fields; 17510ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17520ba2cbe9Sxc151355 str = all_show_wifi_fields; 17530ba2cbe9Sxc151355 } else { 17540ba2cbe9Sxc151355 return (-1); 17550ba2cbe9Sxc151355 } 17560ba2cbe9Sxc151355 17570ba2cbe9Sxc151355 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 17580ba2cbe9Sxc151355 if (sp == NULL) 17590ba2cbe9Sxc151355 return (-1); 17600ba2cbe9Sxc151355 17610ba2cbe9Sxc151355 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 17620ba2cbe9Sxc151355 if (wf == NULL) 17630ba2cbe9Sxc151355 goto fail; 17640ba2cbe9Sxc151355 17650ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 17660ba2cbe9Sxc151355 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 17670ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 17680ba2cbe9Sxc151355 wifi_fields[j].wf_name) == 0) { 1769*13994ee8Sxz162242 good_match = wifi_fields[j]. 17700ba2cbe9Sxc151355 wf_cmdtype & cmdtype; 17710ba2cbe9Sxc151355 break; 17720ba2cbe9Sxc151355 } 17730ba2cbe9Sxc151355 } 17740ba2cbe9Sxc151355 if (!good_match) 17750ba2cbe9Sxc151355 goto fail; 17760ba2cbe9Sxc151355 17770ba2cbe9Sxc151355 good_match = B_FALSE; 17780ba2cbe9Sxc151355 wf[i] = &wifi_fields[j]; 17790ba2cbe9Sxc151355 } 17800ba2cbe9Sxc151355 *countp = i; 17810ba2cbe9Sxc151355 *fields = wf; 17820ba2cbe9Sxc151355 splitfree(sp); 17830ba2cbe9Sxc151355 return (0); 17840ba2cbe9Sxc151355 fail: 17850ba2cbe9Sxc151355 free(wf); 17860ba2cbe9Sxc151355 splitfree(sp); 17870ba2cbe9Sxc151355 return (-1); 17880ba2cbe9Sxc151355 } 17890ba2cbe9Sxc151355 17900ba2cbe9Sxc151355 typedef struct print_wifi_state { 17910ba2cbe9Sxc151355 const char *ws_link; 17920ba2cbe9Sxc151355 boolean_t ws_parseable; 17930ba2cbe9Sxc151355 boolean_t ws_header; 17940ba2cbe9Sxc151355 wifi_field_t **ws_fields; 17950ba2cbe9Sxc151355 uint_t ws_nfields; 17960ba2cbe9Sxc151355 boolean_t ws_lastfield; 17970ba2cbe9Sxc151355 uint_t ws_overflow; 17980ba2cbe9Sxc151355 } print_wifi_state_t; 17990ba2cbe9Sxc151355 18000ba2cbe9Sxc151355 static void 18010ba2cbe9Sxc151355 print_wifi_head(print_wifi_state_t *statep) 18020ba2cbe9Sxc151355 { 18030ba2cbe9Sxc151355 int i; 18040ba2cbe9Sxc151355 wifi_field_t *wfp; 18050ba2cbe9Sxc151355 18060ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 18070ba2cbe9Sxc151355 wfp = statep->ws_fields[i]; 18080ba2cbe9Sxc151355 if (i + 1 < statep->ws_nfields) 18090ba2cbe9Sxc151355 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 18100ba2cbe9Sxc151355 else 18110ba2cbe9Sxc151355 (void) printf("%s", wfp->wf_header); 18120ba2cbe9Sxc151355 } 18130ba2cbe9Sxc151355 (void) printf("\n"); 18140ba2cbe9Sxc151355 } 18150ba2cbe9Sxc151355 18160ba2cbe9Sxc151355 static void 18170ba2cbe9Sxc151355 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 18180ba2cbe9Sxc151355 const char *value) 18190ba2cbe9Sxc151355 { 18200ba2cbe9Sxc151355 uint_t width = wfp->wf_width; 18210ba2cbe9Sxc151355 uint_t valwidth = strlen(value); 18220ba2cbe9Sxc151355 uint_t compress; 18230ba2cbe9Sxc151355 18240ba2cbe9Sxc151355 if (statep->ws_parseable) { 18250ba2cbe9Sxc151355 (void) printf("%s=\"%s\"", wfp->wf_header, value); 18260ba2cbe9Sxc151355 } else { 18270ba2cbe9Sxc151355 if (value[0] == '\0') 18280ba2cbe9Sxc151355 value = "--"; 18290ba2cbe9Sxc151355 if (statep->ws_lastfield) { 18300ba2cbe9Sxc151355 (void) printf("%s", value); 18310ba2cbe9Sxc151355 return; 18320ba2cbe9Sxc151355 } 18330ba2cbe9Sxc151355 18340ba2cbe9Sxc151355 if (valwidth > width) { 18350ba2cbe9Sxc151355 statep->ws_overflow += valwidth - width; 18360ba2cbe9Sxc151355 } else if (valwidth < width && statep->ws_overflow > 0) { 18370ba2cbe9Sxc151355 compress = min(statep->ws_overflow, width - valwidth); 18380ba2cbe9Sxc151355 statep->ws_overflow -= compress; 18390ba2cbe9Sxc151355 width -= compress; 18400ba2cbe9Sxc151355 } 18410ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 18420ba2cbe9Sxc151355 } 18430ba2cbe9Sxc151355 18440ba2cbe9Sxc151355 if (!statep->ws_lastfield) 18450ba2cbe9Sxc151355 (void) putchar(' '); 18460ba2cbe9Sxc151355 } 18470ba2cbe9Sxc151355 18480ba2cbe9Sxc151355 static void 18490ba2cbe9Sxc151355 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 18500ba2cbe9Sxc151355 wladm_wlan_attr_t *attrp) 18510ba2cbe9Sxc151355 { 18520ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 18530ba2cbe9Sxc151355 const char *str = ""; 18540ba2cbe9Sxc151355 18550ba2cbe9Sxc151355 if (wfp->wf_mask == 0) { 18560ba2cbe9Sxc151355 print_wifi_field(statep, wfp, statep->ws_link); 18570ba2cbe9Sxc151355 return; 18580ba2cbe9Sxc151355 } 18590ba2cbe9Sxc151355 18600ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 18610ba2cbe9Sxc151355 print_wifi_field(statep, wfp, ""); 18620ba2cbe9Sxc151355 return; 18630ba2cbe9Sxc151355 } 18640ba2cbe9Sxc151355 18650ba2cbe9Sxc151355 switch (wfp->wf_mask) { 18660ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_ESSID: 18670ba2cbe9Sxc151355 str = wladm_essid2str(&attrp->wa_essid, buf); 18680ba2cbe9Sxc151355 break; 18690ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSID: 18700ba2cbe9Sxc151355 str = wladm_bssid2str(&attrp->wa_bssid, buf); 18710ba2cbe9Sxc151355 break; 18720ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SECMODE: 18730ba2cbe9Sxc151355 str = wladm_secmode2str(&attrp->wa_secmode, buf); 18740ba2cbe9Sxc151355 break; 18750ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_STRENGTH: 18760ba2cbe9Sxc151355 str = wladm_strength2str(&attrp->wa_strength, buf); 18770ba2cbe9Sxc151355 break; 18780ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_MODE: 18790ba2cbe9Sxc151355 str = wladm_mode2str(&attrp->wa_mode, buf); 18800ba2cbe9Sxc151355 break; 18810ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SPEED: 18820ba2cbe9Sxc151355 str = wladm_speed2str(&attrp->wa_speed, buf); 18830ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 18840ba2cbe9Sxc151355 break; 18850ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_AUTH: 18860ba2cbe9Sxc151355 str = wladm_auth2str(&attrp->wa_auth, buf); 18870ba2cbe9Sxc151355 break; 18880ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSTYPE: 18890ba2cbe9Sxc151355 str = wladm_bsstype2str(&attrp->wa_bsstype, buf); 18900ba2cbe9Sxc151355 break; 18910ba2cbe9Sxc151355 } 18920ba2cbe9Sxc151355 18930ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 18940ba2cbe9Sxc151355 } 18950ba2cbe9Sxc151355 18960ba2cbe9Sxc151355 static boolean_t 18970ba2cbe9Sxc151355 print_scan_results(void *arg, wladm_wlan_attr_t *attrp) 18980ba2cbe9Sxc151355 { 18990ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19000ba2cbe9Sxc151355 int i; 19010ba2cbe9Sxc151355 19020ba2cbe9Sxc151355 if (statep->ws_header) { 19030ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19040ba2cbe9Sxc151355 if (!statep->ws_parseable) 19050ba2cbe9Sxc151355 print_wifi_head(statep); 19060ba2cbe9Sxc151355 } 19070ba2cbe9Sxc151355 19080ba2cbe9Sxc151355 statep->ws_overflow = 0; 19090ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19100ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19110ba2cbe9Sxc151355 print_wlan_attr(statep, statep->ws_fields[i], attrp); 19120ba2cbe9Sxc151355 } 19130ba2cbe9Sxc151355 (void) putchar('\n'); 19140ba2cbe9Sxc151355 return (B_TRUE); 19150ba2cbe9Sxc151355 } 19160ba2cbe9Sxc151355 19170ba2cbe9Sxc151355 static boolean_t 19180ba2cbe9Sxc151355 scan_wifi(void *arg, const char *link) 19190ba2cbe9Sxc151355 { 19200ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19210ba2cbe9Sxc151355 wladm_status_t status; 19220ba2cbe9Sxc151355 19230ba2cbe9Sxc151355 statep->ws_link = link; 19240ba2cbe9Sxc151355 status = wladm_scan(link, statep, print_scan_results); 192533343a97Smeem if (status != WLADM_STATUS_OK) 192633343a97Smeem die_wlerr(status, "cannot scan link '%s'", link); 192733343a97Smeem 19280ba2cbe9Sxc151355 return (B_TRUE); 19290ba2cbe9Sxc151355 } 19300ba2cbe9Sxc151355 19310ba2cbe9Sxc151355 static void 19320ba2cbe9Sxc151355 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 19330ba2cbe9Sxc151355 wladm_link_attr_t *attrp) 19340ba2cbe9Sxc151355 { 19350ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 19360ba2cbe9Sxc151355 const char *str = ""; 19370ba2cbe9Sxc151355 19380ba2cbe9Sxc151355 if (strcmp(wfp->wf_name, "status") == 0) { 19390ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->la_valid) != 0) 19400ba2cbe9Sxc151355 str = wladm_linkstatus2str(&attrp->la_status, buf); 19410ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 19420ba2cbe9Sxc151355 return; 19430ba2cbe9Sxc151355 } 19440ba2cbe9Sxc151355 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 19450ba2cbe9Sxc151355 } 19460ba2cbe9Sxc151355 19470ba2cbe9Sxc151355 static boolean_t 19480ba2cbe9Sxc151355 show_wifi(void *arg, const char *link) 19490ba2cbe9Sxc151355 { 19500ba2cbe9Sxc151355 int i; 19510ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19520ba2cbe9Sxc151355 wladm_link_attr_t attr; 19530ba2cbe9Sxc151355 wladm_status_t status; 19540ba2cbe9Sxc151355 19550ba2cbe9Sxc151355 status = wladm_get_link_attr(link, &attr); 195633343a97Smeem if (status != WLADM_STATUS_OK) 195733343a97Smeem die_wlerr(status, "cannot get link attributes for '%s'", link); 19580ba2cbe9Sxc151355 19590ba2cbe9Sxc151355 if (statep->ws_header) { 19600ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19610ba2cbe9Sxc151355 if (!statep->ws_parseable) 19620ba2cbe9Sxc151355 print_wifi_head(statep); 19630ba2cbe9Sxc151355 } 19640ba2cbe9Sxc151355 19650ba2cbe9Sxc151355 statep->ws_link = link; 19660ba2cbe9Sxc151355 statep->ws_overflow = 0; 19670ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19680ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19690ba2cbe9Sxc151355 print_link_attr(statep, statep->ws_fields[i], &attr); 19700ba2cbe9Sxc151355 } 19710ba2cbe9Sxc151355 (void) putchar('\n'); 19720ba2cbe9Sxc151355 return (B_TRUE); 19730ba2cbe9Sxc151355 } 19740ba2cbe9Sxc151355 19750ba2cbe9Sxc151355 static void 19760ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd) 19770ba2cbe9Sxc151355 { 19780ba2cbe9Sxc151355 int option; 19790ba2cbe9Sxc151355 char *fields_str = NULL; 19800ba2cbe9Sxc151355 wifi_field_t **fields; 19810ba2cbe9Sxc151355 boolean_t (*callback)(void *, const char *); 19820ba2cbe9Sxc151355 uint_t nfields; 19830ba2cbe9Sxc151355 print_wifi_state_t state; 19840ba2cbe9Sxc151355 wladm_status_t status; 19850ba2cbe9Sxc151355 19860ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 19870ba2cbe9Sxc151355 callback = scan_wifi; 19880ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 19890ba2cbe9Sxc151355 callback = show_wifi; 19900ba2cbe9Sxc151355 else 19910ba2cbe9Sxc151355 return; 19920ba2cbe9Sxc151355 19930ba2cbe9Sxc151355 state.ws_link = NULL; 19940ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 19950ba2cbe9Sxc151355 state.ws_header = B_TRUE; 19960ba2cbe9Sxc151355 opterr = 0; 19970ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 19980ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 19990ba2cbe9Sxc151355 switch (option) { 20000ba2cbe9Sxc151355 case 'o': 20010ba2cbe9Sxc151355 fields_str = optarg; 20020ba2cbe9Sxc151355 break; 20030ba2cbe9Sxc151355 case 'p': 20040ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 20050ba2cbe9Sxc151355 if (fields_str == NULL) 20060ba2cbe9Sxc151355 fields_str = "all"; 20070ba2cbe9Sxc151355 break; 20080ba2cbe9Sxc151355 default: 200933343a97Smeem die_opterr(optopt, option); 20100ba2cbe9Sxc151355 break; 20110ba2cbe9Sxc151355 } 20120ba2cbe9Sxc151355 } 20130ba2cbe9Sxc151355 20140ba2cbe9Sxc151355 if (optind == (argc - 1)) 20150ba2cbe9Sxc151355 state.ws_link = argv[optind]; 20160ba2cbe9Sxc151355 else if (optind != argc) 20170ba2cbe9Sxc151355 usage(); 20180ba2cbe9Sxc151355 201933343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 202033343a97Smeem die("invalid field(s) specified"); 202133343a97Smeem 20220ba2cbe9Sxc151355 state.ws_fields = fields; 20230ba2cbe9Sxc151355 state.ws_nfields = nfields; 20240ba2cbe9Sxc151355 20250ba2cbe9Sxc151355 if (state.ws_link == NULL) { 20260ba2cbe9Sxc151355 status = wladm_walk(&state, callback); 202733343a97Smeem if (status != WLADM_STATUS_OK) 202833343a97Smeem die_wlerr(status, "cannot walk wifi links"); 20290ba2cbe9Sxc151355 } else { 20300ba2cbe9Sxc151355 (void) (*callback)(&state, state.ws_link); 20310ba2cbe9Sxc151355 } 20320ba2cbe9Sxc151355 free(fields); 20330ba2cbe9Sxc151355 } 20340ba2cbe9Sxc151355 20350ba2cbe9Sxc151355 static void 20360ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv) 20370ba2cbe9Sxc151355 { 20380ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 20390ba2cbe9Sxc151355 } 20400ba2cbe9Sxc151355 20410ba2cbe9Sxc151355 static void 20420ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv) 20430ba2cbe9Sxc151355 { 20440ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 20450ba2cbe9Sxc151355 } 20460ba2cbe9Sxc151355 20470ba2cbe9Sxc151355 typedef struct wlan_count_attr { 20480ba2cbe9Sxc151355 uint_t wc_count; 20490ba2cbe9Sxc151355 const char *wc_link; 20500ba2cbe9Sxc151355 } wlan_count_attr_t; 20510ba2cbe9Sxc151355 20520ba2cbe9Sxc151355 static boolean_t 20530ba2cbe9Sxc151355 do_count_wlan(void *arg, const char *link) 20540ba2cbe9Sxc151355 { 205533343a97Smeem wlan_count_attr_t *cp = arg; 20560ba2cbe9Sxc151355 20570ba2cbe9Sxc151355 if (cp->wc_count == 0) 20580ba2cbe9Sxc151355 cp->wc_link = strdup(link); 20590ba2cbe9Sxc151355 cp->wc_count++; 20600ba2cbe9Sxc151355 return (B_TRUE); 20610ba2cbe9Sxc151355 } 20620ba2cbe9Sxc151355 20630ba2cbe9Sxc151355 static int 20640ba2cbe9Sxc151355 parse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp) 20650ba2cbe9Sxc151355 { 20660ba2cbe9Sxc151355 uint_t i; 20670ba2cbe9Sxc151355 split_t *sp; 20680ba2cbe9Sxc151355 wladm_wep_key_t *wk; 20690ba2cbe9Sxc151355 20700ba2cbe9Sxc151355 sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN); 20710ba2cbe9Sxc151355 if (sp == NULL) 20720ba2cbe9Sxc151355 return (-1); 20730ba2cbe9Sxc151355 20740ba2cbe9Sxc151355 wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t)); 20750ba2cbe9Sxc151355 if (wk == NULL) 20760ba2cbe9Sxc151355 goto fail; 20770ba2cbe9Sxc151355 20780ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 20790ba2cbe9Sxc151355 char *s; 20800ba2cbe9Sxc151355 dladm_secobj_class_t class; 20810ba2cbe9Sxc151355 dladm_status_t status; 20820ba2cbe9Sxc151355 20830ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 20840ba2cbe9Sxc151355 WLADM_MAX_WEPKEYNAME_LEN); 20850ba2cbe9Sxc151355 20860ba2cbe9Sxc151355 wk[i].wk_idx = 1; 20870ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 20880ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 20890ba2cbe9Sxc151355 goto fail; 20900ba2cbe9Sxc151355 20910ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 20920ba2cbe9Sxc151355 *s = '\0'; 20930ba2cbe9Sxc151355 } 20940ba2cbe9Sxc151355 wk[i].wk_len = WLADM_MAX_WEPKEY_LEN; 20950ba2cbe9Sxc151355 20960ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 20970ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 20980ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 20990ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 21000ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 21010ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 21020ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 21030ba2cbe9Sxc151355 } 21040ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 21050ba2cbe9Sxc151355 goto fail; 21060ba2cbe9Sxc151355 } 21070ba2cbe9Sxc151355 } 21080ba2cbe9Sxc151355 *keys = wk; 21090ba2cbe9Sxc151355 *key_countp = i; 21100ba2cbe9Sxc151355 splitfree(sp); 21110ba2cbe9Sxc151355 return (0); 21120ba2cbe9Sxc151355 fail: 21130ba2cbe9Sxc151355 free(wk); 21140ba2cbe9Sxc151355 splitfree(sp); 21150ba2cbe9Sxc151355 return (-1); 21160ba2cbe9Sxc151355 } 21170ba2cbe9Sxc151355 21180ba2cbe9Sxc151355 static void 21190ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv) 21200ba2cbe9Sxc151355 { 21210ba2cbe9Sxc151355 int option; 21220ba2cbe9Sxc151355 wladm_wlan_attr_t attr, *attrp; 21230ba2cbe9Sxc151355 wladm_status_t status = WLADM_STATUS_OK; 21240ba2cbe9Sxc151355 int timeout = WLADM_CONNECT_TIMEOUT_DEFAULT; 21250ba2cbe9Sxc151355 const char *link = NULL; 21260ba2cbe9Sxc151355 wladm_wep_key_t *keys = NULL; 21270ba2cbe9Sxc151355 uint_t key_count = 0; 21280ba2cbe9Sxc151355 uint_t flags = 0; 21290ba2cbe9Sxc151355 wladm_secmode_t keysecmode = WLADM_SECMODE_NONE; 21300ba2cbe9Sxc151355 21310ba2cbe9Sxc151355 opterr = 0; 21320ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 21330ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 21340ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 21350ba2cbe9Sxc151355 switch (option) { 21360ba2cbe9Sxc151355 case 'e': 21370ba2cbe9Sxc151355 status = wladm_str2essid(optarg, &attr.wa_essid); 213833343a97Smeem if (status != WLADM_STATUS_OK) 213933343a97Smeem die("invalid ESSID '%s'", optarg); 214033343a97Smeem 21410ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_ESSID; 21420ba2cbe9Sxc151355 /* 21430ba2cbe9Sxc151355 * Try to connect without doing a scan. 21440ba2cbe9Sxc151355 */ 21450ba2cbe9Sxc151355 flags |= WLADM_OPT_NOSCAN; 21460ba2cbe9Sxc151355 break; 21470ba2cbe9Sxc151355 case 'i': 21480ba2cbe9Sxc151355 status = wladm_str2bssid(optarg, &attr.wa_bssid); 214933343a97Smeem if (status != WLADM_STATUS_OK) 215033343a97Smeem die("invalid BSSID %s", optarg); 215133343a97Smeem 21520ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 21530ba2cbe9Sxc151355 break; 21540ba2cbe9Sxc151355 case 'a': 21550ba2cbe9Sxc151355 status = wladm_str2auth(optarg, &attr.wa_auth); 215633343a97Smeem if (status != WLADM_STATUS_OK) 215733343a97Smeem die("invalid authentication mode '%s'", optarg); 215833343a97Smeem 21590ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 21600ba2cbe9Sxc151355 break; 21610ba2cbe9Sxc151355 case 'm': 21620ba2cbe9Sxc151355 status = wladm_str2mode(optarg, &attr.wa_mode); 216333343a97Smeem if (status != WLADM_STATUS_OK) 216433343a97Smeem die("invalid mode '%s'", optarg); 216533343a97Smeem 21660ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 21670ba2cbe9Sxc151355 break; 21680ba2cbe9Sxc151355 case 'b': 21690ba2cbe9Sxc151355 status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 217033343a97Smeem if (status != WLADM_STATUS_OK) 217133343a97Smeem die("invalid bsstype '%s'", optarg); 217233343a97Smeem 21730ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 21740ba2cbe9Sxc151355 break; 21750ba2cbe9Sxc151355 case 's': 21760ba2cbe9Sxc151355 status = wladm_str2secmode(optarg, &attr.wa_secmode); 217733343a97Smeem if (status != WLADM_STATUS_OK) 217833343a97Smeem die("invalid security mode '%s'", optarg); 217933343a97Smeem 21800ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 21810ba2cbe9Sxc151355 break; 21820ba2cbe9Sxc151355 case 'k': 218333343a97Smeem if (parse_wep_keys(optarg, &keys, &key_count) < 0) 218433343a97Smeem die("invalid key(s) '%s'", optarg); 218533343a97Smeem 21860ba2cbe9Sxc151355 keysecmode = WLADM_SECMODE_WEP; 21870ba2cbe9Sxc151355 break; 21880ba2cbe9Sxc151355 case 'T': 21890ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 21900ba2cbe9Sxc151355 timeout = -1; 21910ba2cbe9Sxc151355 break; 21920ba2cbe9Sxc151355 } 219333343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 219433343a97Smeem die("invalid timeout value '%s'", optarg); 21950ba2cbe9Sxc151355 break; 21960ba2cbe9Sxc151355 case 'c': 21970ba2cbe9Sxc151355 flags |= WLADM_OPT_CREATEIBSS; 21980ba2cbe9Sxc151355 break; 21990ba2cbe9Sxc151355 default: 220033343a97Smeem die_opterr(optopt, option); 22010ba2cbe9Sxc151355 break; 22020ba2cbe9Sxc151355 } 22030ba2cbe9Sxc151355 } 22040ba2cbe9Sxc151355 22050ba2cbe9Sxc151355 if (keysecmode == WLADM_SECMODE_NONE) { 22060ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 220733343a97Smeem attr.wa_secmode == WLADM_SECMODE_WEP) 220833343a97Smeem die("key required for security mode 'wep'"); 22090ba2cbe9Sxc151355 } else { 22100ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 221133343a97Smeem attr.wa_secmode != keysecmode) 221233343a97Smeem die("incompatible -s and -k options"); 22130ba2cbe9Sxc151355 } 22140ba2cbe9Sxc151355 attr.wa_secmode = keysecmode; 22150ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 22160ba2cbe9Sxc151355 22170ba2cbe9Sxc151355 if (optind == (argc - 1)) 22180ba2cbe9Sxc151355 link = argv[optind]; 22190ba2cbe9Sxc151355 else if (optind != argc) 22200ba2cbe9Sxc151355 usage(); 22210ba2cbe9Sxc151355 22220ba2cbe9Sxc151355 if (link == NULL) { 22230ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22240ba2cbe9Sxc151355 22250ba2cbe9Sxc151355 wcattr.wc_link = NULL; 22260ba2cbe9Sxc151355 wcattr.wc_count = 0; 22270ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 22280ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 222933343a97Smeem die("no wifi links are available"); 22300ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 223133343a97Smeem die("link name is required when more than one wifi " 223233343a97Smeem "link is available"); 22330ba2cbe9Sxc151355 } 22340ba2cbe9Sxc151355 link = wcattr.wc_link; 22350ba2cbe9Sxc151355 } 22360ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 223733343a97Smeem again: 22380ba2cbe9Sxc151355 status = wladm_connect(link, attrp, timeout, keys, key_count, flags); 22390ba2cbe9Sxc151355 if (status != WLADM_STATUS_OK) { 22400ba2cbe9Sxc151355 if ((flags & WLADM_OPT_NOSCAN) != 0) { 22410ba2cbe9Sxc151355 /* 224233343a97Smeem * Try again with scanning and filtering. 22430ba2cbe9Sxc151355 */ 22440ba2cbe9Sxc151355 flags &= ~WLADM_OPT_NOSCAN; 224533343a97Smeem goto again; 22460ba2cbe9Sxc151355 } 224733343a97Smeem 22480ba2cbe9Sxc151355 if (status == WLADM_STATUS_NOTFOUND) { 22490ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 225033343a97Smeem die("no wifi networks are available"); 22510ba2cbe9Sxc151355 } else { 225233343a97Smeem die("no wifi networks with the specified " 225333343a97Smeem "criteria are available"); 22540ba2cbe9Sxc151355 } 22550ba2cbe9Sxc151355 } 2256*13994ee8Sxz162242 die_wlerr(status, "cannot connect link '%s'", link); 22570ba2cbe9Sxc151355 } 22580ba2cbe9Sxc151355 free(keys); 22590ba2cbe9Sxc151355 } 22600ba2cbe9Sxc151355 22610ba2cbe9Sxc151355 /* ARGSUSED */ 22620ba2cbe9Sxc151355 static boolean_t 22630ba2cbe9Sxc151355 do_all_disconnect_wifi(void *arg, const char *link) 22640ba2cbe9Sxc151355 { 22650ba2cbe9Sxc151355 wladm_status_t status; 22660ba2cbe9Sxc151355 22670ba2cbe9Sxc151355 status = wladm_disconnect(link); 226833343a97Smeem if (status != WLADM_STATUS_OK) 226933343a97Smeem warn_wlerr(status, "cannot disconnect link '%s'", link); 227033343a97Smeem 22710ba2cbe9Sxc151355 return (B_TRUE); 22720ba2cbe9Sxc151355 } 22730ba2cbe9Sxc151355 22740ba2cbe9Sxc151355 static void 22750ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv) 22760ba2cbe9Sxc151355 { 22770ba2cbe9Sxc151355 int option; 22780ba2cbe9Sxc151355 const char *link = NULL; 22790ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 22800ba2cbe9Sxc151355 wladm_status_t status; 22810ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22820ba2cbe9Sxc151355 22830ba2cbe9Sxc151355 opterr = 0; 22840ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 22850ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 22860ba2cbe9Sxc151355 switch (option) { 22870ba2cbe9Sxc151355 case 'a': 22880ba2cbe9Sxc151355 all_links = B_TRUE; 22890ba2cbe9Sxc151355 break; 22900ba2cbe9Sxc151355 default: 229133343a97Smeem die_opterr(optopt, option); 22920ba2cbe9Sxc151355 break; 22930ba2cbe9Sxc151355 } 22940ba2cbe9Sxc151355 } 22950ba2cbe9Sxc151355 22960ba2cbe9Sxc151355 if (optind == (argc - 1)) 22970ba2cbe9Sxc151355 link = argv[optind]; 22980ba2cbe9Sxc151355 else if (optind != argc) 22990ba2cbe9Sxc151355 usage(); 23000ba2cbe9Sxc151355 23010ba2cbe9Sxc151355 if (link == NULL) { 23020ba2cbe9Sxc151355 if (!all_links) { 23030ba2cbe9Sxc151355 wcattr.wc_link = NULL; 23040ba2cbe9Sxc151355 wcattr.wc_count = 0; 23050ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 23060ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 230733343a97Smeem die("no wifi links are available"); 23080ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 230933343a97Smeem die("link name is required when more than " 231033343a97Smeem "one wifi link is available"); 23110ba2cbe9Sxc151355 } 23120ba2cbe9Sxc151355 link = wcattr.wc_link; 23130ba2cbe9Sxc151355 } else { 23140ba2cbe9Sxc151355 (void) wladm_walk(&all_links, do_all_disconnect_wifi); 23150ba2cbe9Sxc151355 return; 23160ba2cbe9Sxc151355 } 23170ba2cbe9Sxc151355 } 23180ba2cbe9Sxc151355 status = wladm_disconnect(link); 231933343a97Smeem if (status != WLADM_STATUS_OK) 232033343a97Smeem die_wlerr(status, "cannot disconnect link '%s'", link); 23210ba2cbe9Sxc151355 } 23220ba2cbe9Sxc151355 23230ba2cbe9Sxc151355 #define MAX_PROPS 32 23240ba2cbe9Sxc151355 #define MAX_PROP_VALS 32 23250ba2cbe9Sxc151355 #define MAX_PROP_LINE 512 23260ba2cbe9Sxc151355 23270ba2cbe9Sxc151355 typedef struct prop_info { 23280ba2cbe9Sxc151355 char *pi_name; 23290ba2cbe9Sxc151355 char *pi_val[MAX_PROP_VALS]; 23300ba2cbe9Sxc151355 uint_t pi_count; 23310ba2cbe9Sxc151355 } prop_info_t; 23320ba2cbe9Sxc151355 23330ba2cbe9Sxc151355 typedef struct prop_list { 23340ba2cbe9Sxc151355 prop_info_t pl_info[MAX_PROPS]; 23350ba2cbe9Sxc151355 uint_t pl_count; 23360ba2cbe9Sxc151355 char *pl_buf; 23370ba2cbe9Sxc151355 } prop_list_t; 23380ba2cbe9Sxc151355 23390ba2cbe9Sxc151355 typedef struct show_linkprop_state { 23400ba2cbe9Sxc151355 const char *ls_link; 23410ba2cbe9Sxc151355 char *ls_line; 23420ba2cbe9Sxc151355 char **ls_propvals; 23430ba2cbe9Sxc151355 boolean_t ls_parseable; 23440ba2cbe9Sxc151355 boolean_t ls_persist; 23450ba2cbe9Sxc151355 boolean_t ls_header; 23460ba2cbe9Sxc151355 } show_linkprop_state_t; 23470ba2cbe9Sxc151355 23480ba2cbe9Sxc151355 static void 23490ba2cbe9Sxc151355 free_props(prop_list_t *list) 23500ba2cbe9Sxc151355 { 23510ba2cbe9Sxc151355 if (list != NULL) { 23520ba2cbe9Sxc151355 free(list->pl_buf); 23530ba2cbe9Sxc151355 free(list); 23540ba2cbe9Sxc151355 } 23550ba2cbe9Sxc151355 } 23560ba2cbe9Sxc151355 23570ba2cbe9Sxc151355 static int 23580ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 23590ba2cbe9Sxc151355 { 23600ba2cbe9Sxc151355 prop_list_t *list; 23610ba2cbe9Sxc151355 prop_info_t *pip; 23620ba2cbe9Sxc151355 char *buf, *curr; 23630ba2cbe9Sxc151355 int len, i; 23640ba2cbe9Sxc151355 23650ba2cbe9Sxc151355 list = malloc(sizeof (prop_list_t)); 23660ba2cbe9Sxc151355 if (list == NULL) 23670ba2cbe9Sxc151355 return (-1); 23680ba2cbe9Sxc151355 23690ba2cbe9Sxc151355 list->pl_count = 0; 23700ba2cbe9Sxc151355 list->pl_buf = buf = strdup(str); 23710ba2cbe9Sxc151355 if (buf == NULL) 23720ba2cbe9Sxc151355 goto fail; 23730ba2cbe9Sxc151355 23740ba2cbe9Sxc151355 curr = buf; 23750ba2cbe9Sxc151355 len = strlen(buf); 23760ba2cbe9Sxc151355 pip = NULL; 23770ba2cbe9Sxc151355 for (i = 0; i < len; i++) { 23780ba2cbe9Sxc151355 char c = buf[i]; 23790ba2cbe9Sxc151355 boolean_t match = (c == '=' || c == ','); 23800ba2cbe9Sxc151355 23810ba2cbe9Sxc151355 if (!match && i != len - 1) 23820ba2cbe9Sxc151355 continue; 23830ba2cbe9Sxc151355 23840ba2cbe9Sxc151355 if (match) { 23850ba2cbe9Sxc151355 buf[i] = '\0'; 23860ba2cbe9Sxc151355 if (*curr == '\0') 23870ba2cbe9Sxc151355 goto fail; 23880ba2cbe9Sxc151355 } 23890ba2cbe9Sxc151355 23900ba2cbe9Sxc151355 if (pip != NULL && c != '=') { 23910ba2cbe9Sxc151355 if (pip->pi_count > MAX_PROP_VALS) 23920ba2cbe9Sxc151355 goto fail; 23930ba2cbe9Sxc151355 23940ba2cbe9Sxc151355 if (novalues) 23950ba2cbe9Sxc151355 goto fail; 23960ba2cbe9Sxc151355 23970ba2cbe9Sxc151355 pip->pi_val[pip->pi_count] = curr; 23980ba2cbe9Sxc151355 pip->pi_count++; 23990ba2cbe9Sxc151355 } else { 24000ba2cbe9Sxc151355 if (list->pl_count > MAX_PROPS) 24010ba2cbe9Sxc151355 goto fail; 24020ba2cbe9Sxc151355 24030ba2cbe9Sxc151355 pip = &list->pl_info[list->pl_count]; 24040ba2cbe9Sxc151355 pip->pi_name = curr; 24050ba2cbe9Sxc151355 pip->pi_count = 0; 24060ba2cbe9Sxc151355 list->pl_count++; 24070ba2cbe9Sxc151355 if (c == ',') 24080ba2cbe9Sxc151355 pip = NULL; 24090ba2cbe9Sxc151355 } 24100ba2cbe9Sxc151355 curr = buf + i + 1; 24110ba2cbe9Sxc151355 } 24120ba2cbe9Sxc151355 *listp = list; 24130ba2cbe9Sxc151355 return (0); 24140ba2cbe9Sxc151355 24150ba2cbe9Sxc151355 fail: 24160ba2cbe9Sxc151355 free_props(list); 24170ba2cbe9Sxc151355 return (-1); 24180ba2cbe9Sxc151355 } 24190ba2cbe9Sxc151355 24200ba2cbe9Sxc151355 static void 24210ba2cbe9Sxc151355 print_linkprop_head(void) 24220ba2cbe9Sxc151355 { 24230ba2cbe9Sxc151355 (void) printf("%-15s %-14s %-14s %-30s \n", 24240ba2cbe9Sxc151355 "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 24250ba2cbe9Sxc151355 } 24260ba2cbe9Sxc151355 24270ba2cbe9Sxc151355 static void 24280ba2cbe9Sxc151355 print_linkprop(show_linkprop_state_t *statep, const char *propname, 24290ba2cbe9Sxc151355 dladm_prop_type_t type, const char *typename, const char *format, 24300ba2cbe9Sxc151355 char **pptr) 24310ba2cbe9Sxc151355 { 24320ba2cbe9Sxc151355 int i; 24330ba2cbe9Sxc151355 char *ptr, *lim; 24340ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 24350ba2cbe9Sxc151355 char *unknown = "?", *notsup = ""; 24360ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 24370ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 24380ba2cbe9Sxc151355 dladm_status_t status; 24390ba2cbe9Sxc151355 24400ba2cbe9Sxc151355 status = dladm_get_prop(statep->ls_link, type, propname, 24410ba2cbe9Sxc151355 propvals, &valcnt); 24420ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 24430ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) { 24440ba2cbe9Sxc151355 valcnt = 1; 24450ba2cbe9Sxc151355 if (type == DLADM_PROP_VAL_CURRENT) 24460ba2cbe9Sxc151355 propvals = &unknown; 24470ba2cbe9Sxc151355 else 24480ba2cbe9Sxc151355 propvals = ¬sup; 24490ba2cbe9Sxc151355 } else { 245033343a97Smeem die_dlerr(status, "cannot get link property '%s'", 245133343a97Smeem propname); 24520ba2cbe9Sxc151355 } 24530ba2cbe9Sxc151355 } 24540ba2cbe9Sxc151355 24550ba2cbe9Sxc151355 ptr = buf; 24560ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 24570ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 24580ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 24590ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "--,"); 24600ba2cbe9Sxc151355 else 24610ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 24620ba2cbe9Sxc151355 if (ptr >= lim) 24630ba2cbe9Sxc151355 break; 24640ba2cbe9Sxc151355 } 24650ba2cbe9Sxc151355 if (valcnt > 0) 24660ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 24670ba2cbe9Sxc151355 24680ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 24690ba2cbe9Sxc151355 if (statep->ls_parseable) { 24700ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 24710ba2cbe9Sxc151355 "%s=\"%s\" ", typename, buf); 24720ba2cbe9Sxc151355 } else { 24730ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 24740ba2cbe9Sxc151355 } 24750ba2cbe9Sxc151355 } 24760ba2cbe9Sxc151355 24770ba2cbe9Sxc151355 static boolean_t 24780ba2cbe9Sxc151355 show_linkprop(void *arg, const char *propname) 24790ba2cbe9Sxc151355 { 24800ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 24810ba2cbe9Sxc151355 char *ptr = statep->ls_line; 24820ba2cbe9Sxc151355 char *lim = ptr + MAX_PROP_LINE; 24830ba2cbe9Sxc151355 24840ba2cbe9Sxc151355 if (statep->ls_parseable) 24850ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 24860ba2cbe9Sxc151355 else 24870ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 24880ba2cbe9Sxc151355 24890ba2cbe9Sxc151355 print_linkprop(statep, propname, 24900ba2cbe9Sxc151355 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 24910ba2cbe9Sxc151355 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 24920ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 24930ba2cbe9Sxc151355 "DEFAULT", "%-14s ", &ptr); 24940ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 24950ba2cbe9Sxc151355 "POSSIBLE", "%-30s ", &ptr); 24960ba2cbe9Sxc151355 24970ba2cbe9Sxc151355 if (statep->ls_header) { 24980ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 24990ba2cbe9Sxc151355 if (!statep->ls_parseable) 25000ba2cbe9Sxc151355 print_linkprop_head(); 25010ba2cbe9Sxc151355 } 25020ba2cbe9Sxc151355 (void) printf("%s\n", statep->ls_line); 25030ba2cbe9Sxc151355 return (B_TRUE); 25040ba2cbe9Sxc151355 } 25050ba2cbe9Sxc151355 25060ba2cbe9Sxc151355 static void 25070ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv) 25080ba2cbe9Sxc151355 { 25090ba2cbe9Sxc151355 int i, option, fd; 25100ba2cbe9Sxc151355 char linkname[MAXPATHLEN]; 25110ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 25120ba2cbe9Sxc151355 char *buf; 25130ba2cbe9Sxc151355 dladm_status_t status; 25140ba2cbe9Sxc151355 show_linkprop_state_t state; 25150ba2cbe9Sxc151355 25160ba2cbe9Sxc151355 opterr = 0; 25170ba2cbe9Sxc151355 state.ls_link = NULL; 25180ba2cbe9Sxc151355 state.ls_propvals = NULL; 25190ba2cbe9Sxc151355 state.ls_line = NULL; 25200ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 25210ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 25220ba2cbe9Sxc151355 state.ls_header = B_TRUE; 25230ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:cP", 25240ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 25250ba2cbe9Sxc151355 switch (option) { 25260ba2cbe9Sxc151355 case 'p': 252733343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 2528*13994ee8Sxz162242 die("invalid link properties specified"); 25290ba2cbe9Sxc151355 break; 25300ba2cbe9Sxc151355 case 'c': 25310ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 25320ba2cbe9Sxc151355 break; 25330ba2cbe9Sxc151355 case 'P': 25340ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 25350ba2cbe9Sxc151355 break; 25360ba2cbe9Sxc151355 default: 253733343a97Smeem die_opterr(optopt, option); 25380ba2cbe9Sxc151355 break; 25390ba2cbe9Sxc151355 } 25400ba2cbe9Sxc151355 } 25410ba2cbe9Sxc151355 25420ba2cbe9Sxc151355 if (optind == (argc - 1)) 25430ba2cbe9Sxc151355 state.ls_link = argv[optind]; 25440ba2cbe9Sxc151355 else if (optind != argc) 25450ba2cbe9Sxc151355 usage(); 25460ba2cbe9Sxc151355 254733343a97Smeem if (state.ls_link == NULL) 254833343a97Smeem die("link name must be specified"); 25490ba2cbe9Sxc151355 25500ba2cbe9Sxc151355 /* 25510ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 25520ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 25530ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 25540ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 25550ba2cbe9Sxc151355 */ 25560ba2cbe9Sxc151355 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", state.ls_link); 255733343a97Smeem if ((fd = open(linkname, O_RDWR)) < 0) 255833343a97Smeem die("cannot open %s: %s", state.ls_link, strerror(errno)); 25590ba2cbe9Sxc151355 25600ba2cbe9Sxc151355 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 25610ba2cbe9Sxc151355 MAX_PROP_LINE); 256233343a97Smeem if (buf == NULL) 256333343a97Smeem die("insufficient memory"); 256433343a97Smeem 25650ba2cbe9Sxc151355 state.ls_propvals = (char **)(void *)buf; 25660ba2cbe9Sxc151355 for (i = 0; i < MAX_PROP_VALS; i++) { 25670ba2cbe9Sxc151355 state.ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 25680ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 25690ba2cbe9Sxc151355 } 25700ba2cbe9Sxc151355 state.ls_line = buf + 25710ba2cbe9Sxc151355 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 25720ba2cbe9Sxc151355 25730ba2cbe9Sxc151355 if (proplist != NULL) { 25740ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 25750ba2cbe9Sxc151355 if (!show_linkprop(&state, 25760ba2cbe9Sxc151355 proplist->pl_info[i].pi_name)) 25770ba2cbe9Sxc151355 break; 25780ba2cbe9Sxc151355 } 25790ba2cbe9Sxc151355 } else { 25800ba2cbe9Sxc151355 status = dladm_walk_prop(state.ls_link, &state, show_linkprop); 258133343a97Smeem if (status != DLADM_STATUS_OK) 258233343a97Smeem die_dlerr(status, "show-linkprop"); 25830ba2cbe9Sxc151355 } 25840ba2cbe9Sxc151355 (void) close(fd); 25850ba2cbe9Sxc151355 free(buf); 25860ba2cbe9Sxc151355 free_props(proplist); 25870ba2cbe9Sxc151355 } 25880ba2cbe9Sxc151355 25890ba2cbe9Sxc151355 static dladm_status_t 25900ba2cbe9Sxc151355 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 25910ba2cbe9Sxc151355 uint_t val_cnt, boolean_t reset) 25920ba2cbe9Sxc151355 { 25930ba2cbe9Sxc151355 dladm_status_t status; 25940ba2cbe9Sxc151355 25950ba2cbe9Sxc151355 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 25960ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 25970ba2cbe9Sxc151355 25980ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 25990ba2cbe9Sxc151355 if (reset) { 260033343a97Smeem warn_dlerr(status, "cannot persistently reset link " 260133343a97Smeem "property '%s' on '%s'", prop_name, link); 26020ba2cbe9Sxc151355 } else { 260333343a97Smeem warn_dlerr(status, "cannot persistently set link " 260433343a97Smeem "property '%s' on '%s'", prop_name, link); 26050ba2cbe9Sxc151355 } 26060ba2cbe9Sxc151355 } 26070ba2cbe9Sxc151355 return (status); 26080ba2cbe9Sxc151355 } 26090ba2cbe9Sxc151355 26100ba2cbe9Sxc151355 static void 26110ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset) 26120ba2cbe9Sxc151355 { 26130ba2cbe9Sxc151355 int i, option; 26140ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 26150ba2cbe9Sxc151355 const char *link = NULL; 26160ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 26170ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 26180ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 26190ba2cbe9Sxc151355 26200ba2cbe9Sxc151355 opterr = 0; 26210ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 26220ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 26230ba2cbe9Sxc151355 switch (option) { 26240ba2cbe9Sxc151355 case 'p': 262533343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 262633343a97Smeem die("invalid link properties specified"); 26270ba2cbe9Sxc151355 break; 26280ba2cbe9Sxc151355 case 't': 26290ba2cbe9Sxc151355 temp = B_TRUE; 26300ba2cbe9Sxc151355 break; 26310ba2cbe9Sxc151355 case 'R': 26320ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 26330ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 263433343a97Smeem die_dlerr(status, "invalid directory " 263533343a97Smeem "specified"); 26360ba2cbe9Sxc151355 } 26370ba2cbe9Sxc151355 break; 26380ba2cbe9Sxc151355 default: 263933343a97Smeem die_opterr(optopt, option); 26400ba2cbe9Sxc151355 break; 26410ba2cbe9Sxc151355 } 26420ba2cbe9Sxc151355 } 26430ba2cbe9Sxc151355 26440ba2cbe9Sxc151355 if (optind == (argc - 1)) 26450ba2cbe9Sxc151355 link = argv[optind]; 26460ba2cbe9Sxc151355 else if (optind != argc) 26470ba2cbe9Sxc151355 usage(); 26480ba2cbe9Sxc151355 264933343a97Smeem if (link == NULL) 265033343a97Smeem die("link name must be specified"); 26510ba2cbe9Sxc151355 2652dbc95d79Sxz162242 if (proplist == NULL) { 2653dbc95d79Sxz162242 if (!reset) 265433343a97Smeem die("link property must be specified"); 265533343a97Smeem 26560ba2cbe9Sxc151355 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP); 26570ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 265833343a97Smeem warn_dlerr(status, "cannot reset link properties " 265933343a97Smeem "on '%s'", link); 26600ba2cbe9Sxc151355 } 26610ba2cbe9Sxc151355 if (!temp) { 2662*13994ee8Sxz162242 dladm_status_t s; 2663*13994ee8Sxz162242 2664*13994ee8Sxz162242 s = set_linkprop_persist(link, NULL, NULL, 0, reset); 2665*13994ee8Sxz162242 if (s != DLADM_STATUS_OK) 2666*13994ee8Sxz162242 status = s; 26670ba2cbe9Sxc151355 } 26680ba2cbe9Sxc151355 goto done; 26690ba2cbe9Sxc151355 } 26700ba2cbe9Sxc151355 26710ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 26720ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 26730ba2cbe9Sxc151355 char **val; 26740ba2cbe9Sxc151355 uint_t count; 26750ba2cbe9Sxc151355 dladm_status_t s; 26760ba2cbe9Sxc151355 26770ba2cbe9Sxc151355 if (reset) { 26780ba2cbe9Sxc151355 val = NULL; 26790ba2cbe9Sxc151355 count = 0; 26800ba2cbe9Sxc151355 } else { 26810ba2cbe9Sxc151355 val = pip->pi_val; 26820ba2cbe9Sxc151355 count = pip->pi_count; 26830ba2cbe9Sxc151355 if (count == 0) { 268433343a97Smeem warn("no value specified for '%s'", 268533343a97Smeem pip->pi_name); 26860ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 26870ba2cbe9Sxc151355 continue; 26880ba2cbe9Sxc151355 } 26890ba2cbe9Sxc151355 } 26900ba2cbe9Sxc151355 s = dladm_set_prop(link, pip->pi_name, val, count, 26910ba2cbe9Sxc151355 DLADM_OPT_TEMP); 26920ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 26930ba2cbe9Sxc151355 if (!temp) { 26940ba2cbe9Sxc151355 s = set_linkprop_persist(link, 26950ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 26960ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 26970ba2cbe9Sxc151355 status = s; 26980ba2cbe9Sxc151355 } 26990ba2cbe9Sxc151355 continue; 27000ba2cbe9Sxc151355 } 27010ba2cbe9Sxc151355 status = s; 27020ba2cbe9Sxc151355 switch (s) { 27030ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 270433343a97Smeem warn("invalid link property '%s'", pip->pi_name); 27050ba2cbe9Sxc151355 break; 27060ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 27070ba2cbe9Sxc151355 int j; 27080ba2cbe9Sxc151355 char *ptr, *lim; 27090ba2cbe9Sxc151355 char **propvals = NULL; 27100ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 27110ba2cbe9Sxc151355 27120ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 27130ba2cbe9Sxc151355 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 27140ba2cbe9Sxc151355 MAX_PROP_LINE); 27150ba2cbe9Sxc151355 27160ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 271733343a97Smeem if (propvals == NULL) 271833343a97Smeem die("insufficient memory"); 271933343a97Smeem 27200ba2cbe9Sxc151355 for (j = 0; j < MAX_PROP_VALS; j++) { 27210ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 27220ba2cbe9Sxc151355 MAX_PROP_VALS + 27230ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 27240ba2cbe9Sxc151355 } 27250ba2cbe9Sxc151355 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 27260ba2cbe9Sxc151355 pip->pi_name, propvals, &valcnt); 27270ba2cbe9Sxc151355 27280ba2cbe9Sxc151355 ptr = errmsg; 27290ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 27300ba2cbe9Sxc151355 *ptr = '\0'; 27310ba2cbe9Sxc151355 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 27320ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 27330ba2cbe9Sxc151355 propvals[j]); 27340ba2cbe9Sxc151355 if (ptr >= lim) 27350ba2cbe9Sxc151355 break; 27360ba2cbe9Sxc151355 } 27370ba2cbe9Sxc151355 if (ptr > errmsg) 27380ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 273933343a97Smeem warn("link property '%s' must be one of: %s", 274033343a97Smeem pip->pi_name, errmsg); 27410ba2cbe9Sxc151355 free(propvals); 27420ba2cbe9Sxc151355 break; 27430ba2cbe9Sxc151355 } 27440ba2cbe9Sxc151355 default: 27450ba2cbe9Sxc151355 if (reset) { 274633343a97Smeem warn_dlerr(status, "cannot reset link property " 274733343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27480ba2cbe9Sxc151355 } else { 274933343a97Smeem warn_dlerr(status, "cannot set link property " 275033343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27510ba2cbe9Sxc151355 } 27520ba2cbe9Sxc151355 break; 27530ba2cbe9Sxc151355 } 27540ba2cbe9Sxc151355 } 27550ba2cbe9Sxc151355 done: 27560ba2cbe9Sxc151355 free_props(proplist); 27570ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 27580ba2cbe9Sxc151355 exit(1); 27590ba2cbe9Sxc151355 } 27600ba2cbe9Sxc151355 27610ba2cbe9Sxc151355 static void 27620ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 27630ba2cbe9Sxc151355 { 27640ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 27650ba2cbe9Sxc151355 } 27660ba2cbe9Sxc151355 27670ba2cbe9Sxc151355 static void 27680ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 27690ba2cbe9Sxc151355 { 27700ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 27710ba2cbe9Sxc151355 } 27720ba2cbe9Sxc151355 27730ba2cbe9Sxc151355 static int 27740ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 27750ba2cbe9Sxc151355 dladm_secobj_class_t class) 27760ba2cbe9Sxc151355 { 27770ba2cbe9Sxc151355 int error = 0; 27780ba2cbe9Sxc151355 27790ba2cbe9Sxc151355 if (class != DLADM_SECOBJ_CLASS_WEP) 27800ba2cbe9Sxc151355 return (ENOENT); 27810ba2cbe9Sxc151355 27820ba2cbe9Sxc151355 switch (len) { 27830ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 27840ba2cbe9Sxc151355 case 13: 27850ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 27860ba2cbe9Sxc151355 *obj_lenp = len; 27870ba2cbe9Sxc151355 break; 27880ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 27890ba2cbe9Sxc151355 case 26: 27900ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 27910ba2cbe9Sxc151355 break; 27920ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 27930ba2cbe9Sxc151355 case 28: 27940ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 27950ba2cbe9Sxc151355 return (EINVAL); 27960ba2cbe9Sxc151355 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 27970ba2cbe9Sxc151355 break; 27980ba2cbe9Sxc151355 default: 27990ba2cbe9Sxc151355 return (EINVAL); 28000ba2cbe9Sxc151355 } 28010ba2cbe9Sxc151355 return (error); 28020ba2cbe9Sxc151355 } 28030ba2cbe9Sxc151355 28040ba2cbe9Sxc151355 /* ARGSUSED */ 28050ba2cbe9Sxc151355 static void 28060ba2cbe9Sxc151355 defersig(int sig) 28070ba2cbe9Sxc151355 { 28080ba2cbe9Sxc151355 signalled = sig; 28090ba2cbe9Sxc151355 } 28100ba2cbe9Sxc151355 28110ba2cbe9Sxc151355 static int 28120ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 28130ba2cbe9Sxc151355 { 28140ba2cbe9Sxc151355 uint_t len = 0; 28150ba2cbe9Sxc151355 int c; 28160ba2cbe9Sxc151355 struct termios stored, current; 28170ba2cbe9Sxc151355 void (*sigfunc)(int); 28180ba2cbe9Sxc151355 28190ba2cbe9Sxc151355 /* 28200ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 28210ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 28220ba2cbe9Sxc151355 */ 28230ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 28240ba2cbe9Sxc151355 (void) fflush(stdin); 28250ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 28260ba2cbe9Sxc151355 current = stored; 28270ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 28280ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 28290ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 28300ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 28310ba2cbe9Sxc151355 again: 28320ba2cbe9Sxc151355 if (try == 1) 28330ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 28340ba2cbe9Sxc151355 else 28350ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 28360ba2cbe9Sxc151355 28370ba2cbe9Sxc151355 (void) fflush(stdout); 28380ba2cbe9Sxc151355 while (signalled == 0) { 28390ba2cbe9Sxc151355 c = getchar(); 28400ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 28410ba2cbe9Sxc151355 if (len != 0) 28420ba2cbe9Sxc151355 break; 28430ba2cbe9Sxc151355 (void) putchar('\n'); 28440ba2cbe9Sxc151355 goto again; 28450ba2cbe9Sxc151355 } 28460ba2cbe9Sxc151355 28470ba2cbe9Sxc151355 buf[len++] = c; 28480ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 28490ba2cbe9Sxc151355 break; 28500ba2cbe9Sxc151355 (void) putchar('*'); 28510ba2cbe9Sxc151355 } 28520ba2cbe9Sxc151355 28530ba2cbe9Sxc151355 (void) putchar('\n'); 28540ba2cbe9Sxc151355 (void) fflush(stdin); 28550ba2cbe9Sxc151355 28560ba2cbe9Sxc151355 /* 28570ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 28580ba2cbe9Sxc151355 */ 28590ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 28600ba2cbe9Sxc151355 28610ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 28620ba2cbe9Sxc151355 if (signalled != 0) 28630ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 28640ba2cbe9Sxc151355 28650ba2cbe9Sxc151355 return (len); 28660ba2cbe9Sxc151355 } 28670ba2cbe9Sxc151355 28680ba2cbe9Sxc151355 static int 28690ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 28700ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 28710ba2cbe9Sxc151355 { 28720ba2cbe9Sxc151355 int rval; 28730ba2cbe9Sxc151355 uint_t len, len2; 28740ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 28750ba2cbe9Sxc151355 28760ba2cbe9Sxc151355 if (filep == NULL) { 28770ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 28780ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 28790ba2cbe9Sxc151355 if (rval == 0) { 28800ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 28810ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 28820ba2cbe9Sxc151355 rval = ENOTSUP; 28830ba2cbe9Sxc151355 } 28840ba2cbe9Sxc151355 return (rval); 28850ba2cbe9Sxc151355 } else { 28860ba2cbe9Sxc151355 for (;;) { 28870ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 28880ba2cbe9Sxc151355 break; 28890ba2cbe9Sxc151355 if (isspace(buf[0])) 28900ba2cbe9Sxc151355 continue; 28910ba2cbe9Sxc151355 28920ba2cbe9Sxc151355 len = strlen(buf); 28930ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 28940ba2cbe9Sxc151355 buf[len - 1] = '\0'; 28950ba2cbe9Sxc151355 len--; 28960ba2cbe9Sxc151355 } 28970ba2cbe9Sxc151355 break; 28980ba2cbe9Sxc151355 } 28990ba2cbe9Sxc151355 (void) fclose(filep); 29000ba2cbe9Sxc151355 } 29010ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 29020ba2cbe9Sxc151355 } 29030ba2cbe9Sxc151355 29040ba2cbe9Sxc151355 static boolean_t 29050ba2cbe9Sxc151355 check_auth(const char *auth) 29060ba2cbe9Sxc151355 { 29070ba2cbe9Sxc151355 struct passwd *pw; 29080ba2cbe9Sxc151355 29090ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 29100ba2cbe9Sxc151355 return (B_FALSE); 29110ba2cbe9Sxc151355 29120ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 29130ba2cbe9Sxc151355 } 29140ba2cbe9Sxc151355 29150ba2cbe9Sxc151355 static void 29160ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 29170ba2cbe9Sxc151355 boolean_t success, boolean_t create) 29180ba2cbe9Sxc151355 { 29190ba2cbe9Sxc151355 adt_session_data_t *ah; 29200ba2cbe9Sxc151355 adt_event_data_t *event; 29210ba2cbe9Sxc151355 au_event_t flag; 29220ba2cbe9Sxc151355 char *errstr; 29230ba2cbe9Sxc151355 29240ba2cbe9Sxc151355 if (create) { 29250ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 29260ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 29270ba2cbe9Sxc151355 } else { 29280ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 29290ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 29300ba2cbe9Sxc151355 } 29310ba2cbe9Sxc151355 293233343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 293333343a97Smeem die("adt_start_session: %s", strerror(errno)); 29340ba2cbe9Sxc151355 293533343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 293633343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 29370ba2cbe9Sxc151355 29380ba2cbe9Sxc151355 /* fill in audit info */ 29390ba2cbe9Sxc151355 if (create) { 29400ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 29410ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 29420ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 29430ba2cbe9Sxc151355 } else { 29440ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 29450ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 29460ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 29470ba2cbe9Sxc151355 } 29480ba2cbe9Sxc151355 29490ba2cbe9Sxc151355 if (success) { 29500ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 295133343a97Smeem die("adt_put_event (%s, success): %s", errstr, 295233343a97Smeem strerror(errno)); 29530ba2cbe9Sxc151355 } 29540ba2cbe9Sxc151355 } else { 29550ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 29560ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 295733343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 295833343a97Smeem strerror(errno)); 29590ba2cbe9Sxc151355 } 29600ba2cbe9Sxc151355 } 29610ba2cbe9Sxc151355 29620ba2cbe9Sxc151355 adt_free_event(event); 29630ba2cbe9Sxc151355 (void) adt_end_session(ah); 29640ba2cbe9Sxc151355 } 29650ba2cbe9Sxc151355 29660ba2cbe9Sxc151355 #define MAX_SECOBJS 32 29670ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 29680ba2cbe9Sxc151355 static void 29690ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 29700ba2cbe9Sxc151355 { 29710ba2cbe9Sxc151355 int option, rval; 29720ba2cbe9Sxc151355 FILE *filep = NULL; 29730ba2cbe9Sxc151355 char *obj_name = NULL; 29740ba2cbe9Sxc151355 char *class_name = NULL; 29750ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 29760ba2cbe9Sxc151355 uint_t obj_len; 29770ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 29780ba2cbe9Sxc151355 dladm_status_t status; 29790ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 29800ba2cbe9Sxc151355 uid_t euid; 29810ba2cbe9Sxc151355 29820ba2cbe9Sxc151355 opterr = 0; 29830ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 29840ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 29850ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 29860ba2cbe9Sxc151355 switch (option) { 29870ba2cbe9Sxc151355 case 'f': 29880ba2cbe9Sxc151355 euid = geteuid(); 29890ba2cbe9Sxc151355 (void) seteuid(getuid()); 29900ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 29910ba2cbe9Sxc151355 if (filep == NULL) { 299233343a97Smeem die("cannot open %s: %s", optarg, 299333343a97Smeem strerror(errno)); 29940ba2cbe9Sxc151355 } 29950ba2cbe9Sxc151355 (void) seteuid(euid); 29960ba2cbe9Sxc151355 break; 29970ba2cbe9Sxc151355 case 'c': 29980ba2cbe9Sxc151355 class_name = optarg; 29990ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 30000ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 300133343a97Smeem die("invalid secure object class '%s', " 300233343a97Smeem "valid values are: wep", optarg); 30030ba2cbe9Sxc151355 } 30040ba2cbe9Sxc151355 break; 30050ba2cbe9Sxc151355 case 't': 30060ba2cbe9Sxc151355 temp = B_TRUE; 30070ba2cbe9Sxc151355 break; 30080ba2cbe9Sxc151355 case 'R': 30090ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30100ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 301133343a97Smeem die_dlerr(status, "invalid directory " 301233343a97Smeem "specified"); 30130ba2cbe9Sxc151355 } 30140ba2cbe9Sxc151355 break; 30150ba2cbe9Sxc151355 default: 301633343a97Smeem die_opterr(optopt, option); 30170ba2cbe9Sxc151355 break; 30180ba2cbe9Sxc151355 } 30190ba2cbe9Sxc151355 } 30200ba2cbe9Sxc151355 30210ba2cbe9Sxc151355 if (optind == (argc - 1)) 30220ba2cbe9Sxc151355 obj_name = argv[optind]; 30230ba2cbe9Sxc151355 else if (optind != argc) 30240ba2cbe9Sxc151355 usage(); 30250ba2cbe9Sxc151355 302633343a97Smeem if (class == -1) 302733343a97Smeem die("secure object class required"); 30280ba2cbe9Sxc151355 302933343a97Smeem if (obj_name == NULL) 303033343a97Smeem die("secure object name required"); 30310ba2cbe9Sxc151355 30320ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 30330ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 303433343a97Smeem if (!success) 303533343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 30360ba2cbe9Sxc151355 303733343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 303833343a97Smeem if (rval != 0) { 30390ba2cbe9Sxc151355 switch (rval) { 30400ba2cbe9Sxc151355 case ENOENT: 304133343a97Smeem die("invalid secure object class"); 30420ba2cbe9Sxc151355 break; 30430ba2cbe9Sxc151355 case EINVAL: 304433343a97Smeem die("invalid secure object value"); 30450ba2cbe9Sxc151355 break; 30460ba2cbe9Sxc151355 case ENOTSUP: 304733343a97Smeem die("verification failed"); 30480ba2cbe9Sxc151355 break; 30490ba2cbe9Sxc151355 default: 305033343a97Smeem die("invalid secure object: %s", strerror(rval)); 30510ba2cbe9Sxc151355 break; 30520ba2cbe9Sxc151355 } 30530ba2cbe9Sxc151355 } 30540ba2cbe9Sxc151355 30550ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30560ba2cbe9Sxc151355 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 30570ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 305833343a97Smeem die_dlerr(status, "could not create secure object '%s'", 305933343a97Smeem obj_name); 30600ba2cbe9Sxc151355 } 30610ba2cbe9Sxc151355 if (temp) 30620ba2cbe9Sxc151355 return; 30630ba2cbe9Sxc151355 30640ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30650ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 30660ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 306733343a97Smeem warn_dlerr(status, "could not persistently create secure " 306833343a97Smeem "object '%s'", obj_name); 30690ba2cbe9Sxc151355 } 30700ba2cbe9Sxc151355 } 30710ba2cbe9Sxc151355 30720ba2cbe9Sxc151355 static void 30730ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 30740ba2cbe9Sxc151355 { 30750ba2cbe9Sxc151355 int i, option; 30760ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 30770ba2cbe9Sxc151355 split_t *sp = NULL; 30780ba2cbe9Sxc151355 boolean_t success; 30790ba2cbe9Sxc151355 dladm_status_t status, pstatus; 30800ba2cbe9Sxc151355 30810ba2cbe9Sxc151355 opterr = 0; 30820ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 308333343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 30840ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 30850ba2cbe9Sxc151355 switch (option) { 30860ba2cbe9Sxc151355 case 't': 30870ba2cbe9Sxc151355 temp = B_TRUE; 30880ba2cbe9Sxc151355 break; 30890ba2cbe9Sxc151355 case 'R': 30900ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30910ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 309233343a97Smeem die_dlerr(status, "invalid directory " 309333343a97Smeem "specified"); 30940ba2cbe9Sxc151355 } 30950ba2cbe9Sxc151355 break; 30960ba2cbe9Sxc151355 default: 309733343a97Smeem die_opterr(optopt, option); 30980ba2cbe9Sxc151355 break; 30990ba2cbe9Sxc151355 } 31000ba2cbe9Sxc151355 } 31010ba2cbe9Sxc151355 31020ba2cbe9Sxc151355 if (optind == (argc - 1)) { 31030ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 31040ba2cbe9Sxc151355 if (sp == NULL) { 310533343a97Smeem die("invalid secure object name(s): '%s'", 310633343a97Smeem argv[optind]); 31070ba2cbe9Sxc151355 } 31080ba2cbe9Sxc151355 } else if (optind != argc) 31090ba2cbe9Sxc151355 usage(); 31100ba2cbe9Sxc151355 311133343a97Smeem if (sp == NULL || sp->s_nfields < 1) 311233343a97Smeem die("secure object name required"); 31130ba2cbe9Sxc151355 31140ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 31150ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 311633343a97Smeem if (!success) 311733343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 31180ba2cbe9Sxc151355 31190ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 31200ba2cbe9Sxc151355 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 31210ba2cbe9Sxc151355 if (!temp) { 31220ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 31230ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31240ba2cbe9Sxc151355 } else { 31250ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 31260ba2cbe9Sxc151355 } 31270ba2cbe9Sxc151355 31280ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 312933343a97Smeem warn_dlerr(status, "could not delete secure object " 313033343a97Smeem "'%s'", sp->s_fields[i]); 31310ba2cbe9Sxc151355 } 31320ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 313333343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 313433343a97Smeem "secure object '%s'", sp->s_fields[i]); 31350ba2cbe9Sxc151355 } 31360ba2cbe9Sxc151355 } 31370ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 31380ba2cbe9Sxc151355 exit(1); 31390ba2cbe9Sxc151355 } 31400ba2cbe9Sxc151355 31410ba2cbe9Sxc151355 typedef struct show_secobj_state { 31420ba2cbe9Sxc151355 boolean_t ss_persist; 31430ba2cbe9Sxc151355 boolean_t ss_parseable; 31440ba2cbe9Sxc151355 boolean_t ss_debug; 31450ba2cbe9Sxc151355 boolean_t ss_header; 31460ba2cbe9Sxc151355 } show_secobj_state_t; 31470ba2cbe9Sxc151355 31480ba2cbe9Sxc151355 static void 31490ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep) 31500ba2cbe9Sxc151355 { 31510ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 31520ba2cbe9Sxc151355 if (statep->ss_debug) 31530ba2cbe9Sxc151355 (void) printf("%-30s", "VALUE"); 31540ba2cbe9Sxc151355 (void) putchar('\n'); 31550ba2cbe9Sxc151355 } 31560ba2cbe9Sxc151355 31570ba2cbe9Sxc151355 static boolean_t 31580ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 31590ba2cbe9Sxc151355 { 31600ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 31610ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 31620ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 31630ba2cbe9Sxc151355 uint_t flags = 0; 31640ba2cbe9Sxc151355 dladm_secobj_class_t class; 31650ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 31660ba2cbe9Sxc151355 dladm_status_t status; 31670ba2cbe9Sxc151355 31680ba2cbe9Sxc151355 if (statep->ss_persist) 31690ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 31700ba2cbe9Sxc151355 31710ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 317233343a97Smeem if (status != DLADM_STATUS_OK) 317333343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 31740ba2cbe9Sxc151355 31750ba2cbe9Sxc151355 if (statep->ss_header) { 31760ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 31770ba2cbe9Sxc151355 if (!statep->ss_parseable) 31780ba2cbe9Sxc151355 print_secobj_head(statep); 31790ba2cbe9Sxc151355 } 31800ba2cbe9Sxc151355 31810ba2cbe9Sxc151355 if (statep->ss_parseable) { 31820ba2cbe9Sxc151355 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 31830ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 31840ba2cbe9Sxc151355 } else { 31850ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", obj_name, 31860ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 31870ba2cbe9Sxc151355 } 31880ba2cbe9Sxc151355 31890ba2cbe9Sxc151355 if (statep->ss_debug) { 31900ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 31910ba2cbe9Sxc151355 uint_t len = sizeof (val); 31920ba2cbe9Sxc151355 31930ba2cbe9Sxc151355 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 31940ba2cbe9Sxc151355 if (statep->ss_parseable) 31950ba2cbe9Sxc151355 (void) printf("VALUE=\"0x%s\"", val); 31960ba2cbe9Sxc151355 else 31970ba2cbe9Sxc151355 (void) printf("0x%-30s", val); 31980ba2cbe9Sxc151355 } 31990ba2cbe9Sxc151355 } 32000ba2cbe9Sxc151355 (void) putchar('\n'); 32010ba2cbe9Sxc151355 return (B_TRUE); 32020ba2cbe9Sxc151355 } 32030ba2cbe9Sxc151355 32040ba2cbe9Sxc151355 static void 32050ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 32060ba2cbe9Sxc151355 { 32070ba2cbe9Sxc151355 int option; 32080ba2cbe9Sxc151355 show_secobj_state_t state; 32090ba2cbe9Sxc151355 dladm_status_t status; 32100ba2cbe9Sxc151355 uint_t i; 32110ba2cbe9Sxc151355 split_t *sp; 32120ba2cbe9Sxc151355 uint_t flags; 32130ba2cbe9Sxc151355 32140ba2cbe9Sxc151355 opterr = 0; 32150ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 32160ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 32170ba2cbe9Sxc151355 state.ss_debug = B_FALSE; 32180ba2cbe9Sxc151355 state.ss_header = B_TRUE; 32190ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":pPd", 32200ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 32210ba2cbe9Sxc151355 switch (option) { 32220ba2cbe9Sxc151355 case 'p': 32230ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 32240ba2cbe9Sxc151355 break; 32250ba2cbe9Sxc151355 case 'P': 32260ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 32270ba2cbe9Sxc151355 break; 32280ba2cbe9Sxc151355 case 'd': 322933343a97Smeem if (getuid() != 0) 323033343a97Smeem die("insufficient privileges"); 32310ba2cbe9Sxc151355 state.ss_debug = B_TRUE; 32320ba2cbe9Sxc151355 break; 32330ba2cbe9Sxc151355 default: 323433343a97Smeem die_opterr(optopt, option); 32350ba2cbe9Sxc151355 break; 32360ba2cbe9Sxc151355 } 32370ba2cbe9Sxc151355 } 32380ba2cbe9Sxc151355 32390ba2cbe9Sxc151355 if (optind == (argc - 1)) { 32400ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 32410ba2cbe9Sxc151355 if (sp == NULL) { 324233343a97Smeem die("invalid secure object name(s): '%s'", 324333343a97Smeem argv[optind]); 32440ba2cbe9Sxc151355 } 32450ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 32460ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 32470ba2cbe9Sxc151355 break; 32480ba2cbe9Sxc151355 } 32490ba2cbe9Sxc151355 splitfree(sp); 32500ba2cbe9Sxc151355 return; 32510ba2cbe9Sxc151355 } else if (optind != argc) 32520ba2cbe9Sxc151355 usage(); 32530ba2cbe9Sxc151355 32540ba2cbe9Sxc151355 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 32550ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 325633343a97Smeem if (status != DLADM_STATUS_OK) 325733343a97Smeem die_dlerr(status, "show-secobj"); 32580ba2cbe9Sxc151355 } 32590ba2cbe9Sxc151355 32600ba2cbe9Sxc151355 /* ARGSUSED */ 32610ba2cbe9Sxc151355 static void 32620ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 32630ba2cbe9Sxc151355 { 32640ba2cbe9Sxc151355 dladm_status_t status; 32650ba2cbe9Sxc151355 32660ba2cbe9Sxc151355 status = dladm_init_linkprop(); 326733343a97Smeem if (status != DLADM_STATUS_OK) 326833343a97Smeem die_dlerr(status, "link property initialization failed"); 32690ba2cbe9Sxc151355 } 32700ba2cbe9Sxc151355 32710ba2cbe9Sxc151355 /* ARGSUSED */ 32720ba2cbe9Sxc151355 static void 32730ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 32740ba2cbe9Sxc151355 { 32750ba2cbe9Sxc151355 dladm_status_t status; 32760ba2cbe9Sxc151355 32770ba2cbe9Sxc151355 status = dladm_init_secobj(); 327833343a97Smeem if (status != DLADM_STATUS_OK) 327933343a97Smeem die_dlerr(status, "secure object initialization failed"); 328033343a97Smeem } 328133343a97Smeem 328233343a97Smeem static boolean_t 328333343a97Smeem str2int(const char *str, int *valp) 328433343a97Smeem { 328533343a97Smeem int val; 328633343a97Smeem char *endp = NULL; 328733343a97Smeem 328833343a97Smeem errno = 0; 328933343a97Smeem val = strtol(str, &endp, 10); 329033343a97Smeem if (errno != 0 || *endp != '\0') 329133343a97Smeem return (B_FALSE); 329233343a97Smeem 329333343a97Smeem *valp = val; 329433343a97Smeem return (B_TRUE); 329533343a97Smeem } 329633343a97Smeem 329733343a97Smeem /* PRINTFLIKE1 */ 329833343a97Smeem static void 329933343a97Smeem warn(const char *format, ...) 330033343a97Smeem { 330133343a97Smeem va_list alist; 330233343a97Smeem 330333343a97Smeem format = gettext(format); 330433343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 330533343a97Smeem 330633343a97Smeem va_start(alist, format); 330733343a97Smeem (void) vfprintf(stderr, format, alist); 330833343a97Smeem va_end(alist); 330933343a97Smeem 331033343a97Smeem (void) putchar('\n'); 331133343a97Smeem } 331233343a97Smeem 331333343a97Smeem /* PRINTFLIKE2 */ 331433343a97Smeem static void 331533343a97Smeem warn_wlerr(wladm_status_t err, const char *format, ...) 331633343a97Smeem { 331733343a97Smeem va_list alist; 331833343a97Smeem char errmsg[WLADM_STRSIZE]; 331933343a97Smeem 332033343a97Smeem format = gettext(format); 332133343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 332233343a97Smeem 332333343a97Smeem va_start(alist, format); 332433343a97Smeem (void) vfprintf(stderr, format, alist); 332533343a97Smeem va_end(alist); 332633343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 332733343a97Smeem } 332833343a97Smeem 332933343a97Smeem /* PRINTFLIKE2 */ 333033343a97Smeem static void 333133343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 333233343a97Smeem { 333333343a97Smeem va_list alist; 333433343a97Smeem char errmsg[DLADM_STRSIZE]; 333533343a97Smeem 333633343a97Smeem format = gettext(format); 333733343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 333833343a97Smeem 333933343a97Smeem va_start(alist, format); 334033343a97Smeem (void) vfprintf(stderr, format, alist); 334133343a97Smeem va_end(alist); 334233343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 334333343a97Smeem } 334433343a97Smeem 334533343a97Smeem /* PRINTFLIKE2 */ 334633343a97Smeem static void 334733343a97Smeem die_laerr(laadm_diag_t diag, const char *format, ...) 334833343a97Smeem { 334933343a97Smeem va_list alist; 335033343a97Smeem char *errstr = strerror(errno); 335133343a97Smeem 335233343a97Smeem format = gettext(format); 335333343a97Smeem (void) fprintf(stderr, "%s: ", progname); 335433343a97Smeem 335533343a97Smeem va_start(alist, format); 335633343a97Smeem (void) vfprintf(stderr, format, alist); 335733343a97Smeem va_end(alist); 335833343a97Smeem 335933343a97Smeem if (diag == 0) 336033343a97Smeem (void) fprintf(stderr, ": %s\n", errstr); 336133343a97Smeem else 336233343a97Smeem (void) fprintf(stderr, ": %s (%s)\n", errstr, laadm_diag(diag)); 336333343a97Smeem 336433343a97Smeem exit(EXIT_FAILURE); 336533343a97Smeem } 336633343a97Smeem 336733343a97Smeem /* PRINTFLIKE2 */ 336833343a97Smeem static void 336933343a97Smeem die_wlerr(wladm_status_t err, const char *format, ...) 337033343a97Smeem { 337133343a97Smeem va_list alist; 337233343a97Smeem char errmsg[WLADM_STRSIZE]; 337333343a97Smeem 337433343a97Smeem format = gettext(format); 337533343a97Smeem (void) fprintf(stderr, "%s: ", progname); 337633343a97Smeem 337733343a97Smeem va_start(alist, format); 337833343a97Smeem (void) vfprintf(stderr, format, alist); 337933343a97Smeem va_end(alist); 338033343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 338133343a97Smeem 338233343a97Smeem exit(EXIT_FAILURE); 338333343a97Smeem } 338433343a97Smeem 338533343a97Smeem /* PRINTFLIKE2 */ 338633343a97Smeem static void 338733343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 338833343a97Smeem { 338933343a97Smeem va_list alist; 339033343a97Smeem char errmsg[DLADM_STRSIZE]; 339133343a97Smeem 339233343a97Smeem format = gettext(format); 339333343a97Smeem (void) fprintf(stderr, "%s: ", progname); 339433343a97Smeem 339533343a97Smeem va_start(alist, format); 339633343a97Smeem (void) vfprintf(stderr, format, alist); 339733343a97Smeem va_end(alist); 339833343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 339933343a97Smeem 340033343a97Smeem exit(EXIT_FAILURE); 340133343a97Smeem } 340233343a97Smeem 340333343a97Smeem /* PRINTFLIKE1 */ 340433343a97Smeem static void 340533343a97Smeem die(const char *format, ...) 340633343a97Smeem { 340733343a97Smeem va_list alist; 340833343a97Smeem 340933343a97Smeem format = gettext(format); 341033343a97Smeem (void) fprintf(stderr, "%s: ", progname); 341133343a97Smeem 341233343a97Smeem va_start(alist, format); 341333343a97Smeem (void) vfprintf(stderr, format, alist); 341433343a97Smeem va_end(alist); 341533343a97Smeem 341633343a97Smeem (void) putchar('\n'); 341733343a97Smeem exit(EXIT_FAILURE); 341833343a97Smeem } 341933343a97Smeem 342033343a97Smeem static void 342133343a97Smeem die_optdup(int opt) 342233343a97Smeem { 342333343a97Smeem die("the option -%c cannot be specified more than once", opt); 342433343a97Smeem } 342533343a97Smeem 342633343a97Smeem static void 342733343a97Smeem die_opterr(int opt, int opterr) 342833343a97Smeem { 342933343a97Smeem switch (opterr) { 343033343a97Smeem case ':': 343133343a97Smeem die("option '-%c' requires a value", opt); 343233343a97Smeem break; 343333343a97Smeem case '?': 343433343a97Smeem default: 343533343a97Smeem die("unrecognized option '-%c'", opt); 343633343a97Smeem break; 34370ba2cbe9Sxc151355 } 34380ba2cbe9Sxc151355 } 3439