17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5219a2a31Shl157128 * Common Development and Distribution License (the "License"). 6219a2a31Shl157128 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22f4b3ec61Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 290ba2cbe9Sxc151355 #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <locale.h> 310ba2cbe9Sxc151355 #include <signal.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <stropts.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <kstat.h> 397c478bd9Sstevel@tonic-gate #include <strings.h> 407c478bd9Sstevel@tonic-gate #include <getopt.h> 417c478bd9Sstevel@tonic-gate #include <unistd.h> 42cd93090eSericheng #include <priv.h> 430ba2cbe9Sxc151355 #include <termios.h> 440ba2cbe9Sxc151355 #include <pwd.h> 450ba2cbe9Sxc151355 #include <auth_attr.h> 460ba2cbe9Sxc151355 #include <auth_list.h> 477c478bd9Sstevel@tonic-gate #include <libintl.h> 487c478bd9Sstevel@tonic-gate #include <libdlpi.h> 497c478bd9Sstevel@tonic-gate #include <libdladm.h> 507c478bd9Sstevel@tonic-gate #include <liblaadm.h> 517c478bd9Sstevel@tonic-gate #include <libmacadm.h> 520ba2cbe9Sxc151355 #include <libwladm.h> 530ba2cbe9Sxc151355 #include <libinetutil.h> 540ba2cbe9Sxc151355 #include <bsm/adt.h> 550ba2cbe9Sxc151355 #include <bsm/adt_event.h> 567c478bd9Sstevel@tonic-gate 57ba2e4443Sseb #define AGGR_DRV "aggr" 587c478bd9Sstevel@tonic-gate #define MAXPORT 256 597c478bd9Sstevel@tonic-gate #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 607c478bd9Sstevel@tonic-gate "%-5s %-4s %-4s %-9s %-7s\n" 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate typedef struct pktsum_s { 637c478bd9Sstevel@tonic-gate uint64_t ipackets; 647c478bd9Sstevel@tonic-gate uint64_t opackets; 657c478bd9Sstevel@tonic-gate uint64_t rbytes; 667c478bd9Sstevel@tonic-gate uint64_t obytes; 677c478bd9Sstevel@tonic-gate uint32_t ierrors; 687c478bd9Sstevel@tonic-gate uint32_t oerrors; 697c478bd9Sstevel@tonic-gate } pktsum_t; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate typedef struct show_link_state { 727c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 737c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 747c478bd9Sstevel@tonic-gate boolean_t ls_stats; 757c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 767c478bd9Sstevel@tonic-gate boolean_t ls_parseable; 777c478bd9Sstevel@tonic-gate } show_link_state_t; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 807c478bd9Sstevel@tonic-gate uint32_t gs_key; 817c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 827c478bd9Sstevel@tonic-gate boolean_t gs_found; 837c478bd9Sstevel@tonic-gate boolean_t gs_stats; 847c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 857c478bd9Sstevel@tonic-gate pktsum_t gs_prevstats[MAXPORT]; 867c478bd9Sstevel@tonic-gate boolean_t gs_parseable; 877c478bd9Sstevel@tonic-gate } show_grp_state_t; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate typedef struct show_mac_state { 907c478bd9Sstevel@tonic-gate boolean_t ms_firstonly; 917c478bd9Sstevel@tonic-gate boolean_t ms_donefirst; 927c478bd9Sstevel@tonic-gate pktsum_t ms_prevstats; 937c478bd9Sstevel@tonic-gate boolean_t ms_parseable; 947c478bd9Sstevel@tonic-gate } show_mac_state_t; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate typedef struct port_state { 977c478bd9Sstevel@tonic-gate char *state_name; 987c478bd9Sstevel@tonic-gate aggr_port_state_t state_num; 997c478bd9Sstevel@tonic-gate } port_state_t; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate static port_state_t port_states[] = { 1027c478bd9Sstevel@tonic-gate {"standby", AGGR_PORT_STATE_STANDBY }, 1037c478bd9Sstevel@tonic-gate {"attached", AGGR_PORT_STATE_ATTACHED } 1047c478bd9Sstevel@tonic-gate }; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 1077c478bd9Sstevel@tonic-gate 1080ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **); 1090ba2cbe9Sxc151355 1100ba2cbe9Sxc151355 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi; 1110ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 1120ba2cbe9Sxc151355 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr, do_down_aggr; 1130ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 1140ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 1150ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 1160ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 1177c478bd9Sstevel@tonic-gate 118f4b3ec61Sdh155122 static void show_linkprop_onelink(void *, const char *); 119f4b3ec61Sdh155122 12033343a97Smeem static void link_stats(const char *, uint_t); 12133343a97Smeem static void aggr_stats(uint32_t, uint_t); 1227c478bd9Sstevel@tonic-gate static void dev_stats(const char *dev, uint32_t); 1237c478bd9Sstevel@tonic-gate 124ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 1257c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 126ba2e4443Sseb static uint64_t mac_ifspeed(const char *); 127ba2e4443Sseb static char *mac_link_state(const char *); 128ba2e4443Sseb static char *mac_link_duplex(const char *); 1297c478bd9Sstevel@tonic-gate static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 1307c478bd9Sstevel@tonic-gate static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 1317c478bd9Sstevel@tonic-gate 13233343a97Smeem static boolean_t str2int(const char *, int *); 13333343a97Smeem static void die(const char *, ...); 13433343a97Smeem static void die_optdup(int); 13533343a97Smeem static void die_opterr(int, int); 13633343a97Smeem static void die_laerr(laadm_diag_t, const char *, ...); 13733343a97Smeem static void die_wlerr(wladm_status_t, const char *, ...); 13833343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 13933343a97Smeem static void warn(const char *, ...); 14033343a97Smeem static void warn_wlerr(wladm_status_t, const char *, ...); 14133343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 14233343a97Smeem 1437c478bd9Sstevel@tonic-gate typedef struct cmd { 1447c478bd9Sstevel@tonic-gate char *c_name; 1450ba2cbe9Sxc151355 cmdfunc_t *c_fn; 1467c478bd9Sstevel@tonic-gate } cmd_t; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 1497c478bd9Sstevel@tonic-gate { "show-link", do_show_link }, 150210db224Sericheng { "show-dev", do_show_dev }, 1517c478bd9Sstevel@tonic-gate { "create-aggr", do_create_aggr }, 1527c478bd9Sstevel@tonic-gate { "delete-aggr", do_delete_aggr }, 1537c478bd9Sstevel@tonic-gate { "add-aggr", do_add_aggr }, 1547c478bd9Sstevel@tonic-gate { "remove-aggr", do_remove_aggr }, 1557c478bd9Sstevel@tonic-gate { "modify-aggr", do_modify_aggr }, 1567c478bd9Sstevel@tonic-gate { "show-aggr", do_show_aggr }, 1577c478bd9Sstevel@tonic-gate { "up-aggr", do_up_aggr }, 1580ba2cbe9Sxc151355 { "down-aggr", do_down_aggr }, 1590ba2cbe9Sxc151355 { "scan-wifi", do_scan_wifi }, 1600ba2cbe9Sxc151355 { "connect-wifi", do_connect_wifi }, 1610ba2cbe9Sxc151355 { "disconnect-wifi", do_disconnect_wifi }, 1620ba2cbe9Sxc151355 { "show-wifi", do_show_wifi }, 1630ba2cbe9Sxc151355 { "show-linkprop", do_show_linkprop }, 1640ba2cbe9Sxc151355 { "set-linkprop", do_set_linkprop }, 1650ba2cbe9Sxc151355 { "reset-linkprop", do_reset_linkprop }, 1660ba2cbe9Sxc151355 { "create-secobj", do_create_secobj }, 1670ba2cbe9Sxc151355 { "delete-secobj", do_delete_secobj }, 1680ba2cbe9Sxc151355 { "show-secobj", do_show_secobj }, 1690ba2cbe9Sxc151355 { "init-linkprop", do_init_linkprop }, 1700ba2cbe9Sxc151355 { "init-secobj", do_init_secobj } 1717c478bd9Sstevel@tonic-gate }; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static const struct option longopts[] = { 1747c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v' }, 1757c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd' }, 1767c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P' }, 1777c478bd9Sstevel@tonic-gate {"lacp-mode", required_argument, 0, 'l' }, 1787c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T' }, 1797c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u' }, 1807c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's' }, 1817c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i' }, 1827c478bd9Sstevel@tonic-gate {"lacp", no_argument, 0, 'L' }, 1837c478bd9Sstevel@tonic-gate {"temporary", no_argument, 0, 't' }, 1847c478bd9Sstevel@tonic-gate {"root-dir", required_argument, 0, 'r' }, 1857c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p' }, 1867c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 1877c478bd9Sstevel@tonic-gate }; 1887c478bd9Sstevel@tonic-gate 1890ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 1900ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 1910ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 1920ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 1930ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 1940ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 1950ba2cbe9Sxc151355 { 0, 0, 0, 0 } 1960ba2cbe9Sxc151355 }; 1970ba2cbe9Sxc151355 1980ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 1990ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 2000ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 2010ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 2020ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 2030ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 2040ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 2050ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 2060ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 2070ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 2080ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 2090ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 2100ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 2110ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 2120ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 2130ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 2140ba2cbe9Sxc151355 { 0, 0, 0, 0 } 2150ba2cbe9Sxc151355 }; 2160ba2cbe9Sxc151355 2177c478bd9Sstevel@tonic-gate static char *progname; 2180ba2cbe9Sxc151355 static sig_atomic_t signalled; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate static void 2217c478bd9Sstevel@tonic-gate usage(void) 2227c478bd9Sstevel@tonic-gate { 2230ba2cbe9Sxc151355 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 2240ba2cbe9Sxc151355 "\tshow-link [-p] [-s [-i <interval>]] [<name>]\n" 2250ba2cbe9Sxc151355 "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" 2260ba2cbe9Sxc151355 "\n" 2270ba2cbe9Sxc151355 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2280ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] -d <dev> ... <key>\n" 2290ba2cbe9Sxc151355 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-l <mode>]\n" 2300ba2cbe9Sxc151355 "\t [-T <time>] [-u <address>] <key>\n" 2310ba2cbe9Sxc151355 "\tdelete-aggr [-t] [-R <root-dir>] <key>\n" 2320ba2cbe9Sxc151355 "\tadd-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2330ba2cbe9Sxc151355 "\tremove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 2340ba2cbe9Sxc151355 "\tshow-aggr [-pL][-s [-i <interval>]] [<key>]\n" 2350ba2cbe9Sxc151355 "\n" 2360ba2cbe9Sxc151355 "\tscan-wifi [-p] [-o <field>,...] [<name>]\n" 2370ba2cbe9Sxc151355 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 2380ba2cbe9Sxc151355 " [-s wep]\n" 2390ba2cbe9Sxc151355 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 2400ba2cbe9Sxc151355 "\t [-T <time>] [<name>]\n" 2410ba2cbe9Sxc151355 "\tdisconnect-wifi [-a] [<name>]\n" 2420ba2cbe9Sxc151355 "\tshow-wifi [-p] [-o <field>,...] [<name>]\n" 2430ba2cbe9Sxc151355 "\n" 2440ba2cbe9Sxc151355 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 2450ba2cbe9Sxc151355 " <name>\n" 2460ba2cbe9Sxc151355 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 2470ba2cbe9Sxc151355 "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" 2480ba2cbe9Sxc151355 "\n" 2490ba2cbe9Sxc151355 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 2500ba2cbe9Sxc151355 " <secobj>\n" 2510ba2cbe9Sxc151355 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 2520ba2cbe9Sxc151355 "\tshow-secobj [-pP][<secobj>,...]\n")); 2537c478bd9Sstevel@tonic-gate exit(1); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate int 2577c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate int i; 2607c478bd9Sstevel@tonic-gate cmd_t *cmdp; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2637c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2647c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2657c478bd9Sstevel@tonic-gate #endif 2667c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate progname = argv[0]; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (argc < 2) 2717c478bd9Sstevel@tonic-gate usage(); 2727c478bd9Sstevel@tonic-gate 273cd93090eSericheng if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 27433343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 27533343a97Smeem die("insufficient privileges"); 276cd93090eSericheng 2777c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 2787c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 2797c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 2807c478bd9Sstevel@tonic-gate cmdp->c_fn(argc - 1, &argv[1]); 2817c478bd9Sstevel@tonic-gate exit(0); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 2867c478bd9Sstevel@tonic-gate progname, argv[1]); 2877c478bd9Sstevel@tonic-gate usage(); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate return (0); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate static void 2937c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[]) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate char option; 29633343a97Smeem int key; 2977c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 2987c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2997c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 3007c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 3017c478bd9Sstevel@tonic-gate uint_t nport = 0; 3027c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 3037c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 3047c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 3057c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 3067c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3077c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 3087c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 3097c478bd9Sstevel@tonic-gate char *altroot = NULL; 3107c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate opterr = 0; 3137c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 3147c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 3157c478bd9Sstevel@tonic-gate switch (option) { 3167c478bd9Sstevel@tonic-gate case 'd': 31733343a97Smeem if (nport >= MAXPORT) 31833343a97Smeem die("too many <dev> arguments"); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 32133343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 32233343a97Smeem die("device name too long"); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate nport++; 3257c478bd9Sstevel@tonic-gate break; 3267c478bd9Sstevel@tonic-gate case 'P': 32733343a97Smeem if (P_arg) 32833343a97Smeem die_optdup(option); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 33133343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 33233343a97Smeem die("invalid policy '%s'", optarg); 3337c478bd9Sstevel@tonic-gate break; 3347c478bd9Sstevel@tonic-gate case 'u': 33533343a97Smeem if (u_arg) 33633343a97Smeem die_optdup(option); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 3397c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 34033343a97Smeem mac_addr)) 34133343a97Smeem die("invalid MAC address '%s'", optarg); 3427c478bd9Sstevel@tonic-gate break; 3437c478bd9Sstevel@tonic-gate case 'l': 34433343a97Smeem if (l_arg) 34533343a97Smeem die_optdup(option); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 34833343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 34933343a97Smeem die("invalid LACP mode '%s'", optarg); 3507c478bd9Sstevel@tonic-gate break; 3517c478bd9Sstevel@tonic-gate case 'T': 35233343a97Smeem if (T_arg) 35333343a97Smeem die_optdup(option); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 35633343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 35733343a97Smeem die("invalid LACP timer value '%s'", optarg); 3587c478bd9Sstevel@tonic-gate break; 3597c478bd9Sstevel@tonic-gate case 't': 3607c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 3617c478bd9Sstevel@tonic-gate break; 3627c478bd9Sstevel@tonic-gate case 'R': 3637c478bd9Sstevel@tonic-gate altroot = optarg; 3647c478bd9Sstevel@tonic-gate break; 3657c478bd9Sstevel@tonic-gate default: 36633343a97Smeem die_opterr(optopt, option); 36733343a97Smeem break; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (nport == 0) 3727c478bd9Sstevel@tonic-gate usage(); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 3757c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 3767c478bd9Sstevel@tonic-gate usage(); 3777c478bd9Sstevel@tonic-gate 37833343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 37933343a97Smeem die("invalid key value '%s'", argv[optind]); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (laadm_create(key, nport, port, policy, mac_addr_fixed, 38233343a97Smeem mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 38333343a97Smeem die_laerr(diag, "create operation failed"); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate static void 3877c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[]) 3887c478bd9Sstevel@tonic-gate { 38933343a97Smeem int key; 3907c478bd9Sstevel@tonic-gate char option; 3917c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 3927c478bd9Sstevel@tonic-gate char *altroot = NULL; 3937c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate opterr = 0; 3967c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":R:t", longopts, 3977c478bd9Sstevel@tonic-gate NULL)) != -1) { 3987c478bd9Sstevel@tonic-gate switch (option) { 3997c478bd9Sstevel@tonic-gate case 't': 4007c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4017c478bd9Sstevel@tonic-gate break; 4027c478bd9Sstevel@tonic-gate case 'R': 4037c478bd9Sstevel@tonic-gate altroot = optarg; 4047c478bd9Sstevel@tonic-gate break; 4057c478bd9Sstevel@tonic-gate default: 40633343a97Smeem die_opterr(optopt, option); 4077c478bd9Sstevel@tonic-gate break; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4127c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4137c478bd9Sstevel@tonic-gate usage(); 4147c478bd9Sstevel@tonic-gate 41533343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 41633343a97Smeem die("invalid key value '%s'", argv[optind]); 4177c478bd9Sstevel@tonic-gate 41833343a97Smeem if (laadm_delete(key, t_arg, altroot, &diag) < 0) 41933343a97Smeem die_laerr(diag, "delete operation failed"); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate static void 4237c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[]) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate char option; 42633343a97Smeem int key; 4277c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4287c478bd9Sstevel@tonic-gate uint_t nport = 0; 4297c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4307c478bd9Sstevel@tonic-gate char *altroot = NULL; 4317c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate opterr = 0; 4347c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 4357c478bd9Sstevel@tonic-gate NULL)) != -1) { 4367c478bd9Sstevel@tonic-gate switch (option) { 4377c478bd9Sstevel@tonic-gate case 'd': 43833343a97Smeem if (nport >= MAXPORT) 43933343a97Smeem die("too many <dev> arguments"); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 44233343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 44333343a97Smeem die("device name too long"); 44433343a97Smeem 4457c478bd9Sstevel@tonic-gate nport++; 4467c478bd9Sstevel@tonic-gate break; 4477c478bd9Sstevel@tonic-gate case 't': 4487c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 4497c478bd9Sstevel@tonic-gate break; 4507c478bd9Sstevel@tonic-gate case 'R': 4517c478bd9Sstevel@tonic-gate altroot = optarg; 4527c478bd9Sstevel@tonic-gate break; 4537c478bd9Sstevel@tonic-gate default: 45433343a97Smeem die_opterr(optopt, option); 45533343a97Smeem break; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (nport == 0) 4607c478bd9Sstevel@tonic-gate usage(); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 4637c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 4647c478bd9Sstevel@tonic-gate usage(); 4657c478bd9Sstevel@tonic-gate 46633343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 46733343a97Smeem die("invalid key value '%s'", argv[optind]); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 470219a2a31Shl157128 /* 471219a2a31Shl157128 * checking ENOTSUP is a temporary workaround 472219a2a31Shl157128 * and should be removed once 6399681 is fixed. 473219a2a31Shl157128 */ 474219a2a31Shl157128 if (errno == ENOTSUP) { 475219a2a31Shl157128 (void) fprintf(stderr, 476219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 477219a2a31Shl157128 progname, 478219a2a31Shl157128 gettext("device capabilities don't match")); 479219a2a31Shl157128 exit(ENOTSUP); 480219a2a31Shl157128 } 48133343a97Smeem die_laerr(diag, "add operation failed"); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate static void 4867c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[]) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate char option; 48933343a97Smeem int key; 4907c478bd9Sstevel@tonic-gate laadm_port_attr_db_t port[MAXPORT]; 4917c478bd9Sstevel@tonic-gate uint_t nport = 0; 4927c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 4937c478bd9Sstevel@tonic-gate char *altroot = NULL; 4947c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate opterr = 0; 4977c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":d:R:t", 4987c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 4997c478bd9Sstevel@tonic-gate switch (option) { 5007c478bd9Sstevel@tonic-gate case 'd': 50133343a97Smeem if (nport >= MAXPORT) 50233343a97Smeem die("too many <dev> arguments"); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate if (strlcpy(port[nport].lp_devname, optarg, 50533343a97Smeem MAXNAMELEN) >= MAXNAMELEN) 50633343a97Smeem die("device name too long"); 50733343a97Smeem 5087c478bd9Sstevel@tonic-gate nport++; 5097c478bd9Sstevel@tonic-gate break; 5107c478bd9Sstevel@tonic-gate case 't': 5117c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5127c478bd9Sstevel@tonic-gate break; 5137c478bd9Sstevel@tonic-gate case 'R': 5147c478bd9Sstevel@tonic-gate altroot = optarg; 5157c478bd9Sstevel@tonic-gate break; 5167c478bd9Sstevel@tonic-gate default: 51733343a97Smeem die_opterr(optopt, option); 51833343a97Smeem break; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate if (nport == 0) 5237c478bd9Sstevel@tonic-gate usage(); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 5267c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 5277c478bd9Sstevel@tonic-gate usage(); 5287c478bd9Sstevel@tonic-gate 52933343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 53033343a97Smeem die("invalid key value '%s'", argv[optind]); 5317c478bd9Sstevel@tonic-gate 53233343a97Smeem if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) 53333343a97Smeem die_laerr(diag, "remove operation failed"); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate static void 5377c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[]) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate char option; 54033343a97Smeem int key; 5417c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 5427c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 5437c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 5447c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 5457c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 5467c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 5477c478bd9Sstevel@tonic-gate boolean_t t_arg = B_FALSE; 5487c478bd9Sstevel@tonic-gate char *altroot = NULL; 5497c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate opterr = 0; 5527c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 5537c478bd9Sstevel@tonic-gate NULL)) != -1) { 5547c478bd9Sstevel@tonic-gate switch (option) { 5557c478bd9Sstevel@tonic-gate case 'P': 55633343a97Smeem if (modify_mask & LAADM_MODIFY_POLICY) 55733343a97Smeem die_optdup(option); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_POLICY; 5607c478bd9Sstevel@tonic-gate 56133343a97Smeem if (!laadm_str_to_policy(optarg, &policy)) 56233343a97Smeem die("invalid policy '%s'", optarg); 5637c478bd9Sstevel@tonic-gate break; 5647c478bd9Sstevel@tonic-gate case 'u': 56533343a97Smeem if (modify_mask & LAADM_MODIFY_MAC) 56633343a97Smeem die_optdup(option); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_MAC; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 57133343a97Smeem mac_addr)) 57233343a97Smeem die("invalid MAC address '%s'", optarg); 5737c478bd9Sstevel@tonic-gate break; 5747c478bd9Sstevel@tonic-gate case 'l': 57533343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_MODE) 57633343a97Smeem die_optdup(option); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_MODE; 5797c478bd9Sstevel@tonic-gate 58033343a97Smeem if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) 58133343a97Smeem die("invalid LACP mode '%s'", optarg); 5827c478bd9Sstevel@tonic-gate break; 5837c478bd9Sstevel@tonic-gate case 'T': 58433343a97Smeem if (modify_mask & LAADM_MODIFY_LACP_TIMER) 58533343a97Smeem die_optdup(option); 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate modify_mask |= LAADM_MODIFY_LACP_TIMER; 5887c478bd9Sstevel@tonic-gate 58933343a97Smeem if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) 59033343a97Smeem die("invalid LACP timer value '%s'", optarg); 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate case 't': 5937c478bd9Sstevel@tonic-gate t_arg = B_TRUE; 5947c478bd9Sstevel@tonic-gate break; 5957c478bd9Sstevel@tonic-gate case 'R': 5967c478bd9Sstevel@tonic-gate altroot = optarg; 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate default: 59933343a97Smeem die_opterr(optopt, option); 60033343a97Smeem break; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 60433343a97Smeem if (modify_mask == 0) 60533343a97Smeem die("at least one of the -PulT options must be specified"); 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* get key value (required last argument) */ 6087c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 6097c478bd9Sstevel@tonic-gate usage(); 6107c478bd9Sstevel@tonic-gate 61133343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 61233343a97Smeem die("invalid key value '%s'", argv[optind]); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 61533343a97Smeem lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) 61633343a97Smeem die_laerr(diag, "modify operation failed"); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate static void 6207c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[]) 6217c478bd9Sstevel@tonic-gate { 62233343a97Smeem int key = 0; 6237c478bd9Sstevel@tonic-gate laadm_diag_t diag = 0; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6267c478bd9Sstevel@tonic-gate if (argc == 2) { 62733343a97Smeem if (!str2int(argv[1], &key) || key < 1) 62833343a97Smeem die("invalid key value '%s'", argv[1]); 6297c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6307c478bd9Sstevel@tonic-gate usage(); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate if (laadm_up(key, NULL, &diag) < 0) { 6347c478bd9Sstevel@tonic-gate if (key != 0) { 63533343a97Smeem die_laerr(diag, "could not bring up aggregation '%u'", 63633343a97Smeem key); 6377c478bd9Sstevel@tonic-gate } else { 63833343a97Smeem die_laerr(diag, "could not bring aggregations up"); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate static void 6447c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[]) 6457c478bd9Sstevel@tonic-gate { 64633343a97Smeem int key = 0; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 6497c478bd9Sstevel@tonic-gate if (argc == 2) { 65033343a97Smeem if (!str2int(argv[1], &key) || key < 1) 65133343a97Smeem die("invalid key value '%s'", argv[1]); 6527c478bd9Sstevel@tonic-gate } else if (argc > 2) { 6537c478bd9Sstevel@tonic-gate usage(); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if (laadm_down(key) < 0) { 6577c478bd9Sstevel@tonic-gate if (key != 0) { 65833343a97Smeem die("could not bring down aggregation '%u': %s", 65933343a97Smeem key, strerror(errno)); 6607c478bd9Sstevel@tonic-gate } else { 66133343a97Smeem die("could not bring down aggregations: %s", 66233343a97Smeem strerror(errno)); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate #define TYPE_WIDTH 10 668210db224Sericheng 669210db224Sericheng static void 670210db224Sericheng print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 671210db224Sericheng { 672210db224Sericheng char type[TYPE_WIDTH]; 673210db224Sericheng 674210db224Sericheng if (!legacy) { 675*c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 676*c7e4935fSss150715 uint_t instance; 677ba2e4443Sseb 678210db224Sericheng if (dap->da_vid != 0) { 679210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "vlan %u", 680210db224Sericheng dap->da_vid); 681210db224Sericheng } else { 682210db224Sericheng (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 683210db224Sericheng } 684*c7e4935fSss150715 685*c7e4935fSss150715 if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS) 686ba2e4443Sseb return; 687*c7e4935fSss150715 688ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 689210db224Sericheng (void) printf("%s type=%s mtu=%d key=%u\n", 690ba2e4443Sseb name, type, dap->da_max_sdu, instance); 691210db224Sericheng } else { 692210db224Sericheng (void) printf("%s type=%s mtu=%d device=%s\n", 693210db224Sericheng name, type, dap->da_max_sdu, dap->da_dev); 694210db224Sericheng } 695210db224Sericheng } else { 696210db224Sericheng (void) printf("%s type=legacy mtu=%d device=%s\n", 697210db224Sericheng name, dap->da_max_sdu, name); 698210db224Sericheng } 699210db224Sericheng } 700210db224Sericheng 701210db224Sericheng static void 702210db224Sericheng print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 703210db224Sericheng { 704210db224Sericheng char type[TYPE_WIDTH]; 705210db224Sericheng 706210db224Sericheng if (!legacy) { 707*c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 708*c7e4935fSss150715 uint_t instance; 709ba2e4443Sseb 710210db224Sericheng if (dap->da_vid != 0) { 711210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 712210db224Sericheng dap->da_vid); 713210db224Sericheng } else { 714210db224Sericheng (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 715210db224Sericheng } 716*c7e4935fSss150715 717*c7e4935fSss150715 if (dlpi_parselink(dap->da_dev, drv, &instance) != DLPI_SUCCESS) 718ba2e4443Sseb return; 719ba2e4443Sseb if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 720210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 721210db224Sericheng "\taggregation: key %u\n"), name, type, 722ba2e4443Sseb dap->da_max_sdu, instance); 723210db224Sericheng } else { 724210db224Sericheng (void) printf(gettext("%-9s\ttype: %s\tmtu: " 725210db224Sericheng "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 726210db224Sericheng dap->da_dev); 727210db224Sericheng } 728210db224Sericheng } else { 729210db224Sericheng (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 730210db224Sericheng "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 731210db224Sericheng } 732210db224Sericheng } 733210db224Sericheng 734210db224Sericheng static int 735210db224Sericheng get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 736210db224Sericheng { 737210db224Sericheng int err; 738210db224Sericheng 739210db224Sericheng if ((err = dladm_info(name, dlattrp)) == 0) { 740210db224Sericheng *legacy = B_FALSE; 741210db224Sericheng } else if (err < 0 && errno == ENODEV) { 742*c7e4935fSss150715 dlpi_handle_t dh; 743*c7e4935fSss150715 dlpi_info_t dlinfo; 744210db224Sericheng 745210db224Sericheng /* 746210db224Sericheng * A return value of ENODEV means that the specified 747210db224Sericheng * device is not gldv3. 748210db224Sericheng */ 749*c7e4935fSss150715 if (dlpi_open(name, &dh, 0) != DLPI_SUCCESS) { 750210db224Sericheng errno = ENOENT; 751210db224Sericheng return (-1); 752210db224Sericheng } 753*c7e4935fSss150715 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 754*c7e4935fSss150715 dlpi_close(dh); 755*c7e4935fSss150715 errno = EINVAL; 756*c7e4935fSss150715 return (-1); 757*c7e4935fSss150715 } 758*c7e4935fSss150715 dlpi_close(dh); 759*c7e4935fSss150715 *legacy = B_TRUE; 760*c7e4935fSss150715 bzero(dlattrp, sizeof (*dlattrp)); 761*c7e4935fSss150715 dlattrp->da_max_sdu = dlinfo.di_max_sdu; 762*c7e4935fSss150715 763210db224Sericheng } else { 764210db224Sericheng /* 765210db224Sericheng * If the return value is not ENODEV, this means that 766210db224Sericheng * user is either passing in a bogus interface name 767210db224Sericheng * or a vlan interface name that doesn't exist yet. 768210db224Sericheng */ 769210db224Sericheng errno = ENOENT; 770210db224Sericheng return (-1); 771210db224Sericheng } 772210db224Sericheng return (0); 773210db224Sericheng } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7767c478bd9Sstevel@tonic-gate static void 7777c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate dladm_attr_t dlattr; 780210db224Sericheng boolean_t legacy = B_TRUE; 7817c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7827c478bd9Sstevel@tonic-gate 78333343a97Smeem if (get_if_info(name, &dlattr, &legacy) < 0) 78433343a97Smeem die("invalid link '%s'", name); 7857c478bd9Sstevel@tonic-gate 786210db224Sericheng if (state->ls_parseable) { 787210db224Sericheng print_link_parseable(name, &dlattr, legacy); 7887c478bd9Sstevel@tonic-gate } else { 789210db224Sericheng print_link(name, &dlattr, legacy); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate static void 7947c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name) 7957c478bd9Sstevel@tonic-gate { 7967c478bd9Sstevel@tonic-gate show_link_state_t *state = (show_link_state_t *)arg; 7977c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 8007c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 8017c478bd9Sstevel@tonic-gate return; 8027c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 8037c478bd9Sstevel@tonic-gate } else { 8047c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate get_link_stats(name, &stats); 8087c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ls_prevstats); 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate (void) printf("%s", name); 8117c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 8127c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 8137c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 8147c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 8157c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 8167c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate static void 8227c478bd9Sstevel@tonic-gate dump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8237c478bd9Sstevel@tonic-gate { 8247c478bd9Sstevel@tonic-gate char policy_str[LAADM_POLICY_STR_LEN]; 8257c478bd9Sstevel@tonic-gate char addr_str[ETHERADDRL * 3]; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if (!parseable) { 8287c478bd9Sstevel@tonic-gate (void) printf(gettext("key: %d (0x%04x)"), 8297c478bd9Sstevel@tonic-gate grp->lg_key, grp->lg_key); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate (void) printf(gettext("\tpolicy: %s"), 8327c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate (void) printf(gettext("\taddress: %s (%s)\n"), 8357c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str), 8367c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 8377c478bd9Sstevel@tonic-gate } else { 8387c478bd9Sstevel@tonic-gate (void) printf("aggr key=%d", grp->lg_key); 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate (void) printf(" policy=%s", 8417c478bd9Sstevel@tonic-gate laadm_policy_to_str(grp->lg_policy, policy_str)); 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate (void) printf(" address=%s", 8447c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate (void) printf(" address-type=%s\n", 8477c478bd9Sstevel@tonic-gate (grp->lg_mac_fixed) ? "fixed" : "auto"); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate static void 8527c478bd9Sstevel@tonic-gate dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 8557c478bd9Sstevel@tonic-gate const char *lacp_timer_str = 8567c478bd9Sstevel@tonic-gate laadm_lacp_timer_to_str(grp->lg_lacp_timer); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate if (!parseable) { 8597c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 8607c478bd9Sstevel@tonic-gate (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 8617c478bd9Sstevel@tonic-gate } else { 8627c478bd9Sstevel@tonic-gate (void) printf(" lacp-mode=%s", lacp_mode_str); 8637c478bd9Sstevel@tonic-gate (void) printf(" lacp-timer=%s\n", lacp_timer_str); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate static void 8687c478bd9Sstevel@tonic-gate dump_grp_stats(laadm_grp_attr_sys_t *grp) 8697c478bd9Sstevel@tonic-gate { 8707c478bd9Sstevel@tonic-gate (void) printf("key: %d", grp->lg_key); 8717c478bd9Sstevel@tonic-gate (void) printf("\tipackets rbytes opackets obytes "); 8727c478bd9Sstevel@tonic-gate (void) printf("%%ipkts %%opkts\n"); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate static void 8767c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 8797c478bd9Sstevel@tonic-gate gettext("timeout"), gettext("aggregatable"), gettext("sync"), 8807c478bd9Sstevel@tonic-gate gettext("coll"), gettext("dist"), gettext("defaulted"), 8817c478bd9Sstevel@tonic-gate gettext("expired")); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate static void 8857c478bd9Sstevel@tonic-gate dump_ports_head(void) 8867c478bd9Sstevel@tonic-gate { 8877c478bd9Sstevel@tonic-gate (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 8887c478bd9Sstevel@tonic-gate "state\n")); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate static char * 8927c478bd9Sstevel@tonic-gate port_state_to_str(aggr_port_state_t state_num) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate int i; 8957c478bd9Sstevel@tonic-gate port_state_t *state; 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate for (i = 0; i < NPORTSTATES; i++) { 8987c478bd9Sstevel@tonic-gate state = &port_states[i]; 8997c478bd9Sstevel@tonic-gate if (state->state_num == state_num) 9007c478bd9Sstevel@tonic-gate return (state->state_name); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate return ("unknown"); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate static void 9077c478bd9Sstevel@tonic-gate dump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 9087c478bd9Sstevel@tonic-gate { 9097c478bd9Sstevel@tonic-gate char *dev = port->lp_devname; 9107c478bd9Sstevel@tonic-gate char buf[ETHERADDRL * 3]; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (!parseable) { 9137c478bd9Sstevel@tonic-gate (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 9147c478bd9Sstevel@tonic-gate port->lp_mac, buf)); 91533343a97Smeem (void) printf("\t %5uMb", (int)(mac_ifspeed(dev) / 9167c478bd9Sstevel@tonic-gate 1000000ull)); 917ba2e4443Sseb (void) printf("\t%s", mac_link_duplex(dev)); 918ba2e4443Sseb (void) printf("\t%s", mac_link_state(dev)); 9197c478bd9Sstevel@tonic-gate (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate } else { 9227c478bd9Sstevel@tonic-gate (void) printf(" device=%s address=%s", dev, 9237c478bd9Sstevel@tonic-gate laadm_mac_addr_to_str(port->lp_mac, buf)); 924ba2e4443Sseb (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 9257c478bd9Sstevel@tonic-gate 1000000ull)); 926ba2e4443Sseb (void) printf(" duplex=%s", mac_link_duplex(dev)); 927ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 9287c478bd9Sstevel@tonic-gate (void) printf(" port=%s", port_state_to_str(port->lp_state)); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate static void 9337c478bd9Sstevel@tonic-gate dump_port_lacp(laadm_port_attr_sys_t *port) 9347c478bd9Sstevel@tonic-gate { 9357c478bd9Sstevel@tonic-gate aggr_lacp_state_t *state = &port->lp_lacp_state; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate (void) printf(DUMP_LACP_FORMAT, 9387c478bd9Sstevel@tonic-gate port->lp_devname, state->bit.activity ? "active" : "passive", 9397c478bd9Sstevel@tonic-gate state->bit.timeout ? "short" : "long", 9407c478bd9Sstevel@tonic-gate state->bit.aggregation ? "yes" : "no", 9417c478bd9Sstevel@tonic-gate state->bit.sync ? "yes" : "no", 9427c478bd9Sstevel@tonic-gate state->bit.collecting ? "yes" : "no", 9437c478bd9Sstevel@tonic-gate state->bit.distributing ? "yes" : "no", 9447c478bd9Sstevel@tonic-gate state->bit.defaulted ? "yes" : "no", 9457c478bd9Sstevel@tonic-gate state->bit.expired ? "yes" : "no"); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate static void 9497c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 9507c478bd9Sstevel@tonic-gate pktsum_t *tot_stats) 9517c478bd9Sstevel@tonic-gate { 9527c478bd9Sstevel@tonic-gate pktsum_t diff_stats; 9537c478bd9Sstevel@tonic-gate pktsum_t *old_stats = &state->gs_prevstats[index]; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, port_stats, old_stats); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", diff_stats.ipackets); 9587c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 9597c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 9607c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate if (tot_stats->ipackets == 0) 9637c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9647c478bd9Sstevel@tonic-gate else 9657c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 9667c478bd9Sstevel@tonic-gate (double)tot_stats->ipackets * 100); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate if (tot_stats->opackets == 0) 9697c478bd9Sstevel@tonic-gate (void) printf("\t-"); 9707c478bd9Sstevel@tonic-gate else 9717c478bd9Sstevel@tonic-gate (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 9727c478bd9Sstevel@tonic-gate (double)tot_stats->opackets * 100); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate (void) printf("\n"); 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate *old_stats = *port_stats; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate static int 9807c478bd9Sstevel@tonic-gate show_key(void *arg, laadm_grp_attr_sys_t *grp) 9817c478bd9Sstevel@tonic-gate { 9827c478bd9Sstevel@tonic-gate show_grp_state_t *state = (show_grp_state_t *)arg; 9837c478bd9Sstevel@tonic-gate int i; 9847c478bd9Sstevel@tonic-gate pktsum_t pktsumtot, port_stat; 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (state->gs_key != 0 && state->gs_key != grp->lg_key) 9877c478bd9Sstevel@tonic-gate return (0); 9887c478bd9Sstevel@tonic-gate if (state->gs_firstonly) { 9897c478bd9Sstevel@tonic-gate if (state->gs_found) 9907c478bd9Sstevel@tonic-gate return (0); 9917c478bd9Sstevel@tonic-gate } else { 9927c478bd9Sstevel@tonic-gate bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate state->gs_found = B_TRUE; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if (state->gs_stats) { 9987c478bd9Sstevel@tonic-gate /* show statistics */ 9997c478bd9Sstevel@tonic-gate dump_grp_stats(grp); 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 10027c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 10037c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 1004ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10057c478bd9Sstevel@tonic-gate stats_total(&pktsumtot, &port_stat, 10067c478bd9Sstevel@tonic-gate &state->gs_prevstats[i]); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate (void) printf(" Total"); 10107c478bd9Sstevel@tonic-gate (void) printf("\t%-10llu", pktsumtot.ipackets); 10117c478bd9Sstevel@tonic-gate (void) printf("%-12llu", pktsumtot.rbytes); 10127c478bd9Sstevel@tonic-gate (void) printf("%-10llu", pktsumtot.opackets); 10137c478bd9Sstevel@tonic-gate (void) printf("%-12llu\n", pktsumtot.obytes); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 1016ba2e4443Sseb get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 10177c478bd9Sstevel@tonic-gate (void) printf(" %s", grp->lg_ports[i].lp_devname); 10187c478bd9Sstevel@tonic-gate dump_port_stat(i, state, &port_stat, &pktsumtot); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate } else if (state->gs_lacp) { 10217c478bd9Sstevel@tonic-gate /* show LACP info */ 10227c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10237c478bd9Sstevel@tonic-gate dump_grp_lacp(grp, state->gs_parseable); 10247c478bd9Sstevel@tonic-gate dump_ports_lacp_head(); 10257c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) 10267c478bd9Sstevel@tonic-gate dump_port_lacp(&grp->lg_ports[i]); 10277c478bd9Sstevel@tonic-gate } else { 10287c478bd9Sstevel@tonic-gate dump_grp(grp, state->gs_parseable); 10297c478bd9Sstevel@tonic-gate if (!state->gs_parseable) 10307c478bd9Sstevel@tonic-gate dump_ports_head(); 10317c478bd9Sstevel@tonic-gate for (i = 0; i < grp->lg_nports; i++) { 10327c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10337c478bd9Sstevel@tonic-gate (void) printf("dev key=%d", grp->lg_key); 10347c478bd9Sstevel@tonic-gate dump_port(&grp->lg_ports[i], state->gs_parseable); 10357c478bd9Sstevel@tonic-gate if (state->gs_parseable) 10367c478bd9Sstevel@tonic-gate (void) printf("\n"); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate return (0); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate static int 10447c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 10457c478bd9Sstevel@tonic-gate { 10467c478bd9Sstevel@tonic-gate kstat_named_t *knp; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 10497c478bd9Sstevel@tonic-gate return (-1); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate if (knp->data_type != type) 10527c478bd9Sstevel@tonic-gate return (-1); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate switch (type) { 10557c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT64: 10567c478bd9Sstevel@tonic-gate *(uint64_t *)buf = knp->value.ui64; 10577c478bd9Sstevel@tonic-gate break; 10587c478bd9Sstevel@tonic-gate case KSTAT_DATA_UINT32: 10597c478bd9Sstevel@tonic-gate *(uint32_t *)buf = knp->value.ui32; 10607c478bd9Sstevel@tonic-gate break; 10617c478bd9Sstevel@tonic-gate default: 10627c478bd9Sstevel@tonic-gate return (-1); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate return (0); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate static void 1069210db224Sericheng show_dev(void *arg, const char *dev) 10707c478bd9Sstevel@tonic-gate { 10717c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if (!state->ms_parseable) { 10767c478bd9Sstevel@tonic-gate (void) printf(gettext("\t\tlink: %s"), 1077ba2e4443Sseb mac_link_state(dev)); 107833343a97Smeem (void) printf(gettext("\tspeed: %5uMb"), 1079ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 10807c478bd9Sstevel@tonic-gate (void) printf(gettext("\tduplex: %s\n"), 1081ba2e4443Sseb mac_link_duplex(dev)); 10827c478bd9Sstevel@tonic-gate } else { 1083ba2e4443Sseb (void) printf(" link=%s", mac_link_state(dev)); 10847c478bd9Sstevel@tonic-gate (void) printf(" speed=%u", 1085ba2e4443Sseb (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1086ba2e4443Sseb (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10917c478bd9Sstevel@tonic-gate static void 1092210db224Sericheng show_dev_stats(void *arg, const char *dev) 10937c478bd9Sstevel@tonic-gate { 10947c478bd9Sstevel@tonic-gate show_mac_state_t *state = (show_mac_state_t *)arg; 10957c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate if (state->ms_firstonly) { 10987c478bd9Sstevel@tonic-gate if (state->ms_donefirst) 10997c478bd9Sstevel@tonic-gate return; 11007c478bd9Sstevel@tonic-gate state->ms_donefirst = B_TRUE; 11017c478bd9Sstevel@tonic-gate } else { 11027c478bd9Sstevel@tonic-gate bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 1105ba2e4443Sseb get_mac_stats(dev, &stats); 11067c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ms_prevstats); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate (void) printf("%s", dev); 11097c478bd9Sstevel@tonic-gate (void) printf("\t\t%-10llu", diff_stats.ipackets); 11107c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 11117c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 11127c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 11137c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 11147c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate state->ms_prevstats = stats; 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate static void 11207c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[]) 11217c478bd9Sstevel@tonic-gate { 11227c478bd9Sstevel@tonic-gate char *name = NULL; 11237c478bd9Sstevel@tonic-gate int option; 11247c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11257c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 112633343a97Smeem int interval = 0; 11277c478bd9Sstevel@tonic-gate show_link_state_t state; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate state.ls_stats = B_FALSE; 11307c478bd9Sstevel@tonic-gate state.ls_parseable = B_FALSE; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate opterr = 0; 11337c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 11347c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11357c478bd9Sstevel@tonic-gate switch (option) { 11367c478bd9Sstevel@tonic-gate case 'p': 11377c478bd9Sstevel@tonic-gate state.ls_parseable = B_TRUE; 11387c478bd9Sstevel@tonic-gate break; 11397c478bd9Sstevel@tonic-gate case 's': 114033343a97Smeem if (s_arg) 114133343a97Smeem die_optdup(option); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 11447c478bd9Sstevel@tonic-gate break; 11457c478bd9Sstevel@tonic-gate case 'i': 114633343a97Smeem if (i_arg) 114733343a97Smeem die_optdup(option); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 115033343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 115133343a97Smeem die("invalid interval value '%s'", optarg); 11527c478bd9Sstevel@tonic-gate break; 11537c478bd9Sstevel@tonic-gate default: 115433343a97Smeem die_opterr(optopt, option); 115533343a97Smeem break; 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate 115933343a97Smeem if (i_arg && !s_arg) 116033343a97Smeem die("the option -i can be used only with -s"); 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 11637c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 11647c478bd9Sstevel@tonic-gate name = argv[optind]; 11657c478bd9Sstevel@tonic-gate else if (optind != argc) 11667c478bd9Sstevel@tonic-gate usage(); 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate if (s_arg) { 11697c478bd9Sstevel@tonic-gate link_stats(name, interval); 11707c478bd9Sstevel@tonic-gate return; 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 1173210db224Sericheng if (name == NULL) { 11747c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link, &state); 1175210db224Sericheng } else { 11767c478bd9Sstevel@tonic-gate show_link(&state, name); 11777c478bd9Sstevel@tonic-gate } 1178210db224Sericheng } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate static void 11817c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[]) 11827c478bd9Sstevel@tonic-gate { 11837c478bd9Sstevel@tonic-gate int option; 118433343a97Smeem int key = 0; 11857c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 11867c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 11877c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 11887c478bd9Sstevel@tonic-gate show_grp_state_t state; 118933343a97Smeem int interval = 0; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate state.gs_stats = B_FALSE; 11927c478bd9Sstevel@tonic-gate state.gs_lacp = B_FALSE; 11937c478bd9Sstevel@tonic-gate state.gs_parseable = B_FALSE; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate opterr = 0; 11967c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":Lpsi:", 11977c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 11987c478bd9Sstevel@tonic-gate switch (option) { 11997c478bd9Sstevel@tonic-gate case 'L': 120033343a97Smeem if (L_arg) 120133343a97Smeem die_optdup(option); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate if (s_arg || i_arg) { 120433343a97Smeem die("the option -L cannot be used with -i " 120533343a97Smeem "or -s"); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 12097c478bd9Sstevel@tonic-gate state.gs_lacp = B_TRUE; 12107c478bd9Sstevel@tonic-gate break; 12117c478bd9Sstevel@tonic-gate case 'p': 12127c478bd9Sstevel@tonic-gate state.gs_parseable = B_TRUE; 12137c478bd9Sstevel@tonic-gate break; 12147c478bd9Sstevel@tonic-gate case 's': 121533343a97Smeem if (s_arg) 121633343a97Smeem die_optdup(option); 12177c478bd9Sstevel@tonic-gate 121833343a97Smeem if (L_arg) 121913994ee8Sxz162242 die("the option -s cannot be used with -L"); 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12227c478bd9Sstevel@tonic-gate break; 12237c478bd9Sstevel@tonic-gate case 'i': 122433343a97Smeem if (i_arg) 122533343a97Smeem die_optdup(option); 12267c478bd9Sstevel@tonic-gate 122733343a97Smeem if (L_arg) 122833343a97Smeem die("the option -i cannot be used with -L"); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 123133343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 123233343a97Smeem die("invalid interval value '%s'", optarg); 12337c478bd9Sstevel@tonic-gate break; 12347c478bd9Sstevel@tonic-gate default: 123533343a97Smeem die_opterr(optopt, option); 123633343a97Smeem break; 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 124033343a97Smeem if (i_arg && !s_arg) 124133343a97Smeem die("the option -i can be used only with -s"); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* get aggregation key (optional last argument) */ 12447c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 124533343a97Smeem if (!str2int(argv[optind], &key) || key < 1) 124633343a97Smeem die("invalid key value '%s'", argv[optind]); 12477c478bd9Sstevel@tonic-gate } else if (optind != argc) { 12487c478bd9Sstevel@tonic-gate usage(); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate if (s_arg) { 12527c478bd9Sstevel@tonic-gate aggr_stats(key, interval); 12537c478bd9Sstevel@tonic-gate return; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate state.gs_key = key; 12577c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 12607c478bd9Sstevel@tonic-gate 126133343a97Smeem if (key != 0 && !state.gs_found) 126233343a97Smeem die("non-existent aggregation key '%u'", key); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate static void 12667c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[]) 12677c478bd9Sstevel@tonic-gate { 12687c478bd9Sstevel@tonic-gate int option; 12697c478bd9Sstevel@tonic-gate char *dev = NULL; 12707c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 12717c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 127233343a97Smeem int interval = 0; 12737c478bd9Sstevel@tonic-gate show_mac_state_t state; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate state.ms_parseable = B_FALSE; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate opterr = 0; 12787c478bd9Sstevel@tonic-gate while ((option = getopt_long(argc, argv, ":psi:", 12797c478bd9Sstevel@tonic-gate longopts, NULL)) != -1) { 12807c478bd9Sstevel@tonic-gate switch (option) { 12817c478bd9Sstevel@tonic-gate case 'p': 12827c478bd9Sstevel@tonic-gate state.ms_parseable = B_TRUE; 12837c478bd9Sstevel@tonic-gate break; 12847c478bd9Sstevel@tonic-gate case 's': 128533343a97Smeem if (s_arg) 128633343a97Smeem die_optdup(option); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 12897c478bd9Sstevel@tonic-gate break; 12907c478bd9Sstevel@tonic-gate case 'i': 129133343a97Smeem if (i_arg) 129233343a97Smeem die_optdup(option); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 129533343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 129633343a97Smeem die("invalid interval value '%s'", optarg); 12977c478bd9Sstevel@tonic-gate break; 12987c478bd9Sstevel@tonic-gate default: 129933343a97Smeem die_opterr(optopt, option); 130033343a97Smeem break; 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 130433343a97Smeem if (i_arg && !s_arg) 130533343a97Smeem die("the option -i can be used only with -s"); 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* get dev name (optional last argument) */ 13087c478bd9Sstevel@tonic-gate if (optind == (argc-1)) 13097c478bd9Sstevel@tonic-gate dev = argv[optind]; 13107c478bd9Sstevel@tonic-gate else if (optind != argc) 13117c478bd9Sstevel@tonic-gate usage(); 13127c478bd9Sstevel@tonic-gate 1313cd93090eSericheng if (dev != NULL) { 1314*c7e4935fSss150715 uint_t ppa; 1315*c7e4935fSss150715 char drv[DLPI_LINKNAME_MAX]; 1316cd93090eSericheng dladm_attr_t dlattr; 1317cd93090eSericheng boolean_t legacy; 1318cd93090eSericheng 1319cd93090eSericheng /* 1320cd93090eSericheng * Check for invalid devices. 1321cd93090eSericheng * aggregations and vlans are not considered devices. 1322cd93090eSericheng */ 1323*c7e4935fSss150715 if (dlpi_parselink(dev, drv, &ppa) != DLPI_SUCCESS || 1324*c7e4935fSss150715 strcmp(drv, "aggr") == 0 || ppa >= 1000 || 1325*c7e4935fSss150715 get_if_info(dev, &dlattr, &legacy) < 0) 132633343a97Smeem die("invalid device '%s'", dev); 1327cd93090eSericheng } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate if (s_arg) { 13307c478bd9Sstevel@tonic-gate dev_stats(dev, interval); 13317c478bd9Sstevel@tonic-gate return; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate if (dev == NULL) 13357c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev, &state, B_TRUE); 13367c478bd9Sstevel@tonic-gate else 1337210db224Sericheng show_dev(&state, dev); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13417c478bd9Sstevel@tonic-gate static void 134233343a97Smeem link_stats(const char *link, uint_t interval) 13437c478bd9Sstevel@tonic-gate { 1344210db224Sericheng dladm_attr_t dlattr; 1345210db224Sericheng boolean_t legacy; 13467c478bd9Sstevel@tonic-gate show_link_state_t state; 13477c478bd9Sstevel@tonic-gate 134833343a97Smeem if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) 134933343a97Smeem die("invalid link '%s'", link); 135033343a97Smeem 13517c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13557c478bd9Sstevel@tonic-gate * only for the first MAC port. 13567c478bd9Sstevel@tonic-gate */ 13577c478bd9Sstevel@tonic-gate state.ls_firstonly = (interval != 0); 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate for (;;) { 13607c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 13617c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate state.ls_donefirst = B_FALSE; 13647c478bd9Sstevel@tonic-gate if (link == NULL) 13657c478bd9Sstevel@tonic-gate (void) dladm_walk(show_link_stats, &state); 13667c478bd9Sstevel@tonic-gate else 13677c478bd9Sstevel@tonic-gate show_link_stats(&state, link); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if (interval == 0) 13707c478bd9Sstevel@tonic-gate break; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate (void) sleep(interval); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13777c478bd9Sstevel@tonic-gate static void 137833343a97Smeem aggr_stats(uint32_t key, uint_t interval) 13797c478bd9Sstevel@tonic-gate { 13807c478bd9Sstevel@tonic-gate show_grp_state_t state; 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 13837c478bd9Sstevel@tonic-gate state.gs_stats = B_TRUE; 13847c478bd9Sstevel@tonic-gate state.gs_key = key; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 13887c478bd9Sstevel@tonic-gate * only for the first group. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate state.gs_firstonly = (interval != 0); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate for (;;) { 13937c478bd9Sstevel@tonic-gate state.gs_found = B_FALSE; 13947c478bd9Sstevel@tonic-gate (void) laadm_walk_sys(show_key, &state); 139533343a97Smeem if (state.gs_key != 0 && !state.gs_found) 139633343a97Smeem die("non-existent aggregation key '%u'", key); 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate if (interval == 0) 13997c478bd9Sstevel@tonic-gate break; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate (void) sleep(interval); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14067c478bd9Sstevel@tonic-gate static void 14077c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval) 14087c478bd9Sstevel@tonic-gate { 14097c478bd9Sstevel@tonic-gate show_mac_state_t state; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 14157c478bd9Sstevel@tonic-gate * only for the first MAC port. 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate state.ms_firstonly = (interval != 0); 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate for (;;) { 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate (void) printf("\t\tipackets rbytes ierrors "); 14227c478bd9Sstevel@tonic-gate (void) printf("opackets obytes oerrors\n"); 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate state.ms_donefirst = B_FALSE; 1425210db224Sericheng if (dev == NULL) 14267c478bd9Sstevel@tonic-gate (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1427210db224Sericheng else 1428210db224Sericheng show_dev_stats(&state, dev); 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (interval == 0) 14317c478bd9Sstevel@tonic-gate break; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate (void) sleep(interval); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */ 14387c478bd9Sstevel@tonic-gate static void 14397c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14407c478bd9Sstevel@tonic-gate { 14417c478bd9Sstevel@tonic-gate s1->ipackets += (s2->ipackets - s3->ipackets); 14427c478bd9Sstevel@tonic-gate s1->opackets += (s2->opackets - s3->opackets); 14437c478bd9Sstevel@tonic-gate s1->rbytes += (s2->rbytes - s3->rbytes); 14447c478bd9Sstevel@tonic-gate s1->obytes += (s2->obytes - s3->obytes); 14457c478bd9Sstevel@tonic-gate s1->ierrors += (s2->ierrors - s3->ierrors); 14467c478bd9Sstevel@tonic-gate s1->oerrors += (s2->oerrors - s3->oerrors); 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */ 14507c478bd9Sstevel@tonic-gate static void 14517c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 14527c478bd9Sstevel@tonic-gate { 14537c478bd9Sstevel@tonic-gate s1->ipackets = s2->ipackets - s3->ipackets; 14547c478bd9Sstevel@tonic-gate s1->opackets = s2->opackets - s3->opackets; 14557c478bd9Sstevel@tonic-gate s1->rbytes = s2->rbytes - s3->rbytes; 14567c478bd9Sstevel@tonic-gate s1->obytes = s2->obytes - s3->obytes; 14577c478bd9Sstevel@tonic-gate s1->ierrors = s2->ierrors - s3->ierrors; 14587c478bd9Sstevel@tonic-gate s1->oerrors = s2->oerrors - s3->oerrors; 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 1461cd93090eSericheng /* 1462ba2e4443Sseb * In the following routines, we do the first kstat_lookup() assuming that 1463ba2e4443Sseb * the device is gldv3-based and that the kstat name is the one passed in 1464ba2e4443Sseb * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1465ba2e4443Sseb * omitting the kstat name. This second lookup is needed for getting kstats 1466ba2e4443Sseb * from legacy devices. This can fail too if the device is not attached or 1467ba2e4443Sseb * the device is legacy and doesn't export the kstats we need. 1468cd93090eSericheng */ 14697c478bd9Sstevel@tonic-gate static void 14707c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats) 14717c478bd9Sstevel@tonic-gate { 14727c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 14737c478bd9Sstevel@tonic-gate kstat_t *ksp; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 147633343a97Smeem warn("kstat open operation failed"); 14777c478bd9Sstevel@tonic-gate return; 14787c478bd9Sstevel@tonic-gate } 14797c478bd9Sstevel@tonic-gate 1480cd93090eSericheng if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1481ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 14847c478bd9Sstevel@tonic-gate * driver was already detached. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 14877c478bd9Sstevel@tonic-gate return; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) 14917c478bd9Sstevel@tonic-gate goto bail; 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 14947c478bd9Sstevel@tonic-gate &stats->ipackets) < 0) 14957c478bd9Sstevel@tonic-gate goto bail; 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 14987c478bd9Sstevel@tonic-gate &stats->opackets) < 0) 14997c478bd9Sstevel@tonic-gate goto bail; 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 15027c478bd9Sstevel@tonic-gate &stats->rbytes) < 0) 15037c478bd9Sstevel@tonic-gate goto bail; 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 15067c478bd9Sstevel@tonic-gate &stats->obytes) < 0) 15077c478bd9Sstevel@tonic-gate goto bail; 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 15107c478bd9Sstevel@tonic-gate &stats->ierrors) < 0) 15117c478bd9Sstevel@tonic-gate goto bail; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 15147c478bd9Sstevel@tonic-gate &stats->oerrors) < 0) 15157c478bd9Sstevel@tonic-gate goto bail; 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15187c478bd9Sstevel@tonic-gate return; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate bail: 15217c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate static void 1525ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats) 15267c478bd9Sstevel@tonic-gate { 1527*c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1528*c7e4935fSss150715 uint_t instance; 15297c478bd9Sstevel@tonic-gate 1530*c7e4935fSss150715 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 1531ba2e4443Sseb return; 15327c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1533ba2e4443Sseb get_stats(module, instance, "mac", stats); 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate static void 15377c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 15387c478bd9Sstevel@tonic-gate { 1539*c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1540*c7e4935fSss150715 uint_t instance; 1541ba2e4443Sseb 1542*c7e4935fSss150715 if (dlpi_parselink(link, module, &instance) != DLPI_SUCCESS) 1543ba2e4443Sseb return; 15447c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 1545ba2e4443Sseb get_stats(module, instance, (char *)link, stats); 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 1548ba2e4443Sseb static int 1549ba2e4443Sseb get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1550ba2e4443Sseb void *val) 15517c478bd9Sstevel@tonic-gate { 1552*c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 1553*c7e4935fSss150715 uint_t instance; 15547c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 15557c478bd9Sstevel@tonic-gate kstat_t *ksp; 15567c478bd9Sstevel@tonic-gate 1557*c7e4935fSss150715 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 1558*c7e4935fSss150715 return (-1); 1559*c7e4935fSss150715 15607c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 156133343a97Smeem warn("kstat open operation failed"); 1562ba2e4443Sseb return (-1); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate 1565ba2e4443Sseb if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1566ba2e4443Sseb (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 15677c478bd9Sstevel@tonic-gate /* 15687c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 15697c478bd9Sstevel@tonic-gate * driver was already detached. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate goto bail; 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 157533343a97Smeem warn("kstat read failed"); 15767c478bd9Sstevel@tonic-gate goto bail; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 1579ba2e4443Sseb if (kstat_value(ksp, name, type, val) < 0) 15807c478bd9Sstevel@tonic-gate goto bail; 1581ba2e4443Sseb 1582ba2e4443Sseb (void) kstat_close(kcp); 1583ba2e4443Sseb return (0); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate bail: 15867c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 1587ba2e4443Sseb return (-1); 1588ba2e4443Sseb } 1589ba2e4443Sseb 1590ba2e4443Sseb static uint64_t 1591ba2e4443Sseb mac_ifspeed(const char *dev) 1592ba2e4443Sseb { 1593ba2e4443Sseb uint64_t ifspeed = 0; 1594ba2e4443Sseb 1595ba2e4443Sseb (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 15967c478bd9Sstevel@tonic-gate return (ifspeed); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate static char * 1600ba2e4443Sseb mac_link_state(const char *dev) 16017c478bd9Sstevel@tonic-gate { 16027c478bd9Sstevel@tonic-gate link_state_t link_state; 16037c478bd9Sstevel@tonic-gate char *state_str = "unknown"; 16047c478bd9Sstevel@tonic-gate 1605ba2e4443Sseb if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1606ba2e4443Sseb &link_state) != 0) { 16077c478bd9Sstevel@tonic-gate return (state_str); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate switch (link_state) { 16117c478bd9Sstevel@tonic-gate case LINK_STATE_UP: 16127c478bd9Sstevel@tonic-gate state_str = "up"; 16137c478bd9Sstevel@tonic-gate break; 16147c478bd9Sstevel@tonic-gate case LINK_STATE_DOWN: 16157c478bd9Sstevel@tonic-gate state_str = "down"; 16167c478bd9Sstevel@tonic-gate break; 16177c478bd9Sstevel@tonic-gate default: 16187c478bd9Sstevel@tonic-gate break; 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate return (state_str); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate static char * 1626ba2e4443Sseb mac_link_duplex(const char *dev) 16277c478bd9Sstevel@tonic-gate { 16287c478bd9Sstevel@tonic-gate link_duplex_t link_duplex; 16297c478bd9Sstevel@tonic-gate char *duplex_str = "unknown"; 16307c478bd9Sstevel@tonic-gate 1631ba2e4443Sseb if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1632ba2e4443Sseb &link_duplex) != 0) { 16337c478bd9Sstevel@tonic-gate return (duplex_str); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate switch (link_duplex) { 16377c478bd9Sstevel@tonic-gate case LINK_DUPLEX_FULL: 16387c478bd9Sstevel@tonic-gate duplex_str = "full"; 16397c478bd9Sstevel@tonic-gate break; 16407c478bd9Sstevel@tonic-gate case LINK_DUPLEX_HALF: 16417c478bd9Sstevel@tonic-gate duplex_str = "half"; 16427c478bd9Sstevel@tonic-gate break; 16437c478bd9Sstevel@tonic-gate default: 16447c478bd9Sstevel@tonic-gate break; 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate return (duplex_str); 16487c478bd9Sstevel@tonic-gate } 16490ba2cbe9Sxc151355 16500ba2cbe9Sxc151355 #define WIFI_CMD_SCAN 0x00000001 16510ba2cbe9Sxc151355 #define WIFI_CMD_SHOW 0x00000002 16520ba2cbe9Sxc151355 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 16530ba2cbe9Sxc151355 typedef struct wifi_field { 16540ba2cbe9Sxc151355 const char *wf_name; 16550ba2cbe9Sxc151355 const char *wf_header; 16560ba2cbe9Sxc151355 uint_t wf_width; 16570ba2cbe9Sxc151355 uint_t wf_mask; 16580ba2cbe9Sxc151355 uint_t wf_cmdtype; 16590ba2cbe9Sxc151355 } wifi_field_t; 16600ba2cbe9Sxc151355 16610ba2cbe9Sxc151355 static wifi_field_t wifi_fields[] = { 16620ba2cbe9Sxc151355 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 16630ba2cbe9Sxc151355 { "essid", "ESSID", 19, WLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 16640ba2cbe9Sxc151355 { "bssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16650ba2cbe9Sxc151355 { "ibssid", "BSSID/IBSSID", 17, WLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 16660ba2cbe9Sxc151355 { "mode", "MODE", 6, WLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 16670ba2cbe9Sxc151355 { "speed", "SPEED", 6, WLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 166813994ee8Sxz162242 { "auth", "AUTH", 8, WLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 16690ba2cbe9Sxc151355 { "bsstype", "BSSTYPE", 8, WLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 16700ba2cbe9Sxc151355 { "sec", "SEC", 6, WLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 16710ba2cbe9Sxc151355 { "status", "STATUS", 17, WLADM_LINK_ATTR_STATUS, WIFI_CMD_SHOW}, 16720ba2cbe9Sxc151355 { "strength", "STRENGTH", 10, WLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 16730ba2cbe9Sxc151355 ; 16740ba2cbe9Sxc151355 16750ba2cbe9Sxc151355 static char *all_scan_wifi_fields = 167613994ee8Sxz162242 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 16770ba2cbe9Sxc151355 static char *all_show_wifi_fields = 16780ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 16790ba2cbe9Sxc151355 static char *def_scan_wifi_fields = 16800ba2cbe9Sxc151355 "link,essid,bssid,sec,strength,mode,speed"; 16810ba2cbe9Sxc151355 static char *def_show_wifi_fields = 16820ba2cbe9Sxc151355 "link,status,essid,sec,strength,mode,speed"; 16830ba2cbe9Sxc151355 16840ba2cbe9Sxc151355 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) 16850ba2cbe9Sxc151355 #define WIFI_MAX_FIELD_LEN 32 16860ba2cbe9Sxc151355 16870ba2cbe9Sxc151355 typedef struct { 16880ba2cbe9Sxc151355 char *s_buf; 16890ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 16900ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 16910ba2cbe9Sxc151355 } split_t; 16920ba2cbe9Sxc151355 16930ba2cbe9Sxc151355 /* 16940ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 16950ba2cbe9Sxc151355 */ 16960ba2cbe9Sxc151355 static void 16970ba2cbe9Sxc151355 splitfree(split_t *sp) 16980ba2cbe9Sxc151355 { 16990ba2cbe9Sxc151355 free(sp->s_buf); 17000ba2cbe9Sxc151355 free(sp->s_fields); 17010ba2cbe9Sxc151355 free(sp); 17020ba2cbe9Sxc151355 } 17030ba2cbe9Sxc151355 17040ba2cbe9Sxc151355 /* 17050ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 17060ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 17070ba2cbe9Sxc151355 * on failure. 17080ba2cbe9Sxc151355 */ 17090ba2cbe9Sxc151355 static split_t * 17100ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 17110ba2cbe9Sxc151355 { 17120ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 17130ba2cbe9Sxc151355 split_t *sp; 17140ba2cbe9Sxc151355 17150ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 17160ba2cbe9Sxc151355 return (NULL); 17170ba2cbe9Sxc151355 17180ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 17190ba2cbe9Sxc151355 if (sp == NULL) 17200ba2cbe9Sxc151355 return (NULL); 17210ba2cbe9Sxc151355 17220ba2cbe9Sxc151355 sp->s_buf = strdup(str); 17230ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 17240ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 17250ba2cbe9Sxc151355 goto fail; 17260ba2cbe9Sxc151355 17270ba2cbe9Sxc151355 token = sp->s_buf; 17280ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 17290ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 17300ba2cbe9Sxc151355 goto fail; 17310ba2cbe9Sxc151355 token = NULL; 17320ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 17330ba2cbe9Sxc151355 } 17340ba2cbe9Sxc151355 return (sp); 17350ba2cbe9Sxc151355 fail: 17360ba2cbe9Sxc151355 splitfree(sp); 17370ba2cbe9Sxc151355 return (NULL); 17380ba2cbe9Sxc151355 } 17390ba2cbe9Sxc151355 17400ba2cbe9Sxc151355 static int 17410ba2cbe9Sxc151355 parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, 17420ba2cbe9Sxc151355 uint_t cmdtype) 17430ba2cbe9Sxc151355 { 17440ba2cbe9Sxc151355 uint_t i, j; 17450ba2cbe9Sxc151355 wifi_field_t **wf = NULL; 17460ba2cbe9Sxc151355 split_t *sp; 17470ba2cbe9Sxc151355 boolean_t good_match = B_FALSE; 17480ba2cbe9Sxc151355 17490ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 17500ba2cbe9Sxc151355 if (str == NULL) 17510ba2cbe9Sxc151355 str = def_scan_wifi_fields; 17520ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17530ba2cbe9Sxc151355 str = all_scan_wifi_fields; 17540ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 17550ba2cbe9Sxc151355 if (str == NULL) 17560ba2cbe9Sxc151355 str = def_show_wifi_fields; 17570ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 17580ba2cbe9Sxc151355 str = all_show_wifi_fields; 17590ba2cbe9Sxc151355 } else { 17600ba2cbe9Sxc151355 return (-1); 17610ba2cbe9Sxc151355 } 17620ba2cbe9Sxc151355 17630ba2cbe9Sxc151355 sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); 17640ba2cbe9Sxc151355 if (sp == NULL) 17650ba2cbe9Sxc151355 return (-1); 17660ba2cbe9Sxc151355 17670ba2cbe9Sxc151355 wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); 17680ba2cbe9Sxc151355 if (wf == NULL) 17690ba2cbe9Sxc151355 goto fail; 17700ba2cbe9Sxc151355 17710ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 17720ba2cbe9Sxc151355 for (j = 0; j < WIFI_MAX_FIELDS; j++) { 17730ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 17740ba2cbe9Sxc151355 wifi_fields[j].wf_name) == 0) { 177513994ee8Sxz162242 good_match = wifi_fields[j]. 17760ba2cbe9Sxc151355 wf_cmdtype & cmdtype; 17770ba2cbe9Sxc151355 break; 17780ba2cbe9Sxc151355 } 17790ba2cbe9Sxc151355 } 17800ba2cbe9Sxc151355 if (!good_match) 17810ba2cbe9Sxc151355 goto fail; 17820ba2cbe9Sxc151355 17830ba2cbe9Sxc151355 good_match = B_FALSE; 17840ba2cbe9Sxc151355 wf[i] = &wifi_fields[j]; 17850ba2cbe9Sxc151355 } 17860ba2cbe9Sxc151355 *countp = i; 17870ba2cbe9Sxc151355 *fields = wf; 17880ba2cbe9Sxc151355 splitfree(sp); 17890ba2cbe9Sxc151355 return (0); 17900ba2cbe9Sxc151355 fail: 17910ba2cbe9Sxc151355 free(wf); 17920ba2cbe9Sxc151355 splitfree(sp); 17930ba2cbe9Sxc151355 return (-1); 17940ba2cbe9Sxc151355 } 17950ba2cbe9Sxc151355 17960ba2cbe9Sxc151355 typedef struct print_wifi_state { 17970ba2cbe9Sxc151355 const char *ws_link; 17980ba2cbe9Sxc151355 boolean_t ws_parseable; 17990ba2cbe9Sxc151355 boolean_t ws_header; 18000ba2cbe9Sxc151355 wifi_field_t **ws_fields; 18010ba2cbe9Sxc151355 uint_t ws_nfields; 18020ba2cbe9Sxc151355 boolean_t ws_lastfield; 18030ba2cbe9Sxc151355 uint_t ws_overflow; 18040ba2cbe9Sxc151355 } print_wifi_state_t; 18050ba2cbe9Sxc151355 18060ba2cbe9Sxc151355 static void 18070ba2cbe9Sxc151355 print_wifi_head(print_wifi_state_t *statep) 18080ba2cbe9Sxc151355 { 18090ba2cbe9Sxc151355 int i; 18100ba2cbe9Sxc151355 wifi_field_t *wfp; 18110ba2cbe9Sxc151355 18120ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 18130ba2cbe9Sxc151355 wfp = statep->ws_fields[i]; 18140ba2cbe9Sxc151355 if (i + 1 < statep->ws_nfields) 18150ba2cbe9Sxc151355 (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); 18160ba2cbe9Sxc151355 else 18170ba2cbe9Sxc151355 (void) printf("%s", wfp->wf_header); 18180ba2cbe9Sxc151355 } 18190ba2cbe9Sxc151355 (void) printf("\n"); 18200ba2cbe9Sxc151355 } 18210ba2cbe9Sxc151355 18220ba2cbe9Sxc151355 static void 18230ba2cbe9Sxc151355 print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, 18240ba2cbe9Sxc151355 const char *value) 18250ba2cbe9Sxc151355 { 18260ba2cbe9Sxc151355 uint_t width = wfp->wf_width; 18270ba2cbe9Sxc151355 uint_t valwidth = strlen(value); 18280ba2cbe9Sxc151355 uint_t compress; 18290ba2cbe9Sxc151355 18300ba2cbe9Sxc151355 if (statep->ws_parseable) { 18310ba2cbe9Sxc151355 (void) printf("%s=\"%s\"", wfp->wf_header, value); 18320ba2cbe9Sxc151355 } else { 18330ba2cbe9Sxc151355 if (value[0] == '\0') 18340ba2cbe9Sxc151355 value = "--"; 18350ba2cbe9Sxc151355 if (statep->ws_lastfield) { 18360ba2cbe9Sxc151355 (void) printf("%s", value); 18370ba2cbe9Sxc151355 return; 18380ba2cbe9Sxc151355 } 18390ba2cbe9Sxc151355 18400ba2cbe9Sxc151355 if (valwidth > width) { 18410ba2cbe9Sxc151355 statep->ws_overflow += valwidth - width; 18420ba2cbe9Sxc151355 } else if (valwidth < width && statep->ws_overflow > 0) { 18430ba2cbe9Sxc151355 compress = min(statep->ws_overflow, width - valwidth); 18440ba2cbe9Sxc151355 statep->ws_overflow -= compress; 18450ba2cbe9Sxc151355 width -= compress; 18460ba2cbe9Sxc151355 } 18470ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 18480ba2cbe9Sxc151355 } 18490ba2cbe9Sxc151355 18500ba2cbe9Sxc151355 if (!statep->ws_lastfield) 18510ba2cbe9Sxc151355 (void) putchar(' '); 18520ba2cbe9Sxc151355 } 18530ba2cbe9Sxc151355 18540ba2cbe9Sxc151355 static void 18550ba2cbe9Sxc151355 print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 18560ba2cbe9Sxc151355 wladm_wlan_attr_t *attrp) 18570ba2cbe9Sxc151355 { 18580ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 18590ba2cbe9Sxc151355 const char *str = ""; 18600ba2cbe9Sxc151355 18610ba2cbe9Sxc151355 if (wfp->wf_mask == 0) { 18620ba2cbe9Sxc151355 print_wifi_field(statep, wfp, statep->ws_link); 18630ba2cbe9Sxc151355 return; 18640ba2cbe9Sxc151355 } 18650ba2cbe9Sxc151355 18660ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->wa_valid) == 0) { 18670ba2cbe9Sxc151355 print_wifi_field(statep, wfp, ""); 18680ba2cbe9Sxc151355 return; 18690ba2cbe9Sxc151355 } 18700ba2cbe9Sxc151355 18710ba2cbe9Sxc151355 switch (wfp->wf_mask) { 18720ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_ESSID: 18730ba2cbe9Sxc151355 str = wladm_essid2str(&attrp->wa_essid, buf); 18740ba2cbe9Sxc151355 break; 18750ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSID: 18760ba2cbe9Sxc151355 str = wladm_bssid2str(&attrp->wa_bssid, buf); 18770ba2cbe9Sxc151355 break; 18780ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SECMODE: 18790ba2cbe9Sxc151355 str = wladm_secmode2str(&attrp->wa_secmode, buf); 18800ba2cbe9Sxc151355 break; 18810ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_STRENGTH: 18820ba2cbe9Sxc151355 str = wladm_strength2str(&attrp->wa_strength, buf); 18830ba2cbe9Sxc151355 break; 18840ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_MODE: 18850ba2cbe9Sxc151355 str = wladm_mode2str(&attrp->wa_mode, buf); 18860ba2cbe9Sxc151355 break; 18870ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_SPEED: 18880ba2cbe9Sxc151355 str = wladm_speed2str(&attrp->wa_speed, buf); 18890ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 18900ba2cbe9Sxc151355 break; 18910ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_AUTH: 18920ba2cbe9Sxc151355 str = wladm_auth2str(&attrp->wa_auth, buf); 18930ba2cbe9Sxc151355 break; 18940ba2cbe9Sxc151355 case WLADM_WLAN_ATTR_BSSTYPE: 18950ba2cbe9Sxc151355 str = wladm_bsstype2str(&attrp->wa_bsstype, buf); 18960ba2cbe9Sxc151355 break; 18970ba2cbe9Sxc151355 } 18980ba2cbe9Sxc151355 18990ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 19000ba2cbe9Sxc151355 } 19010ba2cbe9Sxc151355 19020ba2cbe9Sxc151355 static boolean_t 19030ba2cbe9Sxc151355 print_scan_results(void *arg, wladm_wlan_attr_t *attrp) 19040ba2cbe9Sxc151355 { 19050ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19060ba2cbe9Sxc151355 int i; 19070ba2cbe9Sxc151355 19080ba2cbe9Sxc151355 if (statep->ws_header) { 19090ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19100ba2cbe9Sxc151355 if (!statep->ws_parseable) 19110ba2cbe9Sxc151355 print_wifi_head(statep); 19120ba2cbe9Sxc151355 } 19130ba2cbe9Sxc151355 19140ba2cbe9Sxc151355 statep->ws_overflow = 0; 19150ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19160ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19170ba2cbe9Sxc151355 print_wlan_attr(statep, statep->ws_fields[i], attrp); 19180ba2cbe9Sxc151355 } 19190ba2cbe9Sxc151355 (void) putchar('\n'); 19200ba2cbe9Sxc151355 return (B_TRUE); 19210ba2cbe9Sxc151355 } 19220ba2cbe9Sxc151355 19230ba2cbe9Sxc151355 static boolean_t 19240ba2cbe9Sxc151355 scan_wifi(void *arg, const char *link) 19250ba2cbe9Sxc151355 { 19260ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19270ba2cbe9Sxc151355 wladm_status_t status; 19280ba2cbe9Sxc151355 19290ba2cbe9Sxc151355 statep->ws_link = link; 19300ba2cbe9Sxc151355 status = wladm_scan(link, statep, print_scan_results); 193133343a97Smeem if (status != WLADM_STATUS_OK) 193233343a97Smeem die_wlerr(status, "cannot scan link '%s'", link); 193333343a97Smeem 19340ba2cbe9Sxc151355 return (B_TRUE); 19350ba2cbe9Sxc151355 } 19360ba2cbe9Sxc151355 19370ba2cbe9Sxc151355 static void 19380ba2cbe9Sxc151355 print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, 19390ba2cbe9Sxc151355 wladm_link_attr_t *attrp) 19400ba2cbe9Sxc151355 { 19410ba2cbe9Sxc151355 char buf[WLADM_STRSIZE]; 19420ba2cbe9Sxc151355 const char *str = ""; 19430ba2cbe9Sxc151355 19440ba2cbe9Sxc151355 if (strcmp(wfp->wf_name, "status") == 0) { 19450ba2cbe9Sxc151355 if ((wfp->wf_mask & attrp->la_valid) != 0) 19460ba2cbe9Sxc151355 str = wladm_linkstatus2str(&attrp->la_status, buf); 19470ba2cbe9Sxc151355 print_wifi_field(statep, wfp, str); 19480ba2cbe9Sxc151355 return; 19490ba2cbe9Sxc151355 } 19500ba2cbe9Sxc151355 print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); 19510ba2cbe9Sxc151355 } 19520ba2cbe9Sxc151355 19530ba2cbe9Sxc151355 static boolean_t 19540ba2cbe9Sxc151355 show_wifi(void *arg, const char *link) 19550ba2cbe9Sxc151355 { 19560ba2cbe9Sxc151355 int i; 19570ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 19580ba2cbe9Sxc151355 wladm_link_attr_t attr; 19590ba2cbe9Sxc151355 wladm_status_t status; 19600ba2cbe9Sxc151355 19610ba2cbe9Sxc151355 status = wladm_get_link_attr(link, &attr); 196233343a97Smeem if (status != WLADM_STATUS_OK) 196333343a97Smeem die_wlerr(status, "cannot get link attributes for '%s'", link); 19640ba2cbe9Sxc151355 19650ba2cbe9Sxc151355 if (statep->ws_header) { 19660ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 19670ba2cbe9Sxc151355 if (!statep->ws_parseable) 19680ba2cbe9Sxc151355 print_wifi_head(statep); 19690ba2cbe9Sxc151355 } 19700ba2cbe9Sxc151355 19710ba2cbe9Sxc151355 statep->ws_link = link; 19720ba2cbe9Sxc151355 statep->ws_overflow = 0; 19730ba2cbe9Sxc151355 for (i = 0; i < statep->ws_nfields; i++) { 19740ba2cbe9Sxc151355 statep->ws_lastfield = (i + 1 == statep->ws_nfields); 19750ba2cbe9Sxc151355 print_link_attr(statep, statep->ws_fields[i], &attr); 19760ba2cbe9Sxc151355 } 19770ba2cbe9Sxc151355 (void) putchar('\n'); 19780ba2cbe9Sxc151355 return (B_TRUE); 19790ba2cbe9Sxc151355 } 19800ba2cbe9Sxc151355 19810ba2cbe9Sxc151355 static void 19820ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd) 19830ba2cbe9Sxc151355 { 19840ba2cbe9Sxc151355 int option; 19850ba2cbe9Sxc151355 char *fields_str = NULL; 19860ba2cbe9Sxc151355 wifi_field_t **fields; 19870ba2cbe9Sxc151355 boolean_t (*callback)(void *, const char *); 19880ba2cbe9Sxc151355 uint_t nfields; 19890ba2cbe9Sxc151355 print_wifi_state_t state; 19900ba2cbe9Sxc151355 wladm_status_t status; 19910ba2cbe9Sxc151355 19920ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 19930ba2cbe9Sxc151355 callback = scan_wifi; 19940ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 19950ba2cbe9Sxc151355 callback = show_wifi; 19960ba2cbe9Sxc151355 else 19970ba2cbe9Sxc151355 return; 19980ba2cbe9Sxc151355 19990ba2cbe9Sxc151355 state.ws_link = NULL; 20000ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 20010ba2cbe9Sxc151355 state.ws_header = B_TRUE; 20020ba2cbe9Sxc151355 opterr = 0; 20030ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 20040ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 20050ba2cbe9Sxc151355 switch (option) { 20060ba2cbe9Sxc151355 case 'o': 20070ba2cbe9Sxc151355 fields_str = optarg; 20080ba2cbe9Sxc151355 break; 20090ba2cbe9Sxc151355 case 'p': 20100ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 20110ba2cbe9Sxc151355 if (fields_str == NULL) 20120ba2cbe9Sxc151355 fields_str = "all"; 20130ba2cbe9Sxc151355 break; 20140ba2cbe9Sxc151355 default: 201533343a97Smeem die_opterr(optopt, option); 20160ba2cbe9Sxc151355 break; 20170ba2cbe9Sxc151355 } 20180ba2cbe9Sxc151355 } 20190ba2cbe9Sxc151355 20200ba2cbe9Sxc151355 if (optind == (argc - 1)) 20210ba2cbe9Sxc151355 state.ws_link = argv[optind]; 20220ba2cbe9Sxc151355 else if (optind != argc) 20230ba2cbe9Sxc151355 usage(); 20240ba2cbe9Sxc151355 202533343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 202633343a97Smeem die("invalid field(s) specified"); 202733343a97Smeem 20280ba2cbe9Sxc151355 state.ws_fields = fields; 20290ba2cbe9Sxc151355 state.ws_nfields = nfields; 20300ba2cbe9Sxc151355 20310ba2cbe9Sxc151355 if (state.ws_link == NULL) { 20320ba2cbe9Sxc151355 status = wladm_walk(&state, callback); 203333343a97Smeem if (status != WLADM_STATUS_OK) 203433343a97Smeem die_wlerr(status, "cannot walk wifi links"); 20350ba2cbe9Sxc151355 } else { 20360ba2cbe9Sxc151355 (void) (*callback)(&state, state.ws_link); 20370ba2cbe9Sxc151355 } 20380ba2cbe9Sxc151355 free(fields); 20390ba2cbe9Sxc151355 } 20400ba2cbe9Sxc151355 20410ba2cbe9Sxc151355 static void 20420ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv) 20430ba2cbe9Sxc151355 { 20440ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 20450ba2cbe9Sxc151355 } 20460ba2cbe9Sxc151355 20470ba2cbe9Sxc151355 static void 20480ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv) 20490ba2cbe9Sxc151355 { 20500ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 20510ba2cbe9Sxc151355 } 20520ba2cbe9Sxc151355 20530ba2cbe9Sxc151355 typedef struct wlan_count_attr { 20540ba2cbe9Sxc151355 uint_t wc_count; 20550ba2cbe9Sxc151355 const char *wc_link; 20560ba2cbe9Sxc151355 } wlan_count_attr_t; 20570ba2cbe9Sxc151355 20580ba2cbe9Sxc151355 static boolean_t 20590ba2cbe9Sxc151355 do_count_wlan(void *arg, const char *link) 20600ba2cbe9Sxc151355 { 206133343a97Smeem wlan_count_attr_t *cp = arg; 20620ba2cbe9Sxc151355 20630ba2cbe9Sxc151355 if (cp->wc_count == 0) 20640ba2cbe9Sxc151355 cp->wc_link = strdup(link); 20650ba2cbe9Sxc151355 cp->wc_count++; 20660ba2cbe9Sxc151355 return (B_TRUE); 20670ba2cbe9Sxc151355 } 20680ba2cbe9Sxc151355 20690ba2cbe9Sxc151355 static int 20700ba2cbe9Sxc151355 parse_wep_keys(char *str, wladm_wep_key_t **keys, uint_t *key_countp) 20710ba2cbe9Sxc151355 { 20720ba2cbe9Sxc151355 uint_t i; 20730ba2cbe9Sxc151355 split_t *sp; 20740ba2cbe9Sxc151355 wladm_wep_key_t *wk; 20750ba2cbe9Sxc151355 20760ba2cbe9Sxc151355 sp = split(str, WLADM_MAX_WEPKEYS, WLADM_MAX_WEPKEYNAME_LEN); 20770ba2cbe9Sxc151355 if (sp == NULL) 20780ba2cbe9Sxc151355 return (-1); 20790ba2cbe9Sxc151355 20800ba2cbe9Sxc151355 wk = malloc(sp->s_nfields * sizeof (wladm_wep_key_t)); 20810ba2cbe9Sxc151355 if (wk == NULL) 20820ba2cbe9Sxc151355 goto fail; 20830ba2cbe9Sxc151355 20840ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 20850ba2cbe9Sxc151355 char *s; 20860ba2cbe9Sxc151355 dladm_secobj_class_t class; 20870ba2cbe9Sxc151355 dladm_status_t status; 20880ba2cbe9Sxc151355 20890ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 20900ba2cbe9Sxc151355 WLADM_MAX_WEPKEYNAME_LEN); 20910ba2cbe9Sxc151355 20920ba2cbe9Sxc151355 wk[i].wk_idx = 1; 20930ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 20940ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 20950ba2cbe9Sxc151355 goto fail; 20960ba2cbe9Sxc151355 20970ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 20980ba2cbe9Sxc151355 *s = '\0'; 20990ba2cbe9Sxc151355 } 21000ba2cbe9Sxc151355 wk[i].wk_len = WLADM_MAX_WEPKEY_LEN; 21010ba2cbe9Sxc151355 21020ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 21030ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 21040ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 21050ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 21060ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 21070ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 21080ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 21090ba2cbe9Sxc151355 } 21100ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 21110ba2cbe9Sxc151355 goto fail; 21120ba2cbe9Sxc151355 } 21130ba2cbe9Sxc151355 } 21140ba2cbe9Sxc151355 *keys = wk; 21150ba2cbe9Sxc151355 *key_countp = i; 21160ba2cbe9Sxc151355 splitfree(sp); 21170ba2cbe9Sxc151355 return (0); 21180ba2cbe9Sxc151355 fail: 21190ba2cbe9Sxc151355 free(wk); 21200ba2cbe9Sxc151355 splitfree(sp); 21210ba2cbe9Sxc151355 return (-1); 21220ba2cbe9Sxc151355 } 21230ba2cbe9Sxc151355 21240ba2cbe9Sxc151355 static void 21250ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv) 21260ba2cbe9Sxc151355 { 21270ba2cbe9Sxc151355 int option; 21280ba2cbe9Sxc151355 wladm_wlan_attr_t attr, *attrp; 21290ba2cbe9Sxc151355 wladm_status_t status = WLADM_STATUS_OK; 21300ba2cbe9Sxc151355 int timeout = WLADM_CONNECT_TIMEOUT_DEFAULT; 21310ba2cbe9Sxc151355 const char *link = NULL; 21320ba2cbe9Sxc151355 wladm_wep_key_t *keys = NULL; 21330ba2cbe9Sxc151355 uint_t key_count = 0; 21340ba2cbe9Sxc151355 uint_t flags = 0; 21350ba2cbe9Sxc151355 wladm_secmode_t keysecmode = WLADM_SECMODE_NONE; 21360ba2cbe9Sxc151355 21370ba2cbe9Sxc151355 opterr = 0; 21380ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 21390ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 21400ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 21410ba2cbe9Sxc151355 switch (option) { 21420ba2cbe9Sxc151355 case 'e': 21430ba2cbe9Sxc151355 status = wladm_str2essid(optarg, &attr.wa_essid); 214433343a97Smeem if (status != WLADM_STATUS_OK) 214533343a97Smeem die("invalid ESSID '%s'", optarg); 214633343a97Smeem 21470ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_ESSID; 21480ba2cbe9Sxc151355 /* 21490ba2cbe9Sxc151355 * Try to connect without doing a scan. 21500ba2cbe9Sxc151355 */ 21510ba2cbe9Sxc151355 flags |= WLADM_OPT_NOSCAN; 21520ba2cbe9Sxc151355 break; 21530ba2cbe9Sxc151355 case 'i': 21540ba2cbe9Sxc151355 status = wladm_str2bssid(optarg, &attr.wa_bssid); 215533343a97Smeem if (status != WLADM_STATUS_OK) 215633343a97Smeem die("invalid BSSID %s", optarg); 215733343a97Smeem 21580ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSID; 21590ba2cbe9Sxc151355 break; 21600ba2cbe9Sxc151355 case 'a': 21610ba2cbe9Sxc151355 status = wladm_str2auth(optarg, &attr.wa_auth); 216233343a97Smeem if (status != WLADM_STATUS_OK) 216333343a97Smeem die("invalid authentication mode '%s'", optarg); 216433343a97Smeem 21650ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_AUTH; 21660ba2cbe9Sxc151355 break; 21670ba2cbe9Sxc151355 case 'm': 21680ba2cbe9Sxc151355 status = wladm_str2mode(optarg, &attr.wa_mode); 216933343a97Smeem if (status != WLADM_STATUS_OK) 217033343a97Smeem die("invalid mode '%s'", optarg); 217133343a97Smeem 21720ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_MODE; 21730ba2cbe9Sxc151355 break; 21740ba2cbe9Sxc151355 case 'b': 21750ba2cbe9Sxc151355 status = wladm_str2bsstype(optarg, &attr.wa_bsstype); 217633343a97Smeem if (status != WLADM_STATUS_OK) 217733343a97Smeem die("invalid bsstype '%s'", optarg); 217833343a97Smeem 21790ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_BSSTYPE; 21800ba2cbe9Sxc151355 break; 21810ba2cbe9Sxc151355 case 's': 21820ba2cbe9Sxc151355 status = wladm_str2secmode(optarg, &attr.wa_secmode); 218333343a97Smeem if (status != WLADM_STATUS_OK) 218433343a97Smeem die("invalid security mode '%s'", optarg); 218533343a97Smeem 21860ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 21870ba2cbe9Sxc151355 break; 21880ba2cbe9Sxc151355 case 'k': 218933343a97Smeem if (parse_wep_keys(optarg, &keys, &key_count) < 0) 219033343a97Smeem die("invalid key(s) '%s'", optarg); 219133343a97Smeem 21920ba2cbe9Sxc151355 keysecmode = WLADM_SECMODE_WEP; 21930ba2cbe9Sxc151355 break; 21940ba2cbe9Sxc151355 case 'T': 21950ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 21960ba2cbe9Sxc151355 timeout = -1; 21970ba2cbe9Sxc151355 break; 21980ba2cbe9Sxc151355 } 219933343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 220033343a97Smeem die("invalid timeout value '%s'", optarg); 22010ba2cbe9Sxc151355 break; 22020ba2cbe9Sxc151355 case 'c': 22030ba2cbe9Sxc151355 flags |= WLADM_OPT_CREATEIBSS; 22040ba2cbe9Sxc151355 break; 22050ba2cbe9Sxc151355 default: 220633343a97Smeem die_opterr(optopt, option); 22070ba2cbe9Sxc151355 break; 22080ba2cbe9Sxc151355 } 22090ba2cbe9Sxc151355 } 22100ba2cbe9Sxc151355 22110ba2cbe9Sxc151355 if (keysecmode == WLADM_SECMODE_NONE) { 22120ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 221333343a97Smeem attr.wa_secmode == WLADM_SECMODE_WEP) 221433343a97Smeem die("key required for security mode 'wep'"); 22150ba2cbe9Sxc151355 } else { 22160ba2cbe9Sxc151355 if ((attr.wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 && 221733343a97Smeem attr.wa_secmode != keysecmode) 221833343a97Smeem die("incompatible -s and -k options"); 22190ba2cbe9Sxc151355 } 22200ba2cbe9Sxc151355 attr.wa_secmode = keysecmode; 22210ba2cbe9Sxc151355 attr.wa_valid |= WLADM_WLAN_ATTR_SECMODE; 22220ba2cbe9Sxc151355 22230ba2cbe9Sxc151355 if (optind == (argc - 1)) 22240ba2cbe9Sxc151355 link = argv[optind]; 22250ba2cbe9Sxc151355 else if (optind != argc) 22260ba2cbe9Sxc151355 usage(); 22270ba2cbe9Sxc151355 22280ba2cbe9Sxc151355 if (link == NULL) { 22290ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22300ba2cbe9Sxc151355 22310ba2cbe9Sxc151355 wcattr.wc_link = NULL; 22320ba2cbe9Sxc151355 wcattr.wc_count = 0; 22330ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 22340ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 223533343a97Smeem die("no wifi links are available"); 22360ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 223733343a97Smeem die("link name is required when more than one wifi " 223833343a97Smeem "link is available"); 22390ba2cbe9Sxc151355 } 22400ba2cbe9Sxc151355 link = wcattr.wc_link; 22410ba2cbe9Sxc151355 } 22420ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 224333343a97Smeem again: 22440ba2cbe9Sxc151355 status = wladm_connect(link, attrp, timeout, keys, key_count, flags); 22450ba2cbe9Sxc151355 if (status != WLADM_STATUS_OK) { 22460ba2cbe9Sxc151355 if ((flags & WLADM_OPT_NOSCAN) != 0) { 22470ba2cbe9Sxc151355 /* 224833343a97Smeem * Try again with scanning and filtering. 22490ba2cbe9Sxc151355 */ 22500ba2cbe9Sxc151355 flags &= ~WLADM_OPT_NOSCAN; 225133343a97Smeem goto again; 22520ba2cbe9Sxc151355 } 225333343a97Smeem 22540ba2cbe9Sxc151355 if (status == WLADM_STATUS_NOTFOUND) { 22550ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 225633343a97Smeem die("no wifi networks are available"); 22570ba2cbe9Sxc151355 } else { 225833343a97Smeem die("no wifi networks with the specified " 225933343a97Smeem "criteria are available"); 22600ba2cbe9Sxc151355 } 22610ba2cbe9Sxc151355 } 226213994ee8Sxz162242 die_wlerr(status, "cannot connect link '%s'", link); 22630ba2cbe9Sxc151355 } 22640ba2cbe9Sxc151355 free(keys); 22650ba2cbe9Sxc151355 } 22660ba2cbe9Sxc151355 22670ba2cbe9Sxc151355 /* ARGSUSED */ 22680ba2cbe9Sxc151355 static boolean_t 22690ba2cbe9Sxc151355 do_all_disconnect_wifi(void *arg, const char *link) 22700ba2cbe9Sxc151355 { 22710ba2cbe9Sxc151355 wladm_status_t status; 22720ba2cbe9Sxc151355 22730ba2cbe9Sxc151355 status = wladm_disconnect(link); 227433343a97Smeem if (status != WLADM_STATUS_OK) 227533343a97Smeem warn_wlerr(status, "cannot disconnect link '%s'", link); 227633343a97Smeem 22770ba2cbe9Sxc151355 return (B_TRUE); 22780ba2cbe9Sxc151355 } 22790ba2cbe9Sxc151355 22800ba2cbe9Sxc151355 static void 22810ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv) 22820ba2cbe9Sxc151355 { 22830ba2cbe9Sxc151355 int option; 22840ba2cbe9Sxc151355 const char *link = NULL; 22850ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 22860ba2cbe9Sxc151355 wladm_status_t status; 22870ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 22880ba2cbe9Sxc151355 22890ba2cbe9Sxc151355 opterr = 0; 22900ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 22910ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 22920ba2cbe9Sxc151355 switch (option) { 22930ba2cbe9Sxc151355 case 'a': 22940ba2cbe9Sxc151355 all_links = B_TRUE; 22950ba2cbe9Sxc151355 break; 22960ba2cbe9Sxc151355 default: 229733343a97Smeem die_opterr(optopt, option); 22980ba2cbe9Sxc151355 break; 22990ba2cbe9Sxc151355 } 23000ba2cbe9Sxc151355 } 23010ba2cbe9Sxc151355 23020ba2cbe9Sxc151355 if (optind == (argc - 1)) 23030ba2cbe9Sxc151355 link = argv[optind]; 23040ba2cbe9Sxc151355 else if (optind != argc) 23050ba2cbe9Sxc151355 usage(); 23060ba2cbe9Sxc151355 23070ba2cbe9Sxc151355 if (link == NULL) { 23080ba2cbe9Sxc151355 if (!all_links) { 23090ba2cbe9Sxc151355 wcattr.wc_link = NULL; 23100ba2cbe9Sxc151355 wcattr.wc_count = 0; 23110ba2cbe9Sxc151355 (void) wladm_walk(&wcattr, do_count_wlan); 23120ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 231333343a97Smeem die("no wifi links are available"); 23140ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 231533343a97Smeem die("link name is required when more than " 231633343a97Smeem "one wifi link is available"); 23170ba2cbe9Sxc151355 } 23180ba2cbe9Sxc151355 link = wcattr.wc_link; 23190ba2cbe9Sxc151355 } else { 23200ba2cbe9Sxc151355 (void) wladm_walk(&all_links, do_all_disconnect_wifi); 23210ba2cbe9Sxc151355 return; 23220ba2cbe9Sxc151355 } 23230ba2cbe9Sxc151355 } 23240ba2cbe9Sxc151355 status = wladm_disconnect(link); 232533343a97Smeem if (status != WLADM_STATUS_OK) 232633343a97Smeem die_wlerr(status, "cannot disconnect link '%s'", link); 23270ba2cbe9Sxc151355 } 23280ba2cbe9Sxc151355 23290ba2cbe9Sxc151355 #define MAX_PROPS 32 23300ba2cbe9Sxc151355 #define MAX_PROP_VALS 32 23310ba2cbe9Sxc151355 #define MAX_PROP_LINE 512 23320ba2cbe9Sxc151355 23330ba2cbe9Sxc151355 typedef struct prop_info { 23340ba2cbe9Sxc151355 char *pi_name; 23350ba2cbe9Sxc151355 char *pi_val[MAX_PROP_VALS]; 23360ba2cbe9Sxc151355 uint_t pi_count; 23370ba2cbe9Sxc151355 } prop_info_t; 23380ba2cbe9Sxc151355 23390ba2cbe9Sxc151355 typedef struct prop_list { 23400ba2cbe9Sxc151355 prop_info_t pl_info[MAX_PROPS]; 23410ba2cbe9Sxc151355 uint_t pl_count; 23420ba2cbe9Sxc151355 char *pl_buf; 23430ba2cbe9Sxc151355 } prop_list_t; 23440ba2cbe9Sxc151355 23450ba2cbe9Sxc151355 typedef struct show_linkprop_state { 23460ba2cbe9Sxc151355 const char *ls_link; 23470ba2cbe9Sxc151355 char *ls_line; 23480ba2cbe9Sxc151355 char **ls_propvals; 2349f4b3ec61Sdh155122 prop_list_t *ls_proplist; 23500ba2cbe9Sxc151355 boolean_t ls_parseable; 23510ba2cbe9Sxc151355 boolean_t ls_persist; 23520ba2cbe9Sxc151355 boolean_t ls_header; 23530ba2cbe9Sxc151355 } show_linkprop_state_t; 23540ba2cbe9Sxc151355 23550ba2cbe9Sxc151355 static void 23560ba2cbe9Sxc151355 free_props(prop_list_t *list) 23570ba2cbe9Sxc151355 { 23580ba2cbe9Sxc151355 if (list != NULL) { 23590ba2cbe9Sxc151355 free(list->pl_buf); 23600ba2cbe9Sxc151355 free(list); 23610ba2cbe9Sxc151355 } 23620ba2cbe9Sxc151355 } 23630ba2cbe9Sxc151355 23640ba2cbe9Sxc151355 static int 23650ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 23660ba2cbe9Sxc151355 { 23670ba2cbe9Sxc151355 prop_list_t *list; 23680ba2cbe9Sxc151355 prop_info_t *pip; 23690ba2cbe9Sxc151355 char *buf, *curr; 23700ba2cbe9Sxc151355 int len, i; 23710ba2cbe9Sxc151355 23720ba2cbe9Sxc151355 list = malloc(sizeof (prop_list_t)); 23730ba2cbe9Sxc151355 if (list == NULL) 23740ba2cbe9Sxc151355 return (-1); 23750ba2cbe9Sxc151355 23760ba2cbe9Sxc151355 list->pl_count = 0; 23770ba2cbe9Sxc151355 list->pl_buf = buf = strdup(str); 23780ba2cbe9Sxc151355 if (buf == NULL) 23790ba2cbe9Sxc151355 goto fail; 23800ba2cbe9Sxc151355 23810ba2cbe9Sxc151355 curr = buf; 23820ba2cbe9Sxc151355 len = strlen(buf); 23830ba2cbe9Sxc151355 pip = NULL; 23840ba2cbe9Sxc151355 for (i = 0; i < len; i++) { 23850ba2cbe9Sxc151355 char c = buf[i]; 23860ba2cbe9Sxc151355 boolean_t match = (c == '=' || c == ','); 23870ba2cbe9Sxc151355 23880ba2cbe9Sxc151355 if (!match && i != len - 1) 23890ba2cbe9Sxc151355 continue; 23900ba2cbe9Sxc151355 23910ba2cbe9Sxc151355 if (match) { 23920ba2cbe9Sxc151355 buf[i] = '\0'; 23930ba2cbe9Sxc151355 if (*curr == '\0') 23940ba2cbe9Sxc151355 goto fail; 23950ba2cbe9Sxc151355 } 23960ba2cbe9Sxc151355 23970ba2cbe9Sxc151355 if (pip != NULL && c != '=') { 23980ba2cbe9Sxc151355 if (pip->pi_count > MAX_PROP_VALS) 23990ba2cbe9Sxc151355 goto fail; 24000ba2cbe9Sxc151355 24010ba2cbe9Sxc151355 if (novalues) 24020ba2cbe9Sxc151355 goto fail; 24030ba2cbe9Sxc151355 24040ba2cbe9Sxc151355 pip->pi_val[pip->pi_count] = curr; 24050ba2cbe9Sxc151355 pip->pi_count++; 24060ba2cbe9Sxc151355 } else { 24070ba2cbe9Sxc151355 if (list->pl_count > MAX_PROPS) 24080ba2cbe9Sxc151355 goto fail; 24090ba2cbe9Sxc151355 24100ba2cbe9Sxc151355 pip = &list->pl_info[list->pl_count]; 24110ba2cbe9Sxc151355 pip->pi_name = curr; 24120ba2cbe9Sxc151355 pip->pi_count = 0; 24130ba2cbe9Sxc151355 list->pl_count++; 24140ba2cbe9Sxc151355 if (c == ',') 24150ba2cbe9Sxc151355 pip = NULL; 24160ba2cbe9Sxc151355 } 24170ba2cbe9Sxc151355 curr = buf + i + 1; 24180ba2cbe9Sxc151355 } 24190ba2cbe9Sxc151355 *listp = list; 24200ba2cbe9Sxc151355 return (0); 24210ba2cbe9Sxc151355 24220ba2cbe9Sxc151355 fail: 24230ba2cbe9Sxc151355 free_props(list); 24240ba2cbe9Sxc151355 return (-1); 24250ba2cbe9Sxc151355 } 24260ba2cbe9Sxc151355 24270ba2cbe9Sxc151355 static void 24280ba2cbe9Sxc151355 print_linkprop_head(void) 24290ba2cbe9Sxc151355 { 2430f4b3ec61Sdh155122 (void) printf("%-12s %-15s %-14s %-14s %-20s \n", 2431f4b3ec61Sdh155122 "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); 24320ba2cbe9Sxc151355 } 24330ba2cbe9Sxc151355 24340ba2cbe9Sxc151355 static void 24350ba2cbe9Sxc151355 print_linkprop(show_linkprop_state_t *statep, const char *propname, 24360ba2cbe9Sxc151355 dladm_prop_type_t type, const char *typename, const char *format, 24370ba2cbe9Sxc151355 char **pptr) 24380ba2cbe9Sxc151355 { 24390ba2cbe9Sxc151355 int i; 24400ba2cbe9Sxc151355 char *ptr, *lim; 24410ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 24420ba2cbe9Sxc151355 char *unknown = "?", *notsup = ""; 24430ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 24440ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 24450ba2cbe9Sxc151355 dladm_status_t status; 24460ba2cbe9Sxc151355 24470ba2cbe9Sxc151355 status = dladm_get_prop(statep->ls_link, type, propname, 24480ba2cbe9Sxc151355 propvals, &valcnt); 24490ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 24500ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTSUP || statep->ls_persist) { 24510ba2cbe9Sxc151355 valcnt = 1; 24520ba2cbe9Sxc151355 if (type == DLADM_PROP_VAL_CURRENT) 24530ba2cbe9Sxc151355 propvals = &unknown; 24540ba2cbe9Sxc151355 else 24550ba2cbe9Sxc151355 propvals = ¬sup; 24560ba2cbe9Sxc151355 } else { 245733343a97Smeem die_dlerr(status, "cannot get link property '%s'", 245833343a97Smeem propname); 24590ba2cbe9Sxc151355 } 24600ba2cbe9Sxc151355 } 24610ba2cbe9Sxc151355 24620ba2cbe9Sxc151355 ptr = buf; 24630ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 24640ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 24650ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 24660ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "--,"); 24670ba2cbe9Sxc151355 else 24680ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 24690ba2cbe9Sxc151355 if (ptr >= lim) 24700ba2cbe9Sxc151355 break; 24710ba2cbe9Sxc151355 } 24720ba2cbe9Sxc151355 if (valcnt > 0) 24730ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 24740ba2cbe9Sxc151355 24750ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 24760ba2cbe9Sxc151355 if (statep->ls_parseable) { 24770ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 24780ba2cbe9Sxc151355 "%s=\"%s\" ", typename, buf); 24790ba2cbe9Sxc151355 } else { 24800ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 24810ba2cbe9Sxc151355 } 24820ba2cbe9Sxc151355 } 24830ba2cbe9Sxc151355 24840ba2cbe9Sxc151355 static boolean_t 24850ba2cbe9Sxc151355 show_linkprop(void *arg, const char *propname) 24860ba2cbe9Sxc151355 { 24870ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 24880ba2cbe9Sxc151355 char *ptr = statep->ls_line; 24890ba2cbe9Sxc151355 char *lim = ptr + MAX_PROP_LINE; 24900ba2cbe9Sxc151355 2491f4b3ec61Sdh155122 if (statep->ls_persist && dladm_is_prop_temponly(propname, NULL)) 2492f4b3ec61Sdh155122 return (B_TRUE); 2493f4b3ec61Sdh155122 2494f4b3ec61Sdh155122 if (statep->ls_parseable) 2495f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", 2496f4b3ec61Sdh155122 statep->ls_link); 2497f4b3ec61Sdh155122 else 2498f4b3ec61Sdh155122 ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); 2499f4b3ec61Sdh155122 25000ba2cbe9Sxc151355 if (statep->ls_parseable) 25010ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); 25020ba2cbe9Sxc151355 else 25030ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); 25040ba2cbe9Sxc151355 25050ba2cbe9Sxc151355 print_linkprop(statep, propname, 25060ba2cbe9Sxc151355 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 25070ba2cbe9Sxc151355 DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); 25080ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT, 25090ba2cbe9Sxc151355 "DEFAULT", "%-14s ", &ptr); 25100ba2cbe9Sxc151355 print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE, 2511f4b3ec61Sdh155122 "POSSIBLE", "%-20s ", &ptr); 25120ba2cbe9Sxc151355 25130ba2cbe9Sxc151355 if (statep->ls_header) { 25140ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 25150ba2cbe9Sxc151355 if (!statep->ls_parseable) 25160ba2cbe9Sxc151355 print_linkprop_head(); 25170ba2cbe9Sxc151355 } 25180ba2cbe9Sxc151355 (void) printf("%s\n", statep->ls_line); 25190ba2cbe9Sxc151355 return (B_TRUE); 25200ba2cbe9Sxc151355 } 25210ba2cbe9Sxc151355 25220ba2cbe9Sxc151355 static void 25230ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv) 25240ba2cbe9Sxc151355 { 2525f4b3ec61Sdh155122 int option; 25260ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 25270ba2cbe9Sxc151355 show_linkprop_state_t state; 25280ba2cbe9Sxc151355 25290ba2cbe9Sxc151355 opterr = 0; 25300ba2cbe9Sxc151355 state.ls_link = NULL; 25310ba2cbe9Sxc151355 state.ls_propvals = NULL; 25320ba2cbe9Sxc151355 state.ls_line = NULL; 25330ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 25340ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 25350ba2cbe9Sxc151355 state.ls_header = B_TRUE; 25360ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:cP", 25370ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 25380ba2cbe9Sxc151355 switch (option) { 25390ba2cbe9Sxc151355 case 'p': 254033343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 254113994ee8Sxz162242 die("invalid link properties specified"); 25420ba2cbe9Sxc151355 break; 25430ba2cbe9Sxc151355 case 'c': 25440ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 25450ba2cbe9Sxc151355 break; 25460ba2cbe9Sxc151355 case 'P': 25470ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 25480ba2cbe9Sxc151355 break; 25490ba2cbe9Sxc151355 default: 255033343a97Smeem die_opterr(optopt, option); 25510ba2cbe9Sxc151355 break; 25520ba2cbe9Sxc151355 } 25530ba2cbe9Sxc151355 } 25540ba2cbe9Sxc151355 25550ba2cbe9Sxc151355 if (optind == (argc - 1)) 25560ba2cbe9Sxc151355 state.ls_link = argv[optind]; 25570ba2cbe9Sxc151355 else if (optind != argc) 25580ba2cbe9Sxc151355 usage(); 25590ba2cbe9Sxc151355 2560f4b3ec61Sdh155122 state.ls_proplist = proplist; 2561f4b3ec61Sdh155122 2562f4b3ec61Sdh155122 if (state.ls_link == NULL) { 2563f4b3ec61Sdh155122 (void) dladm_walk(show_linkprop_onelink, &state); 2564f4b3ec61Sdh155122 } else { 2565f4b3ec61Sdh155122 show_linkprop_onelink(&state, state.ls_link); 2566f4b3ec61Sdh155122 } 2567f4b3ec61Sdh155122 free_props(proplist); 2568f4b3ec61Sdh155122 } 2569f4b3ec61Sdh155122 2570f4b3ec61Sdh155122 static void 2571f4b3ec61Sdh155122 show_linkprop_onelink(void *arg, const char *link) 2572f4b3ec61Sdh155122 { 2573f4b3ec61Sdh155122 int i, fd; 2574f4b3ec61Sdh155122 char linkname[MAXPATHLEN]; 2575f4b3ec61Sdh155122 char *buf; 2576f4b3ec61Sdh155122 dladm_status_t status; 2577f4b3ec61Sdh155122 prop_list_t *proplist = NULL; 2578f4b3ec61Sdh155122 show_linkprop_state_t *statep; 2579f4b3ec61Sdh155122 const char *savep; 2580f4b3ec61Sdh155122 2581f4b3ec61Sdh155122 statep = (show_linkprop_state_t *)arg; 2582f4b3ec61Sdh155122 savep = statep->ls_link; 2583f4b3ec61Sdh155122 statep->ls_link = link; 2584f4b3ec61Sdh155122 proplist = statep->ls_proplist; 25850ba2cbe9Sxc151355 25860ba2cbe9Sxc151355 /* 25870ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 25880ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 25890ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 25900ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 25910ba2cbe9Sxc151355 */ 2592f4b3ec61Sdh155122 (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); 259333343a97Smeem if ((fd = open(linkname, O_RDWR)) < 0) 2594f4b3ec61Sdh155122 die("cannot open %s: %s", link, strerror(errno)); 25950ba2cbe9Sxc151355 25960ba2cbe9Sxc151355 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 25970ba2cbe9Sxc151355 MAX_PROP_LINE); 259833343a97Smeem if (buf == NULL) 259933343a97Smeem die("insufficient memory"); 260033343a97Smeem 2601f4b3ec61Sdh155122 statep->ls_propvals = (char **)(void *)buf; 26020ba2cbe9Sxc151355 for (i = 0; i < MAX_PROP_VALS; i++) { 2603f4b3ec61Sdh155122 statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS + 26040ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 26050ba2cbe9Sxc151355 } 2606f4b3ec61Sdh155122 statep->ls_line = buf + 26070ba2cbe9Sxc151355 (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS; 26080ba2cbe9Sxc151355 26090ba2cbe9Sxc151355 if (proplist != NULL) { 26100ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 2611f4b3ec61Sdh155122 if (!show_linkprop(statep, 26120ba2cbe9Sxc151355 proplist->pl_info[i].pi_name)) 26130ba2cbe9Sxc151355 break; 26140ba2cbe9Sxc151355 } 26150ba2cbe9Sxc151355 } else { 2616f4b3ec61Sdh155122 status = dladm_walk_prop(link, statep, show_linkprop); 261733343a97Smeem if (status != DLADM_STATUS_OK) 261833343a97Smeem die_dlerr(status, "show-linkprop"); 26190ba2cbe9Sxc151355 } 26200ba2cbe9Sxc151355 (void) close(fd); 26210ba2cbe9Sxc151355 free(buf); 2622f4b3ec61Sdh155122 statep->ls_link = savep; 26230ba2cbe9Sxc151355 } 26240ba2cbe9Sxc151355 26250ba2cbe9Sxc151355 static dladm_status_t 26260ba2cbe9Sxc151355 set_linkprop_persist(const char *link, const char *prop_name, char **prop_val, 26270ba2cbe9Sxc151355 uint_t val_cnt, boolean_t reset) 26280ba2cbe9Sxc151355 { 26290ba2cbe9Sxc151355 dladm_status_t status; 2630f4b3ec61Sdh155122 char *errprop; 26310ba2cbe9Sxc151355 26320ba2cbe9Sxc151355 status = dladm_set_prop(link, prop_name, prop_val, val_cnt, 2633f4b3ec61Sdh155122 DLADM_OPT_PERSIST, &errprop); 26340ba2cbe9Sxc151355 26350ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 26360ba2cbe9Sxc151355 if (reset) { 263733343a97Smeem warn_dlerr(status, "cannot persistently reset link " 2638f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26390ba2cbe9Sxc151355 } else { 264033343a97Smeem warn_dlerr(status, "cannot persistently set link " 2641f4b3ec61Sdh155122 "property '%s' on '%s'", errprop, link); 26420ba2cbe9Sxc151355 } 26430ba2cbe9Sxc151355 } 26440ba2cbe9Sxc151355 return (status); 26450ba2cbe9Sxc151355 } 26460ba2cbe9Sxc151355 26470ba2cbe9Sxc151355 static void 26480ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset) 26490ba2cbe9Sxc151355 { 26500ba2cbe9Sxc151355 int i, option; 26510ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 26520ba2cbe9Sxc151355 const char *link = NULL; 26530ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 26540ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 26550ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 26560ba2cbe9Sxc151355 26570ba2cbe9Sxc151355 opterr = 0; 26580ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 26590ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 26600ba2cbe9Sxc151355 switch (option) { 26610ba2cbe9Sxc151355 case 'p': 266233343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 266333343a97Smeem die("invalid link properties specified"); 26640ba2cbe9Sxc151355 break; 26650ba2cbe9Sxc151355 case 't': 26660ba2cbe9Sxc151355 temp = B_TRUE; 26670ba2cbe9Sxc151355 break; 26680ba2cbe9Sxc151355 case 'R': 26690ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 26700ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 267133343a97Smeem die_dlerr(status, "invalid directory " 267233343a97Smeem "specified"); 26730ba2cbe9Sxc151355 } 26740ba2cbe9Sxc151355 break; 26750ba2cbe9Sxc151355 default: 267633343a97Smeem die_opterr(optopt, option); 26770ba2cbe9Sxc151355 break; 26780ba2cbe9Sxc151355 } 26790ba2cbe9Sxc151355 } 26800ba2cbe9Sxc151355 26810ba2cbe9Sxc151355 if (optind == (argc - 1)) 26820ba2cbe9Sxc151355 link = argv[optind]; 26830ba2cbe9Sxc151355 else if (optind != argc) 26840ba2cbe9Sxc151355 usage(); 26850ba2cbe9Sxc151355 268633343a97Smeem if (link == NULL) 268733343a97Smeem die("link name must be specified"); 26880ba2cbe9Sxc151355 2689dbc95d79Sxz162242 if (proplist == NULL) { 2690f4b3ec61Sdh155122 char *errprop; 2691f4b3ec61Sdh155122 2692dbc95d79Sxz162242 if (!reset) 269333343a97Smeem die("link property must be specified"); 269433343a97Smeem 2695f4b3ec61Sdh155122 status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP, 2696f4b3ec61Sdh155122 &errprop); 26970ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 2698f4b3ec61Sdh155122 warn_dlerr(status, "cannot reset link property '%s' " 2699f4b3ec61Sdh155122 "on '%s'", errprop, link); 27000ba2cbe9Sxc151355 } 27010ba2cbe9Sxc151355 if (!temp) { 270213994ee8Sxz162242 dladm_status_t s; 270313994ee8Sxz162242 270413994ee8Sxz162242 s = set_linkprop_persist(link, NULL, NULL, 0, reset); 270513994ee8Sxz162242 if (s != DLADM_STATUS_OK) 270613994ee8Sxz162242 status = s; 27070ba2cbe9Sxc151355 } 27080ba2cbe9Sxc151355 goto done; 27090ba2cbe9Sxc151355 } 27100ba2cbe9Sxc151355 27110ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 27120ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 27130ba2cbe9Sxc151355 char **val; 27140ba2cbe9Sxc151355 uint_t count; 27150ba2cbe9Sxc151355 dladm_status_t s; 27160ba2cbe9Sxc151355 27170ba2cbe9Sxc151355 if (reset) { 27180ba2cbe9Sxc151355 val = NULL; 27190ba2cbe9Sxc151355 count = 0; 27200ba2cbe9Sxc151355 } else { 27210ba2cbe9Sxc151355 val = pip->pi_val; 27220ba2cbe9Sxc151355 count = pip->pi_count; 27230ba2cbe9Sxc151355 if (count == 0) { 272433343a97Smeem warn("no value specified for '%s'", 272533343a97Smeem pip->pi_name); 27260ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 27270ba2cbe9Sxc151355 continue; 27280ba2cbe9Sxc151355 } 27290ba2cbe9Sxc151355 } 27300ba2cbe9Sxc151355 s = dladm_set_prop(link, pip->pi_name, val, count, 2731f4b3ec61Sdh155122 DLADM_OPT_TEMP, NULL); 27320ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 27330ba2cbe9Sxc151355 if (!temp) { 27340ba2cbe9Sxc151355 s = set_linkprop_persist(link, 27350ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 27360ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 27370ba2cbe9Sxc151355 status = s; 27380ba2cbe9Sxc151355 } 27390ba2cbe9Sxc151355 continue; 27400ba2cbe9Sxc151355 } 27410ba2cbe9Sxc151355 status = s; 27420ba2cbe9Sxc151355 switch (s) { 27430ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 274433343a97Smeem warn("invalid link property '%s'", pip->pi_name); 27450ba2cbe9Sxc151355 break; 27460ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 27470ba2cbe9Sxc151355 int j; 27480ba2cbe9Sxc151355 char *ptr, *lim; 27490ba2cbe9Sxc151355 char **propvals = NULL; 27500ba2cbe9Sxc151355 uint_t valcnt = MAX_PROP_VALS; 27510ba2cbe9Sxc151355 27520ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 27530ba2cbe9Sxc151355 DLADM_PROP_VAL_MAX) * MAX_PROP_VALS + 27540ba2cbe9Sxc151355 MAX_PROP_LINE); 27550ba2cbe9Sxc151355 27560ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 275733343a97Smeem if (propvals == NULL) 275833343a97Smeem die("insufficient memory"); 275933343a97Smeem 27600ba2cbe9Sxc151355 for (j = 0; j < MAX_PROP_VALS; j++) { 27610ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 27620ba2cbe9Sxc151355 MAX_PROP_VALS + 27630ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 27640ba2cbe9Sxc151355 } 27650ba2cbe9Sxc151355 s = dladm_get_prop(link, DLADM_PROP_VAL_MODIFIABLE, 27660ba2cbe9Sxc151355 pip->pi_name, propvals, &valcnt); 27670ba2cbe9Sxc151355 27680ba2cbe9Sxc151355 ptr = errmsg; 27690ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 27700ba2cbe9Sxc151355 *ptr = '\0'; 27710ba2cbe9Sxc151355 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 27720ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 27730ba2cbe9Sxc151355 propvals[j]); 27740ba2cbe9Sxc151355 if (ptr >= lim) 27750ba2cbe9Sxc151355 break; 27760ba2cbe9Sxc151355 } 2777f4b3ec61Sdh155122 if (ptr > errmsg) { 27780ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 277933343a97Smeem warn("link property '%s' must be one of: %s", 278033343a97Smeem pip->pi_name, errmsg); 2781f4b3ec61Sdh155122 } else 2782f4b3ec61Sdh155122 warn("invalid link property '%s'", *val); 27830ba2cbe9Sxc151355 free(propvals); 27840ba2cbe9Sxc151355 break; 27850ba2cbe9Sxc151355 } 27860ba2cbe9Sxc151355 default: 27870ba2cbe9Sxc151355 if (reset) { 278833343a97Smeem warn_dlerr(status, "cannot reset link property " 278933343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27900ba2cbe9Sxc151355 } else { 279133343a97Smeem warn_dlerr(status, "cannot set link property " 279233343a97Smeem "'%s' on '%s'", pip->pi_name, link); 27930ba2cbe9Sxc151355 } 27940ba2cbe9Sxc151355 break; 27950ba2cbe9Sxc151355 } 27960ba2cbe9Sxc151355 } 27970ba2cbe9Sxc151355 done: 27980ba2cbe9Sxc151355 free_props(proplist); 27990ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 28000ba2cbe9Sxc151355 exit(1); 28010ba2cbe9Sxc151355 } 28020ba2cbe9Sxc151355 28030ba2cbe9Sxc151355 static void 28040ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 28050ba2cbe9Sxc151355 { 28060ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 28070ba2cbe9Sxc151355 } 28080ba2cbe9Sxc151355 28090ba2cbe9Sxc151355 static void 28100ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 28110ba2cbe9Sxc151355 { 28120ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 28130ba2cbe9Sxc151355 } 28140ba2cbe9Sxc151355 28150ba2cbe9Sxc151355 static int 28160ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 28170ba2cbe9Sxc151355 dladm_secobj_class_t class) 28180ba2cbe9Sxc151355 { 28190ba2cbe9Sxc151355 int error = 0; 28200ba2cbe9Sxc151355 28210ba2cbe9Sxc151355 if (class != DLADM_SECOBJ_CLASS_WEP) 28220ba2cbe9Sxc151355 return (ENOENT); 28230ba2cbe9Sxc151355 28240ba2cbe9Sxc151355 switch (len) { 28250ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 28260ba2cbe9Sxc151355 case 13: 28270ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 28280ba2cbe9Sxc151355 *obj_lenp = len; 28290ba2cbe9Sxc151355 break; 28300ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 28310ba2cbe9Sxc151355 case 26: 28320ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 28330ba2cbe9Sxc151355 break; 28340ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 28350ba2cbe9Sxc151355 case 28: 28360ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 28370ba2cbe9Sxc151355 return (EINVAL); 28380ba2cbe9Sxc151355 error = hexascii_to_octet(buf + 2, len - 2, obj_val, obj_lenp); 28390ba2cbe9Sxc151355 break; 28400ba2cbe9Sxc151355 default: 28410ba2cbe9Sxc151355 return (EINVAL); 28420ba2cbe9Sxc151355 } 28430ba2cbe9Sxc151355 return (error); 28440ba2cbe9Sxc151355 } 28450ba2cbe9Sxc151355 28460ba2cbe9Sxc151355 /* ARGSUSED */ 28470ba2cbe9Sxc151355 static void 28480ba2cbe9Sxc151355 defersig(int sig) 28490ba2cbe9Sxc151355 { 28500ba2cbe9Sxc151355 signalled = sig; 28510ba2cbe9Sxc151355 } 28520ba2cbe9Sxc151355 28530ba2cbe9Sxc151355 static int 28540ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 28550ba2cbe9Sxc151355 { 28560ba2cbe9Sxc151355 uint_t len = 0; 28570ba2cbe9Sxc151355 int c; 28580ba2cbe9Sxc151355 struct termios stored, current; 28590ba2cbe9Sxc151355 void (*sigfunc)(int); 28600ba2cbe9Sxc151355 28610ba2cbe9Sxc151355 /* 28620ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 28630ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 28640ba2cbe9Sxc151355 */ 28650ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 28660ba2cbe9Sxc151355 (void) fflush(stdin); 28670ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 28680ba2cbe9Sxc151355 current = stored; 28690ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 28700ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 28710ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 28720ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 28730ba2cbe9Sxc151355 again: 28740ba2cbe9Sxc151355 if (try == 1) 28750ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 28760ba2cbe9Sxc151355 else 28770ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 28780ba2cbe9Sxc151355 28790ba2cbe9Sxc151355 (void) fflush(stdout); 28800ba2cbe9Sxc151355 while (signalled == 0) { 28810ba2cbe9Sxc151355 c = getchar(); 28820ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 28830ba2cbe9Sxc151355 if (len != 0) 28840ba2cbe9Sxc151355 break; 28850ba2cbe9Sxc151355 (void) putchar('\n'); 28860ba2cbe9Sxc151355 goto again; 28870ba2cbe9Sxc151355 } 28880ba2cbe9Sxc151355 28890ba2cbe9Sxc151355 buf[len++] = c; 28900ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 28910ba2cbe9Sxc151355 break; 28920ba2cbe9Sxc151355 (void) putchar('*'); 28930ba2cbe9Sxc151355 } 28940ba2cbe9Sxc151355 28950ba2cbe9Sxc151355 (void) putchar('\n'); 28960ba2cbe9Sxc151355 (void) fflush(stdin); 28970ba2cbe9Sxc151355 28980ba2cbe9Sxc151355 /* 28990ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 29000ba2cbe9Sxc151355 */ 29010ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 29020ba2cbe9Sxc151355 29030ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 29040ba2cbe9Sxc151355 if (signalled != 0) 29050ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 29060ba2cbe9Sxc151355 29070ba2cbe9Sxc151355 return (len); 29080ba2cbe9Sxc151355 } 29090ba2cbe9Sxc151355 29100ba2cbe9Sxc151355 static int 29110ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 29120ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 29130ba2cbe9Sxc151355 { 29140ba2cbe9Sxc151355 int rval; 29150ba2cbe9Sxc151355 uint_t len, len2; 29160ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 29170ba2cbe9Sxc151355 29180ba2cbe9Sxc151355 if (filep == NULL) { 29190ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 29200ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 29210ba2cbe9Sxc151355 if (rval == 0) { 29220ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 29230ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 29240ba2cbe9Sxc151355 rval = ENOTSUP; 29250ba2cbe9Sxc151355 } 29260ba2cbe9Sxc151355 return (rval); 29270ba2cbe9Sxc151355 } else { 29280ba2cbe9Sxc151355 for (;;) { 29290ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 29300ba2cbe9Sxc151355 break; 29310ba2cbe9Sxc151355 if (isspace(buf[0])) 29320ba2cbe9Sxc151355 continue; 29330ba2cbe9Sxc151355 29340ba2cbe9Sxc151355 len = strlen(buf); 29350ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 29360ba2cbe9Sxc151355 buf[len - 1] = '\0'; 29370ba2cbe9Sxc151355 len--; 29380ba2cbe9Sxc151355 } 29390ba2cbe9Sxc151355 break; 29400ba2cbe9Sxc151355 } 29410ba2cbe9Sxc151355 (void) fclose(filep); 29420ba2cbe9Sxc151355 } 29430ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 29440ba2cbe9Sxc151355 } 29450ba2cbe9Sxc151355 29460ba2cbe9Sxc151355 static boolean_t 29470ba2cbe9Sxc151355 check_auth(const char *auth) 29480ba2cbe9Sxc151355 { 29490ba2cbe9Sxc151355 struct passwd *pw; 29500ba2cbe9Sxc151355 29510ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 29520ba2cbe9Sxc151355 return (B_FALSE); 29530ba2cbe9Sxc151355 29540ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 29550ba2cbe9Sxc151355 } 29560ba2cbe9Sxc151355 29570ba2cbe9Sxc151355 static void 29580ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 29590ba2cbe9Sxc151355 boolean_t success, boolean_t create) 29600ba2cbe9Sxc151355 { 29610ba2cbe9Sxc151355 adt_session_data_t *ah; 29620ba2cbe9Sxc151355 adt_event_data_t *event; 29630ba2cbe9Sxc151355 au_event_t flag; 29640ba2cbe9Sxc151355 char *errstr; 29650ba2cbe9Sxc151355 29660ba2cbe9Sxc151355 if (create) { 29670ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 29680ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 29690ba2cbe9Sxc151355 } else { 29700ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 29710ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 29720ba2cbe9Sxc151355 } 29730ba2cbe9Sxc151355 297433343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 297533343a97Smeem die("adt_start_session: %s", strerror(errno)); 29760ba2cbe9Sxc151355 297733343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 297833343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 29790ba2cbe9Sxc151355 29800ba2cbe9Sxc151355 /* fill in audit info */ 29810ba2cbe9Sxc151355 if (create) { 29820ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 29830ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 29840ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 29850ba2cbe9Sxc151355 } else { 29860ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 29870ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 29880ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 29890ba2cbe9Sxc151355 } 29900ba2cbe9Sxc151355 29910ba2cbe9Sxc151355 if (success) { 29920ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 299333343a97Smeem die("adt_put_event (%s, success): %s", errstr, 299433343a97Smeem strerror(errno)); 29950ba2cbe9Sxc151355 } 29960ba2cbe9Sxc151355 } else { 29970ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 29980ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 299933343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 300033343a97Smeem strerror(errno)); 30010ba2cbe9Sxc151355 } 30020ba2cbe9Sxc151355 } 30030ba2cbe9Sxc151355 30040ba2cbe9Sxc151355 adt_free_event(event); 30050ba2cbe9Sxc151355 (void) adt_end_session(ah); 30060ba2cbe9Sxc151355 } 30070ba2cbe9Sxc151355 30080ba2cbe9Sxc151355 #define MAX_SECOBJS 32 30090ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 30100ba2cbe9Sxc151355 static void 30110ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 30120ba2cbe9Sxc151355 { 30130ba2cbe9Sxc151355 int option, rval; 30140ba2cbe9Sxc151355 FILE *filep = NULL; 30150ba2cbe9Sxc151355 char *obj_name = NULL; 30160ba2cbe9Sxc151355 char *class_name = NULL; 30170ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 30180ba2cbe9Sxc151355 uint_t obj_len; 30190ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 30200ba2cbe9Sxc151355 dladm_status_t status; 30210ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 30220ba2cbe9Sxc151355 uid_t euid; 30230ba2cbe9Sxc151355 30240ba2cbe9Sxc151355 opterr = 0; 30250ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 30260ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 30270ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 30280ba2cbe9Sxc151355 switch (option) { 30290ba2cbe9Sxc151355 case 'f': 30300ba2cbe9Sxc151355 euid = geteuid(); 30310ba2cbe9Sxc151355 (void) seteuid(getuid()); 30320ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 30330ba2cbe9Sxc151355 if (filep == NULL) { 303433343a97Smeem die("cannot open %s: %s", optarg, 303533343a97Smeem strerror(errno)); 30360ba2cbe9Sxc151355 } 30370ba2cbe9Sxc151355 (void) seteuid(euid); 30380ba2cbe9Sxc151355 break; 30390ba2cbe9Sxc151355 case 'c': 30400ba2cbe9Sxc151355 class_name = optarg; 30410ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 30420ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 304333343a97Smeem die("invalid secure object class '%s', " 304433343a97Smeem "valid values are: wep", optarg); 30450ba2cbe9Sxc151355 } 30460ba2cbe9Sxc151355 break; 30470ba2cbe9Sxc151355 case 't': 30480ba2cbe9Sxc151355 temp = B_TRUE; 30490ba2cbe9Sxc151355 break; 30500ba2cbe9Sxc151355 case 'R': 30510ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 30520ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 305333343a97Smeem die_dlerr(status, "invalid directory " 305433343a97Smeem "specified"); 30550ba2cbe9Sxc151355 } 30560ba2cbe9Sxc151355 break; 30570ba2cbe9Sxc151355 default: 305833343a97Smeem die_opterr(optopt, option); 30590ba2cbe9Sxc151355 break; 30600ba2cbe9Sxc151355 } 30610ba2cbe9Sxc151355 } 30620ba2cbe9Sxc151355 30630ba2cbe9Sxc151355 if (optind == (argc - 1)) 30640ba2cbe9Sxc151355 obj_name = argv[optind]; 30650ba2cbe9Sxc151355 else if (optind != argc) 30660ba2cbe9Sxc151355 usage(); 30670ba2cbe9Sxc151355 306833343a97Smeem if (class == -1) 306933343a97Smeem die("secure object class required"); 30700ba2cbe9Sxc151355 307133343a97Smeem if (obj_name == NULL) 307233343a97Smeem die("secure object name required"); 30730ba2cbe9Sxc151355 30740ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 30750ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 307633343a97Smeem if (!success) 307733343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 30780ba2cbe9Sxc151355 307933343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 308033343a97Smeem if (rval != 0) { 30810ba2cbe9Sxc151355 switch (rval) { 30820ba2cbe9Sxc151355 case ENOENT: 308333343a97Smeem die("invalid secure object class"); 30840ba2cbe9Sxc151355 break; 30850ba2cbe9Sxc151355 case EINVAL: 308633343a97Smeem die("invalid secure object value"); 30870ba2cbe9Sxc151355 break; 30880ba2cbe9Sxc151355 case ENOTSUP: 308933343a97Smeem die("verification failed"); 30900ba2cbe9Sxc151355 break; 30910ba2cbe9Sxc151355 default: 309233343a97Smeem die("invalid secure object: %s", strerror(rval)); 30930ba2cbe9Sxc151355 break; 30940ba2cbe9Sxc151355 } 30950ba2cbe9Sxc151355 } 30960ba2cbe9Sxc151355 30970ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 30980ba2cbe9Sxc151355 DLADM_OPT_CREATE | DLADM_OPT_TEMP); 30990ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 310033343a97Smeem die_dlerr(status, "could not create secure object '%s'", 310133343a97Smeem obj_name); 31020ba2cbe9Sxc151355 } 31030ba2cbe9Sxc151355 if (temp) 31040ba2cbe9Sxc151355 return; 31050ba2cbe9Sxc151355 31060ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 31070ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31080ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 310933343a97Smeem warn_dlerr(status, "could not persistently create secure " 311033343a97Smeem "object '%s'", obj_name); 31110ba2cbe9Sxc151355 } 31120ba2cbe9Sxc151355 } 31130ba2cbe9Sxc151355 31140ba2cbe9Sxc151355 static void 31150ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 31160ba2cbe9Sxc151355 { 31170ba2cbe9Sxc151355 int i, option; 31180ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 31190ba2cbe9Sxc151355 split_t *sp = NULL; 31200ba2cbe9Sxc151355 boolean_t success; 31210ba2cbe9Sxc151355 dladm_status_t status, pstatus; 31220ba2cbe9Sxc151355 31230ba2cbe9Sxc151355 opterr = 0; 31240ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 312533343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 31260ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 31270ba2cbe9Sxc151355 switch (option) { 31280ba2cbe9Sxc151355 case 't': 31290ba2cbe9Sxc151355 temp = B_TRUE; 31300ba2cbe9Sxc151355 break; 31310ba2cbe9Sxc151355 case 'R': 31320ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 31330ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 313433343a97Smeem die_dlerr(status, "invalid directory " 313533343a97Smeem "specified"); 31360ba2cbe9Sxc151355 } 31370ba2cbe9Sxc151355 break; 31380ba2cbe9Sxc151355 default: 313933343a97Smeem die_opterr(optopt, option); 31400ba2cbe9Sxc151355 break; 31410ba2cbe9Sxc151355 } 31420ba2cbe9Sxc151355 } 31430ba2cbe9Sxc151355 31440ba2cbe9Sxc151355 if (optind == (argc - 1)) { 31450ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 31460ba2cbe9Sxc151355 if (sp == NULL) { 314733343a97Smeem die("invalid secure object name(s): '%s'", 314833343a97Smeem argv[optind]); 31490ba2cbe9Sxc151355 } 31500ba2cbe9Sxc151355 } else if (optind != argc) 31510ba2cbe9Sxc151355 usage(); 31520ba2cbe9Sxc151355 315333343a97Smeem if (sp == NULL || sp->s_nfields < 1) 315433343a97Smeem die("secure object name required"); 31550ba2cbe9Sxc151355 31560ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 31570ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, "wep", argv[optind], success, B_FALSE); 315833343a97Smeem if (!success) 315933343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 31600ba2cbe9Sxc151355 31610ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 31620ba2cbe9Sxc151355 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_TEMP); 31630ba2cbe9Sxc151355 if (!temp) { 31640ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 31650ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 31660ba2cbe9Sxc151355 } else { 31670ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 31680ba2cbe9Sxc151355 } 31690ba2cbe9Sxc151355 31700ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 317133343a97Smeem warn_dlerr(status, "could not delete secure object " 317233343a97Smeem "'%s'", sp->s_fields[i]); 31730ba2cbe9Sxc151355 } 31740ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 317533343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 317633343a97Smeem "secure object '%s'", sp->s_fields[i]); 31770ba2cbe9Sxc151355 } 31780ba2cbe9Sxc151355 } 31790ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 31800ba2cbe9Sxc151355 exit(1); 31810ba2cbe9Sxc151355 } 31820ba2cbe9Sxc151355 31830ba2cbe9Sxc151355 typedef struct show_secobj_state { 31840ba2cbe9Sxc151355 boolean_t ss_persist; 31850ba2cbe9Sxc151355 boolean_t ss_parseable; 31860ba2cbe9Sxc151355 boolean_t ss_debug; 31870ba2cbe9Sxc151355 boolean_t ss_header; 31880ba2cbe9Sxc151355 } show_secobj_state_t; 31890ba2cbe9Sxc151355 31900ba2cbe9Sxc151355 static void 31910ba2cbe9Sxc151355 print_secobj_head(show_secobj_state_t *statep) 31920ba2cbe9Sxc151355 { 31930ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); 31940ba2cbe9Sxc151355 if (statep->ss_debug) 31950ba2cbe9Sxc151355 (void) printf("%-30s", "VALUE"); 31960ba2cbe9Sxc151355 (void) putchar('\n'); 31970ba2cbe9Sxc151355 } 31980ba2cbe9Sxc151355 31990ba2cbe9Sxc151355 static boolean_t 32000ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 32010ba2cbe9Sxc151355 { 32020ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 32030ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 32040ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 32050ba2cbe9Sxc151355 uint_t flags = 0; 32060ba2cbe9Sxc151355 dladm_secobj_class_t class; 32070ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 32080ba2cbe9Sxc151355 dladm_status_t status; 32090ba2cbe9Sxc151355 32100ba2cbe9Sxc151355 if (statep->ss_persist) 32110ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 32120ba2cbe9Sxc151355 32130ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 321433343a97Smeem if (status != DLADM_STATUS_OK) 321533343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 32160ba2cbe9Sxc151355 32170ba2cbe9Sxc151355 if (statep->ss_header) { 32180ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 32190ba2cbe9Sxc151355 if (!statep->ss_parseable) 32200ba2cbe9Sxc151355 print_secobj_head(statep); 32210ba2cbe9Sxc151355 } 32220ba2cbe9Sxc151355 32230ba2cbe9Sxc151355 if (statep->ss_parseable) { 32240ba2cbe9Sxc151355 (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, 32250ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32260ba2cbe9Sxc151355 } else { 32270ba2cbe9Sxc151355 (void) printf("%-20s %-20s ", obj_name, 32280ba2cbe9Sxc151355 dladm_secobjclass2str(class, buf)); 32290ba2cbe9Sxc151355 } 32300ba2cbe9Sxc151355 32310ba2cbe9Sxc151355 if (statep->ss_debug) { 32320ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 32330ba2cbe9Sxc151355 uint_t len = sizeof (val); 32340ba2cbe9Sxc151355 32350ba2cbe9Sxc151355 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { 32360ba2cbe9Sxc151355 if (statep->ss_parseable) 32370ba2cbe9Sxc151355 (void) printf("VALUE=\"0x%s\"", val); 32380ba2cbe9Sxc151355 else 32390ba2cbe9Sxc151355 (void) printf("0x%-30s", val); 32400ba2cbe9Sxc151355 } 32410ba2cbe9Sxc151355 } 32420ba2cbe9Sxc151355 (void) putchar('\n'); 32430ba2cbe9Sxc151355 return (B_TRUE); 32440ba2cbe9Sxc151355 } 32450ba2cbe9Sxc151355 32460ba2cbe9Sxc151355 static void 32470ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 32480ba2cbe9Sxc151355 { 32490ba2cbe9Sxc151355 int option; 32500ba2cbe9Sxc151355 show_secobj_state_t state; 32510ba2cbe9Sxc151355 dladm_status_t status; 32520ba2cbe9Sxc151355 uint_t i; 32530ba2cbe9Sxc151355 split_t *sp; 32540ba2cbe9Sxc151355 uint_t flags; 32550ba2cbe9Sxc151355 32560ba2cbe9Sxc151355 opterr = 0; 32570ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 32580ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 32590ba2cbe9Sxc151355 state.ss_debug = B_FALSE; 32600ba2cbe9Sxc151355 state.ss_header = B_TRUE; 32610ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":pPd", 32620ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 32630ba2cbe9Sxc151355 switch (option) { 32640ba2cbe9Sxc151355 case 'p': 32650ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 32660ba2cbe9Sxc151355 break; 32670ba2cbe9Sxc151355 case 'P': 32680ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 32690ba2cbe9Sxc151355 break; 32700ba2cbe9Sxc151355 case 'd': 327133343a97Smeem if (getuid() != 0) 327233343a97Smeem die("insufficient privileges"); 32730ba2cbe9Sxc151355 state.ss_debug = B_TRUE; 32740ba2cbe9Sxc151355 break; 32750ba2cbe9Sxc151355 default: 327633343a97Smeem die_opterr(optopt, option); 32770ba2cbe9Sxc151355 break; 32780ba2cbe9Sxc151355 } 32790ba2cbe9Sxc151355 } 32800ba2cbe9Sxc151355 32810ba2cbe9Sxc151355 if (optind == (argc - 1)) { 32820ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 32830ba2cbe9Sxc151355 if (sp == NULL) { 328433343a97Smeem die("invalid secure object name(s): '%s'", 328533343a97Smeem argv[optind]); 32860ba2cbe9Sxc151355 } 32870ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 32880ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 32890ba2cbe9Sxc151355 break; 32900ba2cbe9Sxc151355 } 32910ba2cbe9Sxc151355 splitfree(sp); 32920ba2cbe9Sxc151355 return; 32930ba2cbe9Sxc151355 } else if (optind != argc) 32940ba2cbe9Sxc151355 usage(); 32950ba2cbe9Sxc151355 32960ba2cbe9Sxc151355 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 32970ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 329833343a97Smeem if (status != DLADM_STATUS_OK) 329933343a97Smeem die_dlerr(status, "show-secobj"); 33000ba2cbe9Sxc151355 } 33010ba2cbe9Sxc151355 33020ba2cbe9Sxc151355 /* ARGSUSED */ 33030ba2cbe9Sxc151355 static void 33040ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 33050ba2cbe9Sxc151355 { 33060ba2cbe9Sxc151355 dladm_status_t status; 33070ba2cbe9Sxc151355 33080ba2cbe9Sxc151355 status = dladm_init_linkprop(); 330933343a97Smeem if (status != DLADM_STATUS_OK) 331033343a97Smeem die_dlerr(status, "link property initialization failed"); 33110ba2cbe9Sxc151355 } 33120ba2cbe9Sxc151355 33130ba2cbe9Sxc151355 /* ARGSUSED */ 33140ba2cbe9Sxc151355 static void 33150ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 33160ba2cbe9Sxc151355 { 33170ba2cbe9Sxc151355 dladm_status_t status; 33180ba2cbe9Sxc151355 33190ba2cbe9Sxc151355 status = dladm_init_secobj(); 332033343a97Smeem if (status != DLADM_STATUS_OK) 332133343a97Smeem die_dlerr(status, "secure object initialization failed"); 332233343a97Smeem } 332333343a97Smeem 332433343a97Smeem static boolean_t 332533343a97Smeem str2int(const char *str, int *valp) 332633343a97Smeem { 332733343a97Smeem int val; 332833343a97Smeem char *endp = NULL; 332933343a97Smeem 333033343a97Smeem errno = 0; 333133343a97Smeem val = strtol(str, &endp, 10); 333233343a97Smeem if (errno != 0 || *endp != '\0') 333333343a97Smeem return (B_FALSE); 333433343a97Smeem 333533343a97Smeem *valp = val; 333633343a97Smeem return (B_TRUE); 333733343a97Smeem } 333833343a97Smeem 333933343a97Smeem /* PRINTFLIKE1 */ 334033343a97Smeem static void 334133343a97Smeem warn(const char *format, ...) 334233343a97Smeem { 334333343a97Smeem va_list alist; 334433343a97Smeem 334533343a97Smeem format = gettext(format); 334633343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 334733343a97Smeem 334833343a97Smeem va_start(alist, format); 334933343a97Smeem (void) vfprintf(stderr, format, alist); 335033343a97Smeem va_end(alist); 335133343a97Smeem 335233343a97Smeem (void) putchar('\n'); 335333343a97Smeem } 335433343a97Smeem 335533343a97Smeem /* PRINTFLIKE2 */ 335633343a97Smeem static void 335733343a97Smeem warn_wlerr(wladm_status_t err, const char *format, ...) 335833343a97Smeem { 335933343a97Smeem va_list alist; 336033343a97Smeem char errmsg[WLADM_STRSIZE]; 336133343a97Smeem 336233343a97Smeem format = gettext(format); 336333343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 336433343a97Smeem 336533343a97Smeem va_start(alist, format); 336633343a97Smeem (void) vfprintf(stderr, format, alist); 336733343a97Smeem va_end(alist); 336833343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 336933343a97Smeem } 337033343a97Smeem 337133343a97Smeem /* PRINTFLIKE2 */ 337233343a97Smeem static void 337333343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 337433343a97Smeem { 337533343a97Smeem va_list alist; 337633343a97Smeem char errmsg[DLADM_STRSIZE]; 337733343a97Smeem 337833343a97Smeem format = gettext(format); 337933343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 338033343a97Smeem 338133343a97Smeem va_start(alist, format); 338233343a97Smeem (void) vfprintf(stderr, format, alist); 338333343a97Smeem va_end(alist); 338433343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 338533343a97Smeem } 338633343a97Smeem 338733343a97Smeem /* PRINTFLIKE2 */ 338833343a97Smeem static void 338933343a97Smeem die_laerr(laadm_diag_t diag, const char *format, ...) 339033343a97Smeem { 339133343a97Smeem va_list alist; 339233343a97Smeem char *errstr = strerror(errno); 339333343a97Smeem 339433343a97Smeem format = gettext(format); 339533343a97Smeem (void) fprintf(stderr, "%s: ", progname); 339633343a97Smeem 339733343a97Smeem va_start(alist, format); 339833343a97Smeem (void) vfprintf(stderr, format, alist); 339933343a97Smeem va_end(alist); 340033343a97Smeem 340133343a97Smeem if (diag == 0) 340233343a97Smeem (void) fprintf(stderr, ": %s\n", errstr); 340333343a97Smeem else 340433343a97Smeem (void) fprintf(stderr, ": %s (%s)\n", errstr, laadm_diag(diag)); 340533343a97Smeem 340633343a97Smeem exit(EXIT_FAILURE); 340733343a97Smeem } 340833343a97Smeem 340933343a97Smeem /* PRINTFLIKE2 */ 341033343a97Smeem static void 341133343a97Smeem die_wlerr(wladm_status_t err, const char *format, ...) 341233343a97Smeem { 341333343a97Smeem va_list alist; 341433343a97Smeem char errmsg[WLADM_STRSIZE]; 341533343a97Smeem 341633343a97Smeem format = gettext(format); 341733343a97Smeem (void) fprintf(stderr, "%s: ", progname); 341833343a97Smeem 341933343a97Smeem va_start(alist, format); 342033343a97Smeem (void) vfprintf(stderr, format, alist); 342133343a97Smeem va_end(alist); 342233343a97Smeem (void) fprintf(stderr, ": %s\n", wladm_status2str(err, errmsg)); 342333343a97Smeem 342433343a97Smeem exit(EXIT_FAILURE); 342533343a97Smeem } 342633343a97Smeem 342733343a97Smeem /* PRINTFLIKE2 */ 342833343a97Smeem static void 342933343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 343033343a97Smeem { 343133343a97Smeem va_list alist; 343233343a97Smeem char errmsg[DLADM_STRSIZE]; 343333343a97Smeem 343433343a97Smeem format = gettext(format); 343533343a97Smeem (void) fprintf(stderr, "%s: ", progname); 343633343a97Smeem 343733343a97Smeem va_start(alist, format); 343833343a97Smeem (void) vfprintf(stderr, format, alist); 343933343a97Smeem va_end(alist); 344033343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 344133343a97Smeem 344233343a97Smeem exit(EXIT_FAILURE); 344333343a97Smeem } 344433343a97Smeem 344533343a97Smeem /* PRINTFLIKE1 */ 344633343a97Smeem static void 344733343a97Smeem die(const char *format, ...) 344833343a97Smeem { 344933343a97Smeem va_list alist; 345033343a97Smeem 345133343a97Smeem format = gettext(format); 345233343a97Smeem (void) fprintf(stderr, "%s: ", progname); 345333343a97Smeem 345433343a97Smeem va_start(alist, format); 345533343a97Smeem (void) vfprintf(stderr, format, alist); 345633343a97Smeem va_end(alist); 345733343a97Smeem 345833343a97Smeem (void) putchar('\n'); 345933343a97Smeem exit(EXIT_FAILURE); 346033343a97Smeem } 346133343a97Smeem 346233343a97Smeem static void 346333343a97Smeem die_optdup(int opt) 346433343a97Smeem { 346533343a97Smeem die("the option -%c cannot be specified more than once", opt); 346633343a97Smeem } 346733343a97Smeem 346833343a97Smeem static void 346933343a97Smeem die_opterr(int opt, int opterr) 347033343a97Smeem { 347133343a97Smeem switch (opterr) { 347233343a97Smeem case ':': 347333343a97Smeem die("option '-%c' requires a value", opt); 347433343a97Smeem break; 347533343a97Smeem case '?': 347633343a97Smeem default: 347733343a97Smeem die("unrecognized option '-%c'", opt); 347833343a97Smeem break; 34790ba2cbe9Sxc151355 } 34800ba2cbe9Sxc151355 } 3481