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> 35*33343a97Smeem #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 119*33343a97Smeem static void link_stats(const char *, uint_t); 120*33343a97Smeem 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 131*33343a97Smeem static boolean_t str2int(const char *, int *); 132*33343a97Smeem static void die(const char *, ...); 133*33343a97Smeem static void die_optdup(int); 134*33343a97Smeem static void die_opterr(int, int); 135*33343a97Smeem static void die_laerr(laadm_diag_t, const char *, ...); 136*33343a97Smeem static void die_wlerr(wladm_status_t, const char *, ...); 137*33343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 138*33343a97Smeem static void warn(const char *, ...); 139*33343a97Smeem static void warn_wlerr(wladm_status_t, const char *, ...); 140*33343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 141*33343a97Smeem 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) || 273*33343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 274*33343a97Smeem 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; 295*33343a97Smeem 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': 316*33343a97Smeem if (nport >= MAXPORT) 317*33343a97Smeem die("too many <dev> arguments"); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 320*33343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 321*33343a97Smeem die("device name too long"); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate nport++; 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate case 'P': 326*33343a97Smeem if (P_arg) 327*33343a97Smeem die_optdup(option); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 330*33343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 331*33343a97Smeem die("invalid policy '%s'", optarg); 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate case 'u': 334*33343a97Smeem if (u_arg) 335*33343a97Smeem 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, 339*33343a97Smeem mac_addr)) 340*33343a97Smeem die("invalid MAC address '%s'", optarg); 3417c478bd9Sstevel@tonic-gate break; 3427c478bd9Sstevel@tonic-gate case 'l': 343*33343a97Smeem if (l_arg) 344*33343a97Smeem die_optdup(option); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 347*33343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 348*33343a97Smeem die("invalid LACP mode '%s'", optarg); 3497c478bd9Sstevel@tonic-gate break; 3507c478bd9Sstevel@tonic-gate case 'T': 351*33343a97Smeem if (T_arg) 352*33343a97Smeem die_optdup(option); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 355*33343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 356*33343a97Smeem 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: 365*33343a97Smeem die_opterr(optopt, option); 366*33343a97Smeem 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 377*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 378*33343a97Smeem die("invalid key value '%s'", argv[optind]); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (laadm_create(key, nport, port, policy, mac_addr_fixed, 381*33343a97Smeem mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 382*33343a97Smeem 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 { 388*33343a97Smeem 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: 405*33343a97Smeem 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 414*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 415*33343a97Smeem die("invalid key value '%s'", argv[optind]); 4167c478bd9Sstevel@tonic-gate 417*33343a97Smeem if (laadm_delete(key, t_arg, altroot, &diag) < 0) 418*33343a97Smeem 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; 425*33343a97Smeem 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': 437*33343a97Smeem if (nport >= MAXPORT) 438*33343a97Smeem die("too many <dev> arguments"); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 441*33343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 442*33343a97Smeem die("device name too long"); 443*33343a97Smeem 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: 453*33343a97Smeem die_opterr(optopt, option); 454*33343a97Smeem 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 465*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 466*33343a97Smeem 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 } 480*33343a97Smeem 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; 488*33343a97Smeem 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': 500*33343a97Smeem if (nport >= MAXPORT) 501*33343a97Smeem die("too many <dev> arguments"); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 504*33343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 505*33343a97Smeem die("device name too long"); 506*33343a97Smeem 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: 516*33343a97Smeem die_opterr(optopt, option); 517*33343a97Smeem 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 528*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 529*33343a97Smeem die("invalid key value '%s'", argv[optind]); 5307c478bd9Sstevel@tonic-gate 531*33343a97Smeem if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) 532*33343a97Smeem 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; 539*33343a97Smeem 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': 555*33343a97Smeem if (modify_mask & LAADM_MODIFY_POLICY) 556*33343a97Smeem die_optdup(option); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_POLICY; 5597c478bd9Sstevel@tonic-gate 560*33343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 561*33343a97Smeem die("invalid policy '%s'", optarg); 5627c478bd9Sstevel@tonic-gate break; 5637c478bd9Sstevel@tonic-gate case 'u': 564*33343a97Smeem if (modify_mask & LAADM_MODIFY_MAC) 565*33343a97Smeem 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, 570*33343a97Smeem mac_addr)) 571*33343a97Smeem die("invalid MAC address '%s'", optarg); 5727c478bd9Sstevel@tonic-gate break; 5737c478bd9Sstevel@tonic-gate case 'l': 574*33343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_MODE) 575*33343a97Smeem die_optdup(option); 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_MODE; 5787c478bd9Sstevel@tonic-gate 579*33343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 580*33343a97Smeem die("invalid LACP mode '%s'", optarg); 5817c478bd9Sstevel@tonic-gate break; 5827c478bd9Sstevel@tonic-gate case 'T': 583*33343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_TIMER) 584*33343a97Smeem die_optdup(option); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_TIMER; 5877c478bd9Sstevel@tonic-gate 588*33343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 589*33343a97Smeem 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: 598*33343a97Smeem die_opterr(optopt, option); 599*33343a97Smeem break; 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 603*33343a97Smeem if (modify_mask == 0) 604*33343a97Smeem 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 610*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 611*33343a97Smeem 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, 614*33343a97Smeem lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 615*33343a97Smeem 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 { 621*33343a97Smeem 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) { 626*33343a97Smeem if (!str2int(argv[1], &key) || key < 1) 627*33343a97Smeem 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) { 634*33343a97Smeem die_laerr(diag, "could not bring up aggregation '%u'", 635*33343a97Smeem key); 6367c478bd9Sstevel@tonic-gate } else { 637*33343a97Smeem 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 { 645*33343a97Smeem int key = 0; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6487c478bd9Sstevel@tonic-gate if (argc == 2) { 649*33343a97Smeem if (!str2int(argv[1], &key) || key < 1) 650*33343a97Smeem 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) { 657*33343a97Smeem die("could not bring down aggregation '%u': %s", 658*33343a97Smeem key, strerror(errno)); 6597c478bd9Sstevel@tonic-gate } else { 660*33343a97Smeem die("could not bring down aggregations: %s", 661*33343a97Smeem 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 778*33343a97Smeem if (get_if_info(name, &dlattr, &legacy) < 0) 779*33343a97Smeem 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)); 910*33343a97Smeem (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)); 1073*33343a97Smeem (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; 1121*33343a97Smeem 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': 1135*33343a97Smeem if (s_arg) 1136*33343a97Smeem die_optdup(option); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate case 'i': 1141*33343a97Smeem if (i_arg) 1142*33343a97Smeem die_optdup(option); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 1145*33343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 1146*33343a97Smeem die("invalid interval value '%s'", optarg); 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate default: 1149*33343a97Smeem die_opterr(optopt, option); 1150*33343a97Smeem break; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 1154*33343a97Smeem if (i_arg && !s_arg) 1155*33343a97Smeem 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; 1179*33343a97Smeem 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; 1184*33343a97Smeem 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': 1195*33343a97Smeem if (L_arg) 1196*33343a97Smeem die_optdup(option); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (s_arg || i_arg) { 1199*33343a97Smeem die("the option -L cannot be used with -i " 1200*33343a97Smeem "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': 1210*33343a97Smeem if (s_arg) 1211*33343a97Smeem die_optdup(option); 12127c478bd9Sstevel@tonic-gate 1213*33343a97Smeem if (L_arg) 1214*33343a97Smeem die("the option -L cannot be used with -k"); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate case 'i': 1219*33343a97Smeem if (i_arg) 1220*33343a97Smeem die_optdup(option); 12217c478bd9Sstevel@tonic-gate 1222*33343a97Smeem if (L_arg) 1223*33343a97Smeem die("the option -i cannot be used with -L"); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 1226*33343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 1227*33343a97Smeem die("invalid interval value '%s'", optarg); 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate default: 1230*33343a97Smeem die_opterr(optopt, option); 1231*33343a97Smeem break; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate 1235*33343a97Smeem if (i_arg && !s_arg) 1236*33343a97Smeem 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)) { 1240*33343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 1241*33343a97Smeem 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 1256*33343a97Smeem if (key != 0 && !state.gs_found) 1257*33343a97Smeem 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; 1267*33343a97Smeem 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': 1280*33343a97Smeem if (s_arg) 1281*33343a97Smeem die_optdup(option); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12847c478bd9Sstevel@tonic-gate break; 12857c478bd9Sstevel@tonic-gate case 'i': 1286*33343a97Smeem if (i_arg) 1287*33343a97Smeem die_optdup(option); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 1290*33343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 1291*33343a97Smeem die("invalid interval value '%s'", optarg); 12927c478bd9Sstevel@tonic-gate break; 12937c478bd9Sstevel@tonic-gate default: 1294*33343a97Smeem die_opterr(optopt, option); 1295*33343a97Smeem break; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 1299*33343a97Smeem if (i_arg && !s_arg) 1300*33343a97Smeem 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 || 1320*33343a97Smeem index >= 1000 || get_if_info(dev, &dlattr, &legacy) < 0) 1321*33343a97Smeem 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 1337*33343a97Smeem 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 1343*33343a97Smeem if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 1344*33343a97Smeem die("invalid link '%s'", link); 1345*33343a97Smeem 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 1373*33343a97Smeem 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); 1390*33343a97Smeem if (state.gs_key != 0 && !state.gs_found) 1391*33343a97Smeem 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) { 1471*33343a97Smeem 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) { 1553*33343a97Smeem 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) { 1569*33343a97Smeem 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}, 16620ba2cbe9Sxc151355 { "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_ALL}, 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 = 16700ba2cbe9Sxc151355 "link,essid,bssid,sec,strength,mode,speed,auth,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) { 17690ba2cbe9Sxc151355 good_match = wifi_fields[i]. 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); 1925*33343a97Smeem if (status != WLADM_STATUS_OK) 1926*33343a97Smeem die_wlerr(status, "cannot scan link '%s'", link); 1927*33343a97Smeem 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); 1956*33343a97Smeem if (status != WLADM_STATUS_OK) 1957*33343a97Smeem 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: 2009*33343a97Smeem 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 2019*33343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 2020*33343a97Smeem die("invalid field(s) specified"); 2021*33343a97Smeem 20220ba2cbe9Sxc151355 state.ws_fields = fields; 20230ba2cbe9Sxc151355 state.ws_nfields = nfields; 20240ba2cbe9Sxc151355 20250ba2cbe9Sxc151355 if (state.ws_link == NULL) { 20260ba2cbe9Sxc151355 status = wladm_walk(&state, callback); 2027*33343a97Smeem if (status != WLADM_STATUS_OK) 2028*33343a97Smeem 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 { 2055*33343a97Smeem 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); 2138*33343a97Smeem if (status != WLADM_STATUS_OK) 2139*33343a97Smeem die("invalid ESSID '%s'", optarg); 2140*33343a97Smeem 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); 2149*33343a97Smeem if (status != WLADM_STATUS_OK) 2150*33343a97Smeem die("invalid BSSID %s", optarg); 2151*33343a97Smeem 21520ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 21530ba2cbe9Sxc151355 break; 21540ba2cbe9Sxc151355 case 'a': 21550ba2cbe9Sxc151355 status = wladm_str2auth(optarg, &attr.wa_auth); 2156*33343a97Smeem if (status != WLADM_STATUS_OK) 2157*33343a97Smeem die("invalid authentication mode '%s'", optarg); 2158*33343a97Smeem 21590ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 21600ba2cbe9Sxc151355 break; 21610ba2cbe9Sxc151355 case 'm': 21620ba2cbe9Sxc151355 status = wladm_str2mode(optarg, &attr.wa_mode); 2163*33343a97Smeem if (status != WLADM_STATUS_OK) 2164*33343a97Smeem die("invalid mode '%s'", optarg); 2165*33343a97Smeem 21660ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 21670ba2cbe9Sxc151355 break; 21680ba2cbe9Sxc151355 case 'b': 21690ba2cbe9Sxc151355 status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 2170*33343a97Smeem if (status != WLADM_STATUS_OK) 2171*33343a97Smeem die("invalid bsstype '%s'", optarg); 2172*33343a97Smeem 21730ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 21740ba2cbe9Sxc151355 break; 21750ba2cbe9Sxc151355 case 's': 21760ba2cbe9Sxc151355 status = wladm_str2secmode(optarg, &attr.wa_secmode); 2177*33343a97Smeem if (status != WLADM_STATUS_OK) 2178*33343a97Smeem die("invalid security mode '%s'", optarg); 2179*33343a97Smeem 21800ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 21810ba2cbe9Sxc151355 break; 21820ba2cbe9Sxc151355 case 'k': 2183*33343a97Smeem if (parse_wep_keys(optarg, &keys, &key_count) < 0) 2184*33343a97Smeem die("invalid key(s) '%s'", optarg); 2185*33343a97Smeem 21860ba2cbe9Sxc151355 keysecmode = WLADM_SECMODE_WEP; 21870ba2cbe9Sxc151355 break; 21880ba2cbe9Sxc151355 case 'T': 21890ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 21900ba2cbe9Sxc151355 timeout = -1; 21910ba2cbe9Sxc151355 break; 21920ba2cbe9Sxc151355 } 2193*33343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 2194*33343a97Smeem die("invalid timeout value '%s'", optarg); 21950ba2cbe9Sxc151355 break; 21960ba2cbe9Sxc151355 case 'c': 21970ba2cbe9Sxc151355 flags |= WLADM_OPT_CREATEIBSS; 21980ba2cbe9Sxc151355 break; 21990ba2cbe9Sxc151355 default: 2200*33343a97Smeem 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 && 2207*33343a97Smeem attr.wa_secmode == WLADM_SECMODE_WEP) 2208*33343a97Smeem die("key required for security mode 'wep'"); 22090ba2cbe9Sxc151355 } else { 22100ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 2211*33343a97Smeem attr.wa_secmode != keysecmode) 2212*33343a97Smeem 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) { 2229*33343a97Smeem die("no wifi links are available"); 22300ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 2231*33343a97Smeem die("link name is required when more than one wifi " 2232*33343a97Smeem "link is available"); 22330ba2cbe9Sxc151355 } 22340ba2cbe9Sxc151355 link = wcattr.wc_link; 22350ba2cbe9Sxc151355 } 22360ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 2237*33343a97Smeem 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 /* 2242*33343a97Smeem * Try again with scanning and filtering. 22430ba2cbe9Sxc151355 */ 22440ba2cbe9Sxc151355 flags &= ~WLADM_OPT_NOSCAN; 2245*33343a97Smeem goto again; 22460ba2cbe9Sxc151355 } 2247*33343a97Smeem 22480ba2cbe9Sxc151355 if (status == WLADM_STATUS_NOTFOUND) { 22490ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 2250*33343a97Smeem die("no wifi networks are available"); 22510ba2cbe9Sxc151355 } else { 2252*33343a97Smeem die("no wifi networks with the specified" 2253*33343a97Smeem "criteria are available"); 22540ba2cbe9Sxc151355 } 22550ba2cbe9Sxc151355 } 2256*33343a97Smeem die_wlerr(status, "cannot connect"); 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); 2268*33343a97Smeem if (status != WLADM_STATUS_OK) 2269*33343a97Smeem warn_wlerr(status, "cannot disconnect link '%s'", link); 2270*33343a97Smeem 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: 2291*33343a97Smeem 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) { 2307*33343a97Smeem die("no wifi links are available"); 23080ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 2309*33343a97Smeem die("link name is required when more than " 2310*33343a97Smeem "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); 2319*33343a97Smeem if (status != WLADM_STATUS_OK) 2320*33343a97Smeem 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 { 2450*33343a97Smeem die_dlerr(status, "cannot get link property '%s'", 2451*33343a97Smeem 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': 2527*33343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 2528*33343a97Smeem die("invalid field(s) 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: 2537*33343a97Smeem 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 2547*33343a97Smeem if (state.ls_link == NULL) 2548*33343a97Smeem 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); 2557*33343a97Smeem if ((fd = open(linkname, O_RDWR)) < 0) 2558*33343a97Smeem 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); 2562*33343a97Smeem if (buf == NULL) 2563*33343a97Smeem die("insufficient memory"); 2564*33343a97Smeem 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); 2581*33343a97Smeem if (status != DLADM_STATUS_OK) 2582*33343a97Smeem 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) { 2600*33343a97Smeem warn_dlerr(status, "cannot persistently reset link " 2601*33343a97Smeem "property '%s' on '%s'", prop_name, link); 26020ba2cbe9Sxc151355 } else { 2603*33343a97Smeem warn_dlerr(status, "cannot persistently set link " 2604*33343a97Smeem "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': 2625*33343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 2626*33343a97Smeem 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) { 2634*33343a97Smeem die_dlerr(status, "invalid directory " 2635*33343a97Smeem "specified"); 26360ba2cbe9Sxc151355 } 26370ba2cbe9Sxc151355 break; 26380ba2cbe9Sxc151355 default: 2639*33343a97Smeem 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 2649*33343a97Smeem if (link == NULL) 2650*33343a97Smeem die("link name must be specified"); 26510ba2cbe9Sxc151355 2652*33343a97Smeem if (proplist == NULL) 26530ba2cbe9Sxc151355 if (!reset) { 2654*33343a97Smeem die("link property must be specified"); 2655*33343a97Smeem 26560ba2cbe9Sxc151355 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP); 26570ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2658*33343a97Smeem warn_dlerr(status, "cannot reset link properties " 2659*33343a97Smeem "on '%s'", link); 26600ba2cbe9Sxc151355 } 26610ba2cbe9Sxc151355 if (!temp) { 26620ba2cbe9Sxc151355 status = set_linkprop_persist(link, NULL, NULL, 0, 26630ba2cbe9Sxc151355 reset); 26640ba2cbe9Sxc151355 } 26650ba2cbe9Sxc151355 goto done; 26660ba2cbe9Sxc151355 } 26670ba2cbe9Sxc151355 26680ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 26690ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 26700ba2cbe9Sxc151355 char **val; 26710ba2cbe9Sxc151355 uint_t count; 26720ba2cbe9Sxc151355 dladm_status_t s; 26730ba2cbe9Sxc151355 26740ba2cbe9Sxc151355 if (reset) { 26750ba2cbe9Sxc151355 val = NULL; 26760ba2cbe9Sxc151355 count = 0; 26770ba2cbe9Sxc151355 } else { 26780ba2cbe9Sxc151355 val = pip->pi_val; 26790ba2cbe9Sxc151355 count = pip->pi_count; 26800ba2cbe9Sxc151355 if (count == 0) { 2681*33343a97Smeem warn("no value specified for '%s'", 2682*33343a97Smeem pip->pi_name); 26830ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 26840ba2cbe9Sxc151355 continue; 26850ba2cbe9Sxc151355 } 26860ba2cbe9Sxc151355 } 26870ba2cbe9Sxc151355 s = dladm_set_prop(link, pip->pi_name, val, count, 26880ba2cbe9Sxc151355 DLADM_OPT_TEMP); 26890ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 26900ba2cbe9Sxc151355 if (!temp) { 26910ba2cbe9Sxc151355 s = set_linkprop_persist(link, 26920ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 26930ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 26940ba2cbe9Sxc151355 status = s; 26950ba2cbe9Sxc151355 } 26960ba2cbe9Sxc151355 continue; 26970ba2cbe9Sxc151355 } 26980ba2cbe9Sxc151355 status = s; 26990ba2cbe9Sxc151355 switch (s) { 27000ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 2701*33343a97Smeem warn("invalid link property '%s'", pip->pi_name); 27020ba2cbe9Sxc151355 break; 27030ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 27040ba2cbe9Sxc151355 int j; 27050ba2cbe9Sxc151355 char *ptr, *lim; 27060ba2cbe9Sxc151355 char **propvals = NULL; 27070ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 27080ba2cbe9Sxc151355 27090ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 27100ba2cbe9Sxc151355 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 27110ba2cbe9Sxc151355 MAX_PROP_LINE); 27120ba2cbe9Sxc151355 27130ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 2714*33343a97Smeem if (propvals == NULL) 2715*33343a97Smeem die("insufficient memory"); 2716*33343a97Smeem 27170ba2cbe9Sxc151355 for (j = 0; j < MAX_PROP_VALS; j++) { 27180ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 27190ba2cbe9Sxc151355 MAX_PROP_VALS + 27200ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 27210ba2cbe9Sxc151355 } 27220ba2cbe9Sxc151355 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 27230ba2cbe9Sxc151355 pip->pi_name, propvals, &valcnt); 27240ba2cbe9Sxc151355 27250ba2cbe9Sxc151355 ptr = errmsg; 27260ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 27270ba2cbe9Sxc151355 *ptr = '\0'; 27280ba2cbe9Sxc151355 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 27290ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 27300ba2cbe9Sxc151355 propvals[j]); 27310ba2cbe9Sxc151355 if (ptr >= lim) 27320ba2cbe9Sxc151355 break; 27330ba2cbe9Sxc151355 } 27340ba2cbe9Sxc151355 if (ptr > errmsg) 27350ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 2736*33343a97Smeem warn("link property '%s' must be one of: %s", 2737*33343a97Smeem pip->pi_name, errmsg); 27380ba2cbe9Sxc151355 free(propvals); 27390ba2cbe9Sxc151355 break; 27400ba2cbe9Sxc151355 } 27410ba2cbe9Sxc151355 default: 27420ba2cbe9Sxc151355 if (reset) { 2743*33343a97Smeem warn_dlerr(status, "cannot reset link property " 2744*33343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27450ba2cbe9Sxc151355 } else { 2746*33343a97Smeem warn_dlerr(status, "cannot set link property " 2747*33343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27480ba2cbe9Sxc151355 } 27490ba2cbe9Sxc151355 break; 27500ba2cbe9Sxc151355 } 27510ba2cbe9Sxc151355 } 27520ba2cbe9Sxc151355 done: 27530ba2cbe9Sxc151355 free_props(proplist); 27540ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 27550ba2cbe9Sxc151355 exit(1); 27560ba2cbe9Sxc151355 } 27570ba2cbe9Sxc151355 27580ba2cbe9Sxc151355 static void 27590ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 27600ba2cbe9Sxc151355 { 27610ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 27620ba2cbe9Sxc151355 } 27630ba2cbe9Sxc151355 27640ba2cbe9Sxc151355 static void 27650ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 27660ba2cbe9Sxc151355 { 27670ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 27680ba2cbe9Sxc151355 } 27690ba2cbe9Sxc151355 27700ba2cbe9Sxc151355 static int 27710ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 27720ba2cbe9Sxc151355 dladm_secobj_class_t class) 27730ba2cbe9Sxc151355 { 27740ba2cbe9Sxc151355 int error = 0; 27750ba2cbe9Sxc151355 27760ba2cbe9Sxc151355 if (class != DLADM_SECOBJ_CLASS_WEP) 27770ba2cbe9Sxc151355 return (ENOENT); 27780ba2cbe9Sxc151355 27790ba2cbe9Sxc151355 switch (len) { 27800ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 27810ba2cbe9Sxc151355 case 13: 27820ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 27830ba2cbe9Sxc151355 *obj_lenp = len; 27840ba2cbe9Sxc151355 break; 27850ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 27860ba2cbe9Sxc151355 case 26: 27870ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 27880ba2cbe9Sxc151355 break; 27890ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 27900ba2cbe9Sxc151355 case 28: 27910ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 27920ba2cbe9Sxc151355 return (EINVAL); 27930ba2cbe9Sxc151355 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 27940ba2cbe9Sxc151355 break; 27950ba2cbe9Sxc151355 default: 27960ba2cbe9Sxc151355 return (EINVAL); 27970ba2cbe9Sxc151355 } 27980ba2cbe9Sxc151355 return (error); 27990ba2cbe9Sxc151355 } 28000ba2cbe9Sxc151355 28010ba2cbe9Sxc151355 /* ARGSUSED */ 28020ba2cbe9Sxc151355 static void 28030ba2cbe9Sxc151355 defersig(int sig) 28040ba2cbe9Sxc151355 { 28050ba2cbe9Sxc151355 signalled = sig; 28060ba2cbe9Sxc151355 } 28070ba2cbe9Sxc151355 28080ba2cbe9Sxc151355 static int 28090ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 28100ba2cbe9Sxc151355 { 28110ba2cbe9Sxc151355 uint_t len = 0; 28120ba2cbe9Sxc151355 int c; 28130ba2cbe9Sxc151355 struct termios stored, current; 28140ba2cbe9Sxc151355 void (*sigfunc)(int); 28150ba2cbe9Sxc151355 28160ba2cbe9Sxc151355 /* 28170ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 28180ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 28190ba2cbe9Sxc151355 */ 28200ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 28210ba2cbe9Sxc151355 (void) fflush(stdin); 28220ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 28230ba2cbe9Sxc151355 current = stored; 28240ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 28250ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 28260ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 28270ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 28280ba2cbe9Sxc151355 again: 28290ba2cbe9Sxc151355 if (try == 1) 28300ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 28310ba2cbe9Sxc151355 else 28320ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 28330ba2cbe9Sxc151355 28340ba2cbe9Sxc151355 (void) fflush(stdout); 28350ba2cbe9Sxc151355 while (signalled == 0) { 28360ba2cbe9Sxc151355 c = getchar(); 28370ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 28380ba2cbe9Sxc151355 if (len != 0) 28390ba2cbe9Sxc151355 break; 28400ba2cbe9Sxc151355 (void) putchar('\n'); 28410ba2cbe9Sxc151355 goto again; 28420ba2cbe9Sxc151355 } 28430ba2cbe9Sxc151355 28440ba2cbe9Sxc151355 buf[len++] = c; 28450ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 28460ba2cbe9Sxc151355 break; 28470ba2cbe9Sxc151355 (void) putchar('*'); 28480ba2cbe9Sxc151355 } 28490ba2cbe9Sxc151355 28500ba2cbe9Sxc151355 (void) putchar('\n'); 28510ba2cbe9Sxc151355 (void) fflush(stdin); 28520ba2cbe9Sxc151355 28530ba2cbe9Sxc151355 /* 28540ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 28550ba2cbe9Sxc151355 */ 28560ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 28570ba2cbe9Sxc151355 28580ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 28590ba2cbe9Sxc151355 if (signalled != 0) 28600ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 28610ba2cbe9Sxc151355 28620ba2cbe9Sxc151355 return (len); 28630ba2cbe9Sxc151355 } 28640ba2cbe9Sxc151355 28650ba2cbe9Sxc151355 static int 28660ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 28670ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 28680ba2cbe9Sxc151355 { 28690ba2cbe9Sxc151355 int rval; 28700ba2cbe9Sxc151355 uint_t len, len2; 28710ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 28720ba2cbe9Sxc151355 28730ba2cbe9Sxc151355 if (filep == NULL) { 28740ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 28750ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 28760ba2cbe9Sxc151355 if (rval == 0) { 28770ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 28780ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 28790ba2cbe9Sxc151355 rval = ENOTSUP; 28800ba2cbe9Sxc151355 } 28810ba2cbe9Sxc151355 return (rval); 28820ba2cbe9Sxc151355 } else { 28830ba2cbe9Sxc151355 for (;;) { 28840ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 28850ba2cbe9Sxc151355 break; 28860ba2cbe9Sxc151355 if (isspace(buf[0])) 28870ba2cbe9Sxc151355 continue; 28880ba2cbe9Sxc151355 28890ba2cbe9Sxc151355 len = strlen(buf); 28900ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 28910ba2cbe9Sxc151355 buf[len - 1] = '\0'; 28920ba2cbe9Sxc151355 len--; 28930ba2cbe9Sxc151355 } 28940ba2cbe9Sxc151355 break; 28950ba2cbe9Sxc151355 } 28960ba2cbe9Sxc151355 (void) fclose(filep); 28970ba2cbe9Sxc151355 } 28980ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 28990ba2cbe9Sxc151355 } 29000ba2cbe9Sxc151355 29010ba2cbe9Sxc151355 static boolean_t 29020ba2cbe9Sxc151355 check_auth(const char *auth) 29030ba2cbe9Sxc151355 { 29040ba2cbe9Sxc151355 struct passwd *pw; 29050ba2cbe9Sxc151355 29060ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 29070ba2cbe9Sxc151355 return (B_FALSE); 29080ba2cbe9Sxc151355 29090ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 29100ba2cbe9Sxc151355 } 29110ba2cbe9Sxc151355 29120ba2cbe9Sxc151355 static void 29130ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 29140ba2cbe9Sxc151355 boolean_t success, boolean_t create) 29150ba2cbe9Sxc151355 { 29160ba2cbe9Sxc151355 adt_session_data_t *ah; 29170ba2cbe9Sxc151355 adt_event_data_t *event; 29180ba2cbe9Sxc151355 au_event_t flag; 29190ba2cbe9Sxc151355 char *errstr; 29200ba2cbe9Sxc151355 29210ba2cbe9Sxc151355 if (create) { 29220ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 29230ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 29240ba2cbe9Sxc151355 } else { 29250ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 29260ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 29270ba2cbe9Sxc151355 } 29280ba2cbe9Sxc151355 2929*33343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 2930*33343a97Smeem die("adt_start_session: %s", strerror(errno)); 29310ba2cbe9Sxc151355 2932*33343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 2933*33343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 29340ba2cbe9Sxc151355 29350ba2cbe9Sxc151355 /* fill in audit info */ 29360ba2cbe9Sxc151355 if (create) { 29370ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 29380ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 29390ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 29400ba2cbe9Sxc151355 } else { 29410ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 29420ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 29430ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 29440ba2cbe9Sxc151355 } 29450ba2cbe9Sxc151355 29460ba2cbe9Sxc151355 if (success) { 29470ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 2948*33343a97Smeem die("adt_put_event (%s, success): %s", errstr, 2949*33343a97Smeem strerror(errno)); 29500ba2cbe9Sxc151355 } 29510ba2cbe9Sxc151355 } else { 29520ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 29530ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 2954*33343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 2955*33343a97Smeem strerror(errno)); 29560ba2cbe9Sxc151355 } 29570ba2cbe9Sxc151355 } 29580ba2cbe9Sxc151355 29590ba2cbe9Sxc151355 adt_free_event(event); 29600ba2cbe9Sxc151355 (void) adt_end_session(ah); 29610ba2cbe9Sxc151355 } 29620ba2cbe9Sxc151355 29630ba2cbe9Sxc151355 #define MAX_SECOBJS 32 29640ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 29650ba2cbe9Sxc151355 static void 29660ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 29670ba2cbe9Sxc151355 { 29680ba2cbe9Sxc151355 int option, rval; 29690ba2cbe9Sxc151355 FILE *filep = NULL; 29700ba2cbe9Sxc151355 char *obj_name = NULL; 29710ba2cbe9Sxc151355 char *class_name = NULL; 29720ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 29730ba2cbe9Sxc151355 uint_t obj_len; 29740ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 29750ba2cbe9Sxc151355 dladm_status_t status; 29760ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 29770ba2cbe9Sxc151355 uid_t euid; 29780ba2cbe9Sxc151355 29790ba2cbe9Sxc151355 opterr = 0; 29800ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 29810ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 29820ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 29830ba2cbe9Sxc151355 switch (option) { 29840ba2cbe9Sxc151355 case 'f': 29850ba2cbe9Sxc151355 euid = geteuid(); 29860ba2cbe9Sxc151355 (void) seteuid(getuid()); 29870ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 29880ba2cbe9Sxc151355 if (filep == NULL) { 2989*33343a97Smeem die("cannot open %s: %s", optarg, 2990*33343a97Smeem strerror(errno)); 29910ba2cbe9Sxc151355 } 29920ba2cbe9Sxc151355 (void) seteuid(euid); 29930ba2cbe9Sxc151355 break; 29940ba2cbe9Sxc151355 case 'c': 29950ba2cbe9Sxc151355 class_name = optarg; 29960ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 29970ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2998*33343a97Smeem die("invalid secure object class '%s', " 2999*33343a97Smeem "valid values are: wep", optarg); 30000ba2cbe9Sxc151355 } 30010ba2cbe9Sxc151355 break; 30020ba2cbe9Sxc151355 case 't': 30030ba2cbe9Sxc151355 temp = B_TRUE; 30040ba2cbe9Sxc151355 break; 30050ba2cbe9Sxc151355 case 'R': 30060ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30070ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 3008*33343a97Smeem die_dlerr(status, "invalid directory " 3009*33343a97Smeem "specified"); 30100ba2cbe9Sxc151355 } 30110ba2cbe9Sxc151355 break; 30120ba2cbe9Sxc151355 default: 3013*33343a97Smeem die_opterr(optopt, option); 30140ba2cbe9Sxc151355 break; 30150ba2cbe9Sxc151355 } 30160ba2cbe9Sxc151355 } 30170ba2cbe9Sxc151355 30180ba2cbe9Sxc151355 if (optind == (argc - 1)) 30190ba2cbe9Sxc151355 obj_name = argv[optind]; 30200ba2cbe9Sxc151355 else if (optind != argc) 30210ba2cbe9Sxc151355 usage(); 30220ba2cbe9Sxc151355 3023*33343a97Smeem if (class == -1) 3024*33343a97Smeem die("secure object class required"); 30250ba2cbe9Sxc151355 3026*33343a97Smeem if (obj_name == NULL) 3027*33343a97Smeem die("secure object name required"); 30280ba2cbe9Sxc151355 30290ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 30300ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 3031*33343a97Smeem if (!success) 3032*33343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 30330ba2cbe9Sxc151355 3034*33343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 3035*33343a97Smeem if (rval != 0) { 30360ba2cbe9Sxc151355 switch (rval) { 30370ba2cbe9Sxc151355 case ENOENT: 3038*33343a97Smeem die("invalid secure object class"); 30390ba2cbe9Sxc151355 break; 30400ba2cbe9Sxc151355 case EINVAL: 3041*33343a97Smeem die("invalid secure object value"); 30420ba2cbe9Sxc151355 break; 30430ba2cbe9Sxc151355 case ENOTSUP: 3044*33343a97Smeem die("verification failed"); 30450ba2cbe9Sxc151355 break; 30460ba2cbe9Sxc151355 default: 3047*33343a97Smeem die("invalid secure object: %s", strerror(rval)); 30480ba2cbe9Sxc151355 break; 30490ba2cbe9Sxc151355 } 30500ba2cbe9Sxc151355 } 30510ba2cbe9Sxc151355 30520ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30530ba2cbe9Sxc151355 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 30540ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 3055*33343a97Smeem die_dlerr(status, "could not create secure object '%s'", 3056*33343a97Smeem obj_name); 30570ba2cbe9Sxc151355 } 30580ba2cbe9Sxc151355 if (temp) 30590ba2cbe9Sxc151355 return; 30600ba2cbe9Sxc151355 30610ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30620ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 30630ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 3064*33343a97Smeem warn_dlerr(status, "could not persistently create secure " 3065*33343a97Smeem "object '%s'", obj_name); 30660ba2cbe9Sxc151355 } 30670ba2cbe9Sxc151355 } 30680ba2cbe9Sxc151355 30690ba2cbe9Sxc151355 static void 30700ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 30710ba2cbe9Sxc151355 { 30720ba2cbe9Sxc151355 int i, option; 30730ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 30740ba2cbe9Sxc151355 split_t *sp = NULL; 30750ba2cbe9Sxc151355 boolean_t success; 30760ba2cbe9Sxc151355 dladm_status_t status, pstatus; 30770ba2cbe9Sxc151355 30780ba2cbe9Sxc151355 opterr = 0; 30790ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 3080*33343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 30810ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 30820ba2cbe9Sxc151355 switch (option) { 30830ba2cbe9Sxc151355 case 't': 30840ba2cbe9Sxc151355 temp = B_TRUE; 30850ba2cbe9Sxc151355 break; 30860ba2cbe9Sxc151355 case 'R': 30870ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30880ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 3089*33343a97Smeem die_dlerr(status, "invalid directory " 3090*33343a97Smeem "specified"); 30910ba2cbe9Sxc151355 } 30920ba2cbe9Sxc151355 break; 30930ba2cbe9Sxc151355 default: 3094*33343a97Smeem die_opterr(optopt, option); 30950ba2cbe9Sxc151355 break; 30960ba2cbe9Sxc151355 } 30970ba2cbe9Sxc151355 } 30980ba2cbe9Sxc151355 30990ba2cbe9Sxc151355 if (optind == (argc - 1)) { 31000ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 31010ba2cbe9Sxc151355 if (sp == NULL) { 3102*33343a97Smeem die("invalid secure object name(s): '%s'", 3103*33343a97Smeem argv[optind]); 31040ba2cbe9Sxc151355 } 31050ba2cbe9Sxc151355 } else if (optind != argc) 31060ba2cbe9Sxc151355 usage(); 31070ba2cbe9Sxc151355 3108*33343a97Smeem if (sp == NULL || sp->s_nfields < 1) 3109*33343a97Smeem die("secure object name required"); 31100ba2cbe9Sxc151355 31110ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 31120ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 3113*33343a97Smeem if (!success) 3114*33343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 31150ba2cbe9Sxc151355 31160ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 31170ba2cbe9Sxc151355 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 31180ba2cbe9Sxc151355 if (!temp) { 31190ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 31200ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31210ba2cbe9Sxc151355 } else { 31220ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 31230ba2cbe9Sxc151355 } 31240ba2cbe9Sxc151355 31250ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 3126*33343a97Smeem warn_dlerr(status, "could not delete secure object " 3127*33343a97Smeem "'%s'", sp->s_fields[i]); 31280ba2cbe9Sxc151355 } 31290ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 3130*33343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 3131*33343a97Smeem "secure object '%s'", sp->s_fields[i]); 31320ba2cbe9Sxc151355 } 31330ba2cbe9Sxc151355 } 31340ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 31350ba2cbe9Sxc151355 exit(1); 31360ba2cbe9Sxc151355 } 31370ba2cbe9Sxc151355 31380ba2cbe9Sxc151355 typedef struct show_secobj_state { 31390ba2cbe9Sxc151355 boolean_t ss_persist; 31400ba2cbe9Sxc151355 boolean_t ss_parseable; 31410ba2cbe9Sxc151355 boolean_t ss_debug; 31420ba2cbe9Sxc151355 boolean_t ss_header; 31430ba2cbe9Sxc151355 } show_secobj_state_t; 31440ba2cbe9Sxc151355 31450ba2cbe9Sxc151355 static void 31460ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep) 31470ba2cbe9Sxc151355 { 31480ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 31490ba2cbe9Sxc151355 if (statep->ss_debug) 31500ba2cbe9Sxc151355 (void) printf("%-30s", "VALUE"); 31510ba2cbe9Sxc151355 (void) putchar('\n'); 31520ba2cbe9Sxc151355 } 31530ba2cbe9Sxc151355 31540ba2cbe9Sxc151355 static boolean_t 31550ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 31560ba2cbe9Sxc151355 { 31570ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 31580ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 31590ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 31600ba2cbe9Sxc151355 uint_t flags = 0; 31610ba2cbe9Sxc151355 dladm_secobj_class_t class; 31620ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 31630ba2cbe9Sxc151355 dladm_status_t status; 31640ba2cbe9Sxc151355 31650ba2cbe9Sxc151355 if (statep->ss_persist) 31660ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 31670ba2cbe9Sxc151355 31680ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 3169*33343a97Smeem if (status != DLADM_STATUS_OK) 3170*33343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 31710ba2cbe9Sxc151355 31720ba2cbe9Sxc151355 if (statep->ss_header) { 31730ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 31740ba2cbe9Sxc151355 if (!statep->ss_parseable) 31750ba2cbe9Sxc151355 print_secobj_head(statep); 31760ba2cbe9Sxc151355 } 31770ba2cbe9Sxc151355 31780ba2cbe9Sxc151355 if (statep->ss_parseable) { 31790ba2cbe9Sxc151355 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 31800ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 31810ba2cbe9Sxc151355 } else { 31820ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", obj_name, 31830ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 31840ba2cbe9Sxc151355 } 31850ba2cbe9Sxc151355 31860ba2cbe9Sxc151355 if (statep->ss_debug) { 31870ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 31880ba2cbe9Sxc151355 uint_t len = sizeof (val); 31890ba2cbe9Sxc151355 31900ba2cbe9Sxc151355 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 31910ba2cbe9Sxc151355 if (statep->ss_parseable) 31920ba2cbe9Sxc151355 (void) printf("VALUE=\"0x%s\"", val); 31930ba2cbe9Sxc151355 else 31940ba2cbe9Sxc151355 (void) printf("0x%-30s", val); 31950ba2cbe9Sxc151355 } 31960ba2cbe9Sxc151355 } 31970ba2cbe9Sxc151355 (void) putchar('\n'); 31980ba2cbe9Sxc151355 return (B_TRUE); 31990ba2cbe9Sxc151355 } 32000ba2cbe9Sxc151355 32010ba2cbe9Sxc151355 static void 32020ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 32030ba2cbe9Sxc151355 { 32040ba2cbe9Sxc151355 int option; 32050ba2cbe9Sxc151355 show_secobj_state_t state; 32060ba2cbe9Sxc151355 dladm_status_t status; 32070ba2cbe9Sxc151355 uint_t i; 32080ba2cbe9Sxc151355 split_t *sp; 32090ba2cbe9Sxc151355 uint_t flags; 32100ba2cbe9Sxc151355 32110ba2cbe9Sxc151355 opterr = 0; 32120ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 32130ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 32140ba2cbe9Sxc151355 state.ss_debug = B_FALSE; 32150ba2cbe9Sxc151355 state.ss_header = B_TRUE; 32160ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":pPd", 32170ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 32180ba2cbe9Sxc151355 switch (option) { 32190ba2cbe9Sxc151355 case 'p': 32200ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 32210ba2cbe9Sxc151355 break; 32220ba2cbe9Sxc151355 case 'P': 32230ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 32240ba2cbe9Sxc151355 break; 32250ba2cbe9Sxc151355 case 'd': 3226*33343a97Smeem if (getuid() != 0) 3227*33343a97Smeem die("insufficient privileges"); 32280ba2cbe9Sxc151355 state.ss_debug = B_TRUE; 32290ba2cbe9Sxc151355 break; 32300ba2cbe9Sxc151355 default: 3231*33343a97Smeem die_opterr(optopt, option); 32320ba2cbe9Sxc151355 break; 32330ba2cbe9Sxc151355 } 32340ba2cbe9Sxc151355 } 32350ba2cbe9Sxc151355 32360ba2cbe9Sxc151355 if (optind == (argc - 1)) { 32370ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 32380ba2cbe9Sxc151355 if (sp == NULL) { 3239*33343a97Smeem die("invalid secure object name(s): '%s'", 3240*33343a97Smeem argv[optind]); 32410ba2cbe9Sxc151355 } 32420ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 32430ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 32440ba2cbe9Sxc151355 break; 32450ba2cbe9Sxc151355 } 32460ba2cbe9Sxc151355 splitfree(sp); 32470ba2cbe9Sxc151355 return; 32480ba2cbe9Sxc151355 } else if (optind != argc) 32490ba2cbe9Sxc151355 usage(); 32500ba2cbe9Sxc151355 32510ba2cbe9Sxc151355 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 32520ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 3253*33343a97Smeem if (status != DLADM_STATUS_OK) 3254*33343a97Smeem die_dlerr(status, "show-secobj"); 32550ba2cbe9Sxc151355 } 32560ba2cbe9Sxc151355 32570ba2cbe9Sxc151355 /* ARGSUSED */ 32580ba2cbe9Sxc151355 static void 32590ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 32600ba2cbe9Sxc151355 { 32610ba2cbe9Sxc151355 dladm_status_t status; 32620ba2cbe9Sxc151355 32630ba2cbe9Sxc151355 status = dladm_init_linkprop(); 3264*33343a97Smeem if (status != DLADM_STATUS_OK) 3265*33343a97Smeem die_dlerr(status, "link property initialization failed"); 32660ba2cbe9Sxc151355 } 32670ba2cbe9Sxc151355 32680ba2cbe9Sxc151355 /* ARGSUSED */ 32690ba2cbe9Sxc151355 static void 32700ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 32710ba2cbe9Sxc151355 { 32720ba2cbe9Sxc151355 dladm_status_t status; 32730ba2cbe9Sxc151355 32740ba2cbe9Sxc151355 status = dladm_init_secobj(); 3275*33343a97Smeem if (status != DLADM_STATUS_OK) 3276*33343a97Smeem die_dlerr(status, "secure object initialization failed"); 3277*33343a97Smeem } 3278*33343a97Smeem 3279*33343a97Smeem static boolean_t 3280*33343a97Smeem str2int(const char *str, int *valp) 3281*33343a97Smeem { 3282*33343a97Smeem int val; 3283*33343a97Smeem char *endp = NULL; 3284*33343a97Smeem 3285*33343a97Smeem errno = 0; 3286*33343a97Smeem val = strtol(str, &endp, 10); 3287*33343a97Smeem if (errno != 0 || *endp != '\0') 3288*33343a97Smeem return (B_FALSE); 3289*33343a97Smeem 3290*33343a97Smeem *valp = val; 3291*33343a97Smeem return (B_TRUE); 3292*33343a97Smeem } 3293*33343a97Smeem 3294*33343a97Smeem /* PRINTFLIKE1 */ 3295*33343a97Smeem static void 3296*33343a97Smeem warn(const char *format, ...) 3297*33343a97Smeem { 3298*33343a97Smeem va_list alist; 3299*33343a97Smeem 3300*33343a97Smeem format = gettext(format); 3301*33343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 3302*33343a97Smeem 3303*33343a97Smeem va_start(alist, format); 3304*33343a97Smeem (void) vfprintf(stderr, format, alist); 3305*33343a97Smeem va_end(alist); 3306*33343a97Smeem 3307*33343a97Smeem (void) putchar('\n'); 3308*33343a97Smeem } 3309*33343a97Smeem 3310*33343a97Smeem /* PRINTFLIKE2 */ 3311*33343a97Smeem static void 3312*33343a97Smeem warn_wlerr(wladm_status_t err, const char *format, ...) 3313*33343a97Smeem { 3314*33343a97Smeem va_list alist; 3315*33343a97Smeem char errmsg[WLADM_STRSIZE]; 3316*33343a97Smeem 3317*33343a97Smeem format = gettext(format); 3318*33343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 3319*33343a97Smeem 3320*33343a97Smeem va_start(alist, format); 3321*33343a97Smeem (void) vfprintf(stderr, format, alist); 3322*33343a97Smeem va_end(alist); 3323*33343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 3324*33343a97Smeem } 3325*33343a97Smeem 3326*33343a97Smeem /* PRINTFLIKE2 */ 3327*33343a97Smeem static void 3328*33343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 3329*33343a97Smeem { 3330*33343a97Smeem va_list alist; 3331*33343a97Smeem char errmsg[DLADM_STRSIZE]; 3332*33343a97Smeem 3333*33343a97Smeem format = gettext(format); 3334*33343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 3335*33343a97Smeem 3336*33343a97Smeem va_start(alist, format); 3337*33343a97Smeem (void) vfprintf(stderr, format, alist); 3338*33343a97Smeem va_end(alist); 3339*33343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3340*33343a97Smeem } 3341*33343a97Smeem 3342*33343a97Smeem /* PRINTFLIKE2 */ 3343*33343a97Smeem static void 3344*33343a97Smeem die_laerr(laadm_diag_t diag, const char *format, ...) 3345*33343a97Smeem { 3346*33343a97Smeem va_list alist; 3347*33343a97Smeem char *errstr = strerror(errno); 3348*33343a97Smeem 3349*33343a97Smeem format = gettext(format); 3350*33343a97Smeem (void) fprintf(stderr, "%s: ", progname); 3351*33343a97Smeem 3352*33343a97Smeem va_start(alist, format); 3353*33343a97Smeem (void) vfprintf(stderr, format, alist); 3354*33343a97Smeem va_end(alist); 3355*33343a97Smeem 3356*33343a97Smeem if (diag == 0) 3357*33343a97Smeem (void) fprintf(stderr, ": %s\n", errstr); 3358*33343a97Smeem else 3359*33343a97Smeem (void) fprintf(stderr, ": %s (%s)\n", errstr, laadm_diag(diag)); 3360*33343a97Smeem 3361*33343a97Smeem exit(EXIT_FAILURE); 3362*33343a97Smeem } 3363*33343a97Smeem 3364*33343a97Smeem /* PRINTFLIKE2 */ 3365*33343a97Smeem static void 3366*33343a97Smeem die_wlerr(wladm_status_t err, const char *format, ...) 3367*33343a97Smeem { 3368*33343a97Smeem va_list alist; 3369*33343a97Smeem char errmsg[WLADM_STRSIZE]; 3370*33343a97Smeem 3371*33343a97Smeem format = gettext(format); 3372*33343a97Smeem (void) fprintf(stderr, "%s: ", progname); 3373*33343a97Smeem 3374*33343a97Smeem va_start(alist, format); 3375*33343a97Smeem (void) vfprintf(stderr, format, alist); 3376*33343a97Smeem va_end(alist); 3377*33343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 3378*33343a97Smeem 3379*33343a97Smeem exit(EXIT_FAILURE); 3380*33343a97Smeem } 3381*33343a97Smeem 3382*33343a97Smeem /* PRINTFLIKE2 */ 3383*33343a97Smeem static void 3384*33343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 3385*33343a97Smeem { 3386*33343a97Smeem va_list alist; 3387*33343a97Smeem char errmsg[DLADM_STRSIZE]; 3388*33343a97Smeem 3389*33343a97Smeem format = gettext(format); 3390*33343a97Smeem (void) fprintf(stderr, "%s: ", progname); 3391*33343a97Smeem 3392*33343a97Smeem va_start(alist, format); 3393*33343a97Smeem (void) vfprintf(stderr, format, alist); 3394*33343a97Smeem va_end(alist); 3395*33343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 3396*33343a97Smeem 3397*33343a97Smeem exit(EXIT_FAILURE); 3398*33343a97Smeem } 3399*33343a97Smeem 3400*33343a97Smeem /* PRINTFLIKE1 */ 3401*33343a97Smeem static void 3402*33343a97Smeem die(const char *format, ...) 3403*33343a97Smeem { 3404*33343a97Smeem va_list alist; 3405*33343a97Smeem 3406*33343a97Smeem format = gettext(format); 3407*33343a97Smeem (void) fprintf(stderr, "%s: ", progname); 3408*33343a97Smeem 3409*33343a97Smeem va_start(alist, format); 3410*33343a97Smeem (void) vfprintf(stderr, format, alist); 3411*33343a97Smeem va_end(alist); 3412*33343a97Smeem 3413*33343a97Smeem (void) putchar('\n'); 3414*33343a97Smeem exit(EXIT_FAILURE); 3415*33343a97Smeem } 3416*33343a97Smeem 3417*33343a97Smeem static void 3418*33343a97Smeem die_optdup(int opt) 3419*33343a97Smeem { 3420*33343a97Smeem die("the option -%c cannot be specified more than once", opt); 3421*33343a97Smeem } 3422*33343a97Smeem 3423*33343a97Smeem static void 3424*33343a97Smeem die_opterr(int opt, int opterr) 3425*33343a97Smeem { 3426*33343a97Smeem switch (opterr) { 3427*33343a97Smeem case ':': 3428*33343a97Smeem die("option '-%c' requires a value", opt); 3429*33343a97Smeem break; 3430*33343a97Smeem case '?': 3431*33343a97Smeem default: 3432*33343a97Smeem die("unrecognized option '-%c'", opt); 3433*33343a97Smeem break; 34340ba2cbe9Sxc151355 } 34350ba2cbe9Sxc151355 } 3436